wa-lang.org/wazero@v1.0.2/internal/wasm/binary/section.go (about) 1 package binary 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 8 "wa-lang.org/wazero/api" 9 "wa-lang.org/wazero/internal/leb128" 10 "wa-lang.org/wazero/internal/wasm" 11 ) 12 13 func decodeTypeSection(enabledFeatures api.CoreFeatures, r *bytes.Reader) ([]*wasm.FunctionType, error) { 14 vs, _, err := leb128.DecodeUint32(r) 15 if err != nil { 16 return nil, fmt.Errorf("get size of vector: %w", err) 17 } 18 19 result := make([]*wasm.FunctionType, vs) 20 for i := uint32(0); i < vs; i++ { 21 if result[i], err = decodeFunctionType(enabledFeatures, r); err != nil { 22 return nil, fmt.Errorf("read %d-th type: %v", i, err) 23 } 24 } 25 return result, nil 26 } 27 28 func decodeImportSection( 29 r *bytes.Reader, 30 memorySizer func(minPages uint32, maxPages *uint32) (min, capacity, max uint32), 31 memoryLimitPages uint32, 32 enabledFeatures api.CoreFeatures, 33 ) ([]*wasm.Import, error) { 34 vs, _, err := leb128.DecodeUint32(r) 35 if err != nil { 36 return nil, fmt.Errorf("get size of vector: %w", err) 37 } 38 39 result := make([]*wasm.Import, vs) 40 for i := uint32(0); i < vs; i++ { 41 if result[i], err = decodeImport(r, i, memorySizer, memoryLimitPages, enabledFeatures); err != nil { 42 return nil, err 43 } 44 } 45 return result, nil 46 } 47 48 func decodeFunctionSection(r *bytes.Reader) ([]uint32, error) { 49 vs, _, err := leb128.DecodeUint32(r) 50 if err != nil { 51 return nil, fmt.Errorf("get size of vector: %w", err) 52 } 53 54 result := make([]uint32, vs) 55 for i := uint32(0); i < vs; i++ { 56 if result[i], _, err = leb128.DecodeUint32(r); err != nil { 57 return nil, fmt.Errorf("get type index: %w", err) 58 } 59 } 60 return result, err 61 } 62 63 func decodeTableSection(r *bytes.Reader, enabledFeatures api.CoreFeatures) ([]*wasm.Table, error) { 64 vs, _, err := leb128.DecodeUint32(r) 65 if err != nil { 66 return nil, fmt.Errorf("error reading size") 67 } 68 if vs > 1 { 69 if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil { 70 return nil, fmt.Errorf("at most one table allowed in module as %w", err) 71 } 72 } 73 74 ret := make([]*wasm.Table, vs) 75 for i := range ret { 76 table, err := decodeTable(r, enabledFeatures) 77 if err != nil { 78 return nil, err 79 } 80 ret[i] = table 81 } 82 return ret, nil 83 } 84 85 func decodeMemorySection( 86 r *bytes.Reader, 87 memorySizer func(minPages uint32, maxPages *uint32) (min, capacity, max uint32), 88 memoryLimitPages uint32, 89 ) (*wasm.Memory, error) { 90 vs, _, err := leb128.DecodeUint32(r) 91 if err != nil { 92 return nil, fmt.Errorf("error reading size") 93 } 94 if vs > 1 { 95 return nil, fmt.Errorf("at most one memory allowed in module, but read %d", vs) 96 } else if vs == 0 { 97 // memory count can be zero. 98 return nil, nil 99 } 100 101 return decodeMemory(r, memorySizer, memoryLimitPages) 102 } 103 104 func decodeGlobalSection(r *bytes.Reader, enabledFeatures api.CoreFeatures) ([]*wasm.Global, error) { 105 vs, _, err := leb128.DecodeUint32(r) 106 if err != nil { 107 return nil, fmt.Errorf("get size of vector: %w", err) 108 } 109 110 result := make([]*wasm.Global, vs) 111 for i := uint32(0); i < vs; i++ { 112 if result[i], err = decodeGlobal(r, enabledFeatures); err != nil { 113 return nil, fmt.Errorf("global[%d]: %w", i, err) 114 } 115 } 116 return result, nil 117 } 118 119 func decodeExportSection(r *bytes.Reader) ([]*wasm.Export, error) { 120 vs, _, sizeErr := leb128.DecodeUint32(r) 121 if sizeErr != nil { 122 return nil, fmt.Errorf("get size of vector: %v", sizeErr) 123 } 124 125 usedName := make(map[string]struct{}, vs) 126 exportSection := make([]*wasm.Export, 0, vs) 127 for i := wasm.Index(0); i < vs; i++ { 128 export, err := decodeExport(r) 129 if err != nil { 130 return nil, fmt.Errorf("read export: %w", err) 131 } 132 if _, ok := usedName[export.Name]; ok { 133 return nil, fmt.Errorf("export[%d] duplicates name %q", i, export.Name) 134 } else { 135 usedName[export.Name] = struct{}{} 136 } 137 exportSection = append(exportSection, export) 138 } 139 return exportSection, nil 140 } 141 142 func decodeStartSection(r *bytes.Reader) (*wasm.Index, error) { 143 vs, _, err := leb128.DecodeUint32(r) 144 if err != nil { 145 return nil, fmt.Errorf("get function index: %w", err) 146 } 147 return &vs, nil 148 } 149 150 func decodeElementSection(r *bytes.Reader, enabledFeatures api.CoreFeatures) ([]*wasm.ElementSegment, error) { 151 vs, _, err := leb128.DecodeUint32(r) 152 if err != nil { 153 return nil, fmt.Errorf("get size of vector: %w", err) 154 } 155 156 result := make([]*wasm.ElementSegment, vs) 157 for i := uint32(0); i < vs; i++ { 158 if result[i], err = decodeElementSegment(r, enabledFeatures); err != nil { 159 return nil, fmt.Errorf("read element: %w", err) 160 } 161 } 162 return result, nil 163 } 164 165 func decodeCodeSection(r *bytes.Reader) ([]*wasm.Code, error) { 166 vs, _, err := leb128.DecodeUint32(r) 167 if err != nil { 168 return nil, fmt.Errorf("get size of vector: %w", err) 169 } 170 171 result := make([]*wasm.Code, vs) 172 for i := uint32(0); i < vs; i++ { 173 if result[i], err = decodeCode(r); err != nil { 174 return nil, fmt.Errorf("read %d-th code segment: %v", i, err) 175 } 176 } 177 return result, nil 178 } 179 180 func decodeDataSection(r *bytes.Reader, enabledFeatures api.CoreFeatures) ([]*wasm.DataSegment, error) { 181 vs, _, err := leb128.DecodeUint32(r) 182 if err != nil { 183 return nil, fmt.Errorf("get size of vector: %w", err) 184 } 185 186 result := make([]*wasm.DataSegment, vs) 187 for i := uint32(0); i < vs; i++ { 188 if result[i], err = decodeDataSegment(r, enabledFeatures); err != nil { 189 return nil, fmt.Errorf("read data segment: %w", err) 190 } 191 } 192 return result, nil 193 } 194 195 func decodeDataCountSection(r *bytes.Reader) (count *uint32, err error) { 196 v, _, err := leb128.DecodeUint32(r) 197 if err != nil && err != io.EOF { 198 // data count is optional, so EOF is fine. 199 return nil, err 200 } 201 return &v, nil 202 } 203 204 // encodeSection encodes the sectionID, the size of its contents in bytes, followed by the contents. 205 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0 206 func encodeSection(sectionID wasm.SectionID, contents []byte) []byte { 207 return append([]byte{sectionID}, encodeSizePrefixed(contents)...) 208 } 209 210 // encodeTypeSection encodes a wasm.SectionIDType for the given imports in WebAssembly 1.0 (20191205) Binary 211 // Format. 212 // 213 // See encodeFunctionType 214 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#type-section%E2%91%A0 215 func encodeTypeSection(types []*wasm.FunctionType) []byte { 216 contents := leb128.EncodeUint32(uint32(len(types))) 217 for _, t := range types { 218 contents = append(contents, encodeFunctionType(t)...) 219 } 220 return encodeSection(wasm.SectionIDType, contents) 221 } 222 223 // encodeImportSection encodes a wasm.SectionIDImport for the given imports in WebAssembly 1.0 (20191205) Binary 224 // Format. 225 // 226 // See encodeImport 227 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#import-section%E2%91%A0 228 func encodeImportSection(imports []*wasm.Import) []byte { 229 contents := leb128.EncodeUint32(uint32(len(imports))) 230 for _, i := range imports { 231 contents = append(contents, encodeImport(i)...) 232 } 233 return encodeSection(wasm.SectionIDImport, contents) 234 } 235 236 // encodeFunctionSection encodes a wasm.SectionIDFunction for the type indices associated with module-defined 237 // functions in WebAssembly 1.0 (20191205) Binary Format. 238 // 239 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#function-section%E2%91%A0 240 func encodeFunctionSection(typeIndices []wasm.Index) []byte { 241 contents := leb128.EncodeUint32(uint32(len(typeIndices))) 242 for _, index := range typeIndices { 243 contents = append(contents, leb128.EncodeUint32(index)...) 244 } 245 return encodeSection(wasm.SectionIDFunction, contents) 246 } 247 248 // encodeCodeSection encodes a wasm.SectionIDCode for the module-defined function in WebAssembly 1.0 (20191205) 249 // Binary Format. 250 // 251 // See encodeCode 252 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#code-section%E2%91%A0 253 func encodeCodeSection(code []*wasm.Code) []byte { 254 contents := leb128.EncodeUint32(uint32(len(code))) 255 for _, i := range code { 256 contents = append(contents, encodeCode(i)...) 257 } 258 return encodeSection(wasm.SectionIDCode, contents) 259 } 260 261 // encodeTableSection encodes a wasm.SectionIDTable for the module-defined function in WebAssembly 1.0 262 // (20191205) Binary Format. 263 // 264 // See encodeTable 265 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#table-section%E2%91%A0 266 func encodeTableSection(tables []*wasm.Table) []byte { 267 var contents []byte = leb128.EncodeUint32(uint32(len(tables))) 268 for _, table := range tables { 269 contents = append(contents, encodeTable(table)...) 270 } 271 return encodeSection(wasm.SectionIDTable, contents) 272 } 273 274 // encodeMemorySection encodes a wasm.SectionIDMemory for the module-defined function in WebAssembly 1.0 275 // (20191205) Binary Format. 276 // 277 // See encodeMemory 278 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#memory-section%E2%91%A0 279 func encodeMemorySection(memory *wasm.Memory) []byte { 280 contents := append([]byte{1}, encodeMemory(memory)...) 281 return encodeSection(wasm.SectionIDMemory, contents) 282 } 283 284 // encodeGlobalSection encodes a wasm.SectionIDGlobal for the given globals in WebAssembly 1.0 (20191205) Binary 285 // Format. 286 // 287 // See encodeGlobal 288 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#global-section%E2%91%A0 289 func encodeGlobalSection(globals []*wasm.Global) []byte { 290 contents := leb128.EncodeUint32(uint32(len(globals))) 291 for _, g := range globals { 292 contents = append(contents, encodeGlobal(g)...) 293 } 294 return encodeSection(wasm.SectionIDGlobal, contents) 295 } 296 297 // encodeExportSection encodes a wasm.SectionIDExport for the given exports in WebAssembly 1.0 (20191205) Binary 298 // Format. 299 // 300 // See encodeExport 301 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#export-section%E2%91%A0 302 func encodeExportSection(exports []*wasm.Export) []byte { 303 contents := leb128.EncodeUint32(uint32(len(exports))) 304 for _, e := range exports { 305 contents = append(contents, encodeExport(e)...) 306 } 307 return encodeSection(wasm.SectionIDExport, contents) 308 } 309 310 // encodeStartSection encodes a wasm.SectionIDStart for the given function index in WebAssembly 1.0 (20191205) 311 // Binary Format. 312 // 313 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#start-section%E2%91%A0 314 func encodeStartSection(funcidx wasm.Index) []byte { 315 return encodeSection(wasm.SectionIDStart, leb128.EncodeUint32(funcidx)) 316 } 317 318 // encodeEelementSection encodes a wasm.SectionIDElement for the elements in WebAssembly 1.0 (20191205) 319 // Binary Format. 320 // 321 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#element-section%E2%91%A0 322 func encodeElementSection(elements []*wasm.ElementSegment) []byte { 323 contents := leb128.EncodeUint32(uint32(len(elements))) 324 for _, e := range elements { 325 contents = append(contents, encodeElement(e)...) 326 } 327 return encodeSection(wasm.SectionIDElement, contents) 328 } 329 330 // encodeDataSection encodes a wasm.SectionIDData for the data in WebAssembly 1.0 (20191205) 331 // Binary Format. 332 // 333 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#data-section%E2%91%A0 334 func encodeDataSection(datum []*wasm.DataSegment) []byte { 335 contents := leb128.EncodeUint32(uint32(len(datum))) 336 for _, d := range datum { 337 contents = append(contents, encodeDataSegment(d)...) 338 } 339 return encodeSection(wasm.SectionIDData, contents) 340 }