wa-lang.org/wazero@v1.0.2/internal/wasm/module.go (about) 1 package wasm 2 3 import ( 4 "bytes" 5 "crypto/sha256" 6 "errors" 7 "fmt" 8 "io" 9 "sort" 10 "strings" 11 12 "wa-lang.org/wazero/api" 13 "wa-lang.org/wazero/internal/ieee754" 14 "wa-lang.org/wazero/internal/leb128" 15 ) 16 17 // DecodeModule parses the WebAssembly Binary Format (%.wasm) into a Module. This function returns when the input is 18 // exhausted or an error occurs. The result can be initialized for use via Store.Instantiate. 19 // 20 // Here's a description of the return values: 21 // * result is the module parsed or nil on error 22 // * err is a FormatError invoking the parser, dangling block comments or unexpected characters. 23 // See binary.DecodeModule and text.DecodeModule 24 type DecodeModule func( 25 wasm []byte, 26 enabledFeatures api.CoreFeatures, 27 memorySizer func(minPages uint32, maxPages *uint32) (min, capacity, max uint32), 28 ) (result *Module, err error) 29 30 // EncodeModule encodes the given module into a byte slice depending on the format of the implementation. 31 // See binary.EncodeModule 32 type EncodeModule func(m *Module) (bytes []byte) 33 34 // Module is a WebAssembly binary representation. 35 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#modules%E2%91%A8 36 // 37 // Differences from the specification: 38 // * NameSection is the only key ("name") decoded from the SectionIDCustom. 39 // * ExportSection is represented as a map for lookup convenience. 40 // * Code.GoFunc is contains any go `func`. It may be present when Code.Body is not. 41 type Module struct { 42 // TypeSection contains the unique FunctionType of functions imported or defined in this module. 43 // 44 // Note: Currently, there is no type ambiguity in the index as WebAssembly 1.0 only defines function type. 45 // In the future, other types may be introduced to support CoreFeatures such as module linking. 46 // 47 // Note: In the Binary Format, this is SectionIDType. 48 // 49 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#types%E2%91%A0%E2%91%A0 50 TypeSection []*FunctionType 51 52 // ImportSection contains imported functions, tables, memories or globals required for instantiation 53 // (Store.Instantiate). 54 // 55 // Note: there are no unique constraints relating to the two-level namespace of Import.Module and Import.Name. 56 // 57 // Note: In the Binary Format, this is SectionIDImport. 58 // 59 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#import-section%E2%91%A0 60 ImportSection []*Import 61 62 // FunctionSection contains the index in TypeSection of each function defined in this module. 63 // 64 // Note: The function Index namespace begins with imported functions and ends with those defined in this module. 65 // For example, if there are two imported functions and one defined in this module, the function Index 3 is defined 66 // in this module at FunctionSection[0]. 67 // 68 // Note: FunctionSection is index correlated with the CodeSection. If given the same position, e.g. 2, a function 69 // type is at TypeSection[FunctionSection[2]], while its locals and body are at CodeSection[2]. 70 // 71 // Note: In the Binary Format, this is SectionIDFunction. 72 // 73 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#function-section%E2%91%A0 74 FunctionSection []Index 75 76 // TableSection contains each table defined in this module. 77 // 78 // Note: The table Index namespace begins with imported tables and ends with those defined in this module. 79 // For example, if there are two imported tables and one defined in this module, the table Index 3 is defined in 80 // this module at TableSection[0]. 81 // 82 // Note: Version 1.0 (20191205) of the WebAssembly spec allows at most one table definition per module, so the 83 // length of the TableSection can be zero or one, and can only be one if there is no imported table. 84 // 85 // Note: In the Binary Format, this is SectionIDTable. 86 // 87 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#table-section%E2%91%A0 88 TableSection []*Table 89 90 // MemorySection contains each memory defined in this module. 91 // 92 // Note: The memory Index namespace begins with imported memories and ends with those defined in this module. 93 // For example, if there are two imported memories and one defined in this module, the memory Index 3 is defined in 94 // this module at TableSection[0]. 95 // 96 // Note: Version 1.0 (20191205) of the WebAssembly spec allows at most one memory definition per module, so the 97 // length of the MemorySection can be zero or one, and can only be one if there is no imported memory. 98 // 99 // Note: In the Binary Format, this is SectionIDMemory. 100 // 101 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#memory-section%E2%91%A0 102 MemorySection *Memory 103 104 // GlobalSection contains each global defined in this module. 105 // 106 // Global indexes are offset by any imported globals because the global index space begins with imports, followed by 107 // ones defined in this module. For example, if there are two imported globals and three defined in this module, the 108 // global at index 3 is defined in this module at GlobalSection[0]. 109 // 110 // Note: In the Binary Format, this is SectionIDGlobal. 111 // 112 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#global-section%E2%91%A0 113 GlobalSection []*Global 114 115 // ExportSection contains each export defined in this module. 116 // 117 // Note: In the Binary Format, this is SectionIDExport. 118 // 119 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#exports%E2%91%A0 120 ExportSection []*Export 121 122 // StartSection is the index of a function to call before returning from Store.Instantiate. 123 // 124 // Note: The index here is not the position in the FunctionSection, rather in the function index namespace, which 125 // begins with imported functions. 126 // 127 // Note: In the Binary Format, this is SectionIDStart. 128 // 129 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#start-section%E2%91%A0 130 StartSection *Index 131 132 // Note: In the Binary Format, this is SectionIDElement. 133 ElementSection []*ElementSegment 134 135 // CodeSection is index-correlated with FunctionSection and contains each 136 // function's locals and body. 137 // 138 // When present, the HostFunctionSection of the same index must be nil. 139 // 140 // Note: In the Binary Format, this is SectionIDCode. 141 // 142 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#code-section%E2%91%A0 143 CodeSection []*Code 144 145 // Note: In the Binary Format, this is SectionIDData. 146 DataSection []*DataSegment 147 148 // NameSection is set when the SectionIDCustom "name" was successfully decoded from the binary format. 149 // 150 // Note: This is the only SectionIDCustom defined in the WebAssembly 1.0 (20191205) Binary Format. 151 // Others are skipped as they are not used in wazero. 152 // 153 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#name-section%E2%91%A0 154 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#custom-section%E2%91%A0 155 NameSection *NameSection 156 157 // validatedActiveElementSegments are built on Validate when 158 // SectionIDElement is non-empty and all inputs are valid. 159 // 160 // Note: elementSegments retain Module.ElementSection order. Since an 161 // ElementSegment can overlap with another, order preservation ensures a 162 // consistent initialization result. 163 // 164 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#table-instances%E2%91%A0 165 validatedActiveElementSegments []*validatedActiveElementSegment 166 167 // DataCountSection is the optional section and holds the number of data segments in the data section. 168 // 169 // Note: This may exist in WebAssembly 2.0 or WebAssembly 1.0 with CoreFeatureBulkMemoryOperations. 170 // See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#data-count-section 171 // See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/appendix/changes.html#bulk-memory-and-table-instructions 172 DataCountSection *uint32 173 174 // ID is the sha256 value of the source wasm and is used for caching. 175 ID ModuleID 176 177 // FunctionDefinitionSection is a wazero-specific section built on Validate. 178 FunctionDefinitionSection []*FunctionDefinition 179 180 // MemoryDefinitionSection is a wazero-specific section built on Validate. 181 MemoryDefinitionSection []*MemoryDefinition 182 } 183 184 // ModuleID represents sha256 hash value uniquely assigned to Module. 185 type ModuleID = [sha256.Size]byte 186 187 // The wazero specific limitation described at RATIONALE.md. 188 // TL;DR; We multiply by 8 (to get offsets in bytes) and the multiplication result must be less than 32bit max 189 const ( 190 MaximumGlobals = uint32(1 << 27) 191 MaximumFunctionIndex = uint32(1 << 27) 192 MaximumTableIndex = uint32(1 << 27) 193 ) 194 195 // AssignModuleID calculates a sha256 checksum on `wasm` and set Module.ID to the result. 196 func (m *Module) AssignModuleID(wasm []byte) { 197 m.ID = sha256.Sum256(wasm) 198 } 199 200 // TypeOfFunction returns the wasm.SectionIDType index for the given function namespace index or nil. 201 // Note: The function index namespace is preceded by imported functions. 202 // TODO: Returning nil should be impossible when decode results are validated. Validate decode before back-filling tests. 203 func (m *Module) TypeOfFunction(funcIdx Index) *FunctionType { 204 typeSectionLength := uint32(len(m.TypeSection)) 205 if typeSectionLength == 0 { 206 return nil 207 } 208 funcImportCount := Index(0) 209 for _, im := range m.ImportSection { 210 if im.Type == ExternTypeFunc { 211 if funcIdx == funcImportCount { 212 if im.DescFunc >= typeSectionLength { 213 return nil 214 } 215 return m.TypeSection[im.DescFunc] 216 } 217 funcImportCount++ 218 } 219 } 220 funcSectionIdx := funcIdx - funcImportCount 221 if funcSectionIdx >= uint32(len(m.FunctionSection)) { 222 return nil 223 } 224 typeIdx := m.FunctionSection[funcSectionIdx] 225 if typeIdx >= typeSectionLength { 226 return nil 227 } 228 return m.TypeSection[typeIdx] 229 } 230 231 func (m *Module) Validate(enabledFeatures api.CoreFeatures) error { 232 for _, tp := range m.TypeSection { 233 tp.CacheNumInUint64() 234 } 235 236 if err := m.validateStartSection(); err != nil { 237 return err 238 } 239 240 functions, globals, memory, tables, err := m.AllDeclarations() 241 if err != nil { 242 return err 243 } 244 245 if err = m.validateImports(enabledFeatures); err != nil { 246 return err 247 } 248 249 if err = m.validateGlobals(globals, uint32(len(functions)), MaximumGlobals); err != nil { 250 return err 251 } 252 253 if err = m.validateMemory(memory, globals, enabledFeatures); err != nil { 254 return err 255 } 256 257 if err = m.validateExports(enabledFeatures, functions, globals, memory, tables); err != nil { 258 return err 259 } 260 261 if m.CodeSection != nil { 262 if err = m.validateFunctions(enabledFeatures, functions, globals, memory, tables, MaximumFunctionIndex); err != nil { 263 return err 264 } 265 } // No need to validate host functions as NewHostModule validates 266 267 if _, err = m.validateTable(enabledFeatures, tables, MaximumTableIndex); err != nil { 268 return err 269 } 270 271 if err = m.validateDataCountSection(); err != nil { 272 return err 273 } 274 return nil 275 } 276 277 func (m *Module) validateStartSection() error { 278 // Check the start function is valid. 279 // TODO: this should be verified during decode so that errors have the correct source positions 280 if m.StartSection != nil { 281 startIndex := *m.StartSection 282 ft := m.TypeOfFunction(startIndex) 283 if ft == nil { // TODO: move this check to decoder so that a module can never be decoded invalidly 284 return fmt.Errorf("invalid start function: func[%d] has an invalid type", startIndex) 285 } 286 if len(ft.Params) > 0 || len(ft.Results) > 0 { 287 return fmt.Errorf("invalid start function: func[%d] must have an empty (nullary) signature: %s", startIndex, ft) 288 } 289 } 290 return nil 291 } 292 293 func (m *Module) validateGlobals(globals []*GlobalType, numFuncts, maxGlobals uint32) error { 294 if uint32(len(globals)) > maxGlobals { 295 return fmt.Errorf("too many globals in a module") 296 } 297 298 // Global initialization constant expression can only reference the imported globals. 299 // See the note on https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#constant-expressions%E2%91%A0 300 importedGlobals := globals[:m.ImportGlobalCount()] 301 for _, g := range m.GlobalSection { 302 if err := validateConstExpression(importedGlobals, numFuncts, g.Init, g.Type.ValType); err != nil { 303 return err 304 } 305 } 306 return nil 307 } 308 309 func (m *Module) validateFunctions(enabledFeatures api.CoreFeatures, functions []Index, globals []*GlobalType, memory *Memory, tables []*Table, maximumFunctionIndex uint32) error { 310 if uint32(len(functions)) > maximumFunctionIndex { 311 return fmt.Errorf("too many functions in a store") 312 } 313 314 functionCount := m.SectionElementCount(SectionIDFunction) 315 codeCount := m.SectionElementCount(SectionIDCode) 316 if functionCount == 0 && codeCount == 0 { 317 return nil 318 } 319 320 typeCount := m.SectionElementCount(SectionIDType) 321 if codeCount != functionCount { 322 return fmt.Errorf("code count (%d) != function count (%d)", codeCount, functionCount) 323 } 324 325 declaredFuncIndexes, err := m.declaredFunctionIndexes() 326 if err != nil { 327 return err 328 } 329 330 for idx, typeIndex := range m.FunctionSection { 331 if typeIndex >= typeCount { 332 return fmt.Errorf("invalid %s: type section index %d out of range", m.funcDesc(SectionIDFunction, Index(idx)), typeIndex) 333 } 334 if m.CodeSection[idx].GoFunc != nil { 335 continue 336 } 337 if err = m.validateFunction(enabledFeatures, Index(idx), functions, globals, memory, tables, declaredFuncIndexes); err != nil { 338 return fmt.Errorf("invalid %s: %w", m.funcDesc(SectionIDFunction, Index(idx)), err) 339 } 340 } 341 return nil 342 } 343 344 // declaredFunctionIndexes returns a set of function indexes that can be used as an immediate for OpcodeRefFunc instruction. 345 // 346 // The criteria for which function indexes can be available for that instruction is vague in the spec: 347 // 348 // - "References: the list of function indices that occur in the module outside functions and can hence be used to form references inside them." 349 // - https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/valid/conventions.html#contexts 350 // - "Ref is the set funcidx(module with functions=ε, start=ε) , i.e., the set of function indices occurring in the module, except in its functions or start function." 351 // - https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/valid/modules.html#valid-module 352 // 353 // To clarify, we reverse-engineer logic required to pass the WebAssembly Core specification 2.0 test suite: 354 // https://github.com/WebAssembly/spec/blob/d39195773112a22b245ffbe864bab6d1182ccb06/test/core/ref_func.wast#L78-L115 355 // 356 // To summarize, the function indexes OpcodeRefFunc can refer include: 357 // - existing in an element section regardless of its mode (active, passive, declarative). 358 // - defined as globals whose value type is ValueRefFunc. 359 // - used as an exported function. 360 // 361 // See https://github.com/WebAssembly/reference-types/issues/31 362 // See https://github.com/WebAssembly/reference-types/issues/76 363 func (m *Module) declaredFunctionIndexes() (ret map[Index]struct{}, err error) { 364 ret = map[uint32]struct{}{} 365 366 for _, exp := range m.ExportSection { 367 if exp.Type == ExternTypeFunc { 368 ret[exp.Index] = struct{}{} 369 } 370 } 371 372 for i, g := range m.GlobalSection { 373 if g.Init.Opcode == OpcodeRefFunc { 374 var index uint32 375 index, _, err = leb128.LoadUint32(g.Init.Data) 376 if err != nil { 377 err = fmt.Errorf("%s[%d] failed to initialize: %w", SectionIDName(SectionIDGlobal), i, err) 378 return 379 } 380 ret[index] = struct{}{} 381 } 382 } 383 384 for _, elem := range m.ElementSection { 385 for _, index := range elem.Init { 386 if index != nil { 387 ret[*index] = struct{}{} 388 } 389 } 390 } 391 return 392 } 393 394 func (m *Module) funcDesc(sectionID SectionID, sectionIndex Index) string { 395 // Try to improve the error message by collecting any exports: 396 var exportNames []string 397 funcIdx := sectionIndex + m.importCount(ExternTypeFunc) 398 for _, e := range m.ExportSection { 399 if e.Index == funcIdx && e.Type == ExternTypeFunc { 400 exportNames = append(exportNames, fmt.Sprintf("%q", e.Name)) 401 } 402 } 403 sectionIDName := SectionIDName(sectionID) 404 if exportNames == nil { 405 return fmt.Sprintf("%s[%d]", sectionIDName, sectionIndex) 406 } 407 sort.Strings(exportNames) // go map keys do not iterate consistently 408 return fmt.Sprintf("%s[%d] export[%s]", sectionIDName, sectionIndex, strings.Join(exportNames, ",")) 409 } 410 411 func (m *Module) validateMemory(memory *Memory, globals []*GlobalType, _ api.CoreFeatures) error { 412 var activeElementCount int 413 for _, sec := range m.DataSection { 414 if !sec.IsPassive() { 415 activeElementCount++ 416 } 417 } 418 if activeElementCount > 0 && memory == nil { 419 return fmt.Errorf("unknown memory") 420 } 421 422 // Constant expression can only reference imported globals. 423 // https://github.com/WebAssembly/spec/blob/5900d839f38641989a9d8df2df4aee0513365d39/test/core/data.wast#L84-L91 424 importedGlobals := globals[:m.ImportGlobalCount()] 425 for _, d := range m.DataSection { 426 if !d.IsPassive() { 427 if err := validateConstExpression(importedGlobals, 0, d.OffsetExpression, ValueTypeI32); err != nil { 428 return fmt.Errorf("calculate offset: %w", err) 429 } 430 } 431 } 432 return nil 433 } 434 435 func (m *Module) validateImports(enabledFeatures api.CoreFeatures) error { 436 for _, i := range m.ImportSection { 437 switch i.Type { 438 case ExternTypeGlobal: 439 if !i.DescGlobal.Mutable { 440 continue 441 } 442 if err := enabledFeatures.RequireEnabled(api.CoreFeatureMutableGlobal); err != nil { 443 return fmt.Errorf("invalid import[%q.%q] global: %w", i.Module, i.Name, err) 444 } 445 } 446 } 447 return nil 448 } 449 450 func (m *Module) validateExports(enabledFeatures api.CoreFeatures, functions []Index, globals []*GlobalType, memory *Memory, tables []*Table) error { 451 for _, exp := range m.ExportSection { 452 index := exp.Index 453 switch exp.Type { 454 case ExternTypeFunc: 455 if index >= uint32(len(functions)) { 456 return fmt.Errorf("unknown function for export[%q]", exp.Name) 457 } 458 case ExternTypeGlobal: 459 if index >= uint32(len(globals)) { 460 return fmt.Errorf("unknown global for export[%q]", exp.Name) 461 } 462 if !globals[index].Mutable { 463 continue 464 } 465 if err := enabledFeatures.RequireEnabled(api.CoreFeatureMutableGlobal); err != nil { 466 return fmt.Errorf("invalid export[%q] global[%d]: %w", exp.Name, index, err) 467 } 468 case ExternTypeMemory: 469 if index > 0 || memory == nil { 470 return fmt.Errorf("memory for export[%q] out of range", exp.Name) 471 } 472 case ExternTypeTable: 473 if index >= uint32(len(tables)) { 474 return fmt.Errorf("table for export[%q] out of range", exp.Name) 475 } 476 } 477 } 478 return nil 479 } 480 481 func validateConstExpression(globals []*GlobalType, numFuncs uint32, expr *ConstantExpression, expectedType ValueType) (err error) { 482 var actualType ValueType 483 switch expr.Opcode { 484 case OpcodeI32Const: 485 // Treat constants as signed as their interpretation is not yet known per /RATIONALE.md 486 _, _, err = leb128.LoadInt32(expr.Data) 487 if err != nil { 488 return fmt.Errorf("read i32: %w", err) 489 } 490 actualType = ValueTypeI32 491 case OpcodeI64Const: 492 // Treat constants as signed as their interpretation is not yet known per /RATIONALE.md 493 _, _, err = leb128.LoadInt64(expr.Data) 494 if err != nil { 495 return fmt.Errorf("read i64: %w", err) 496 } 497 actualType = ValueTypeI64 498 case OpcodeF32Const: 499 _, err = ieee754.DecodeFloat32(expr.Data) 500 if err != nil { 501 return fmt.Errorf("read f32: %w", err) 502 } 503 actualType = ValueTypeF32 504 case OpcodeF64Const: 505 _, err = ieee754.DecodeFloat64(expr.Data) 506 if err != nil { 507 return fmt.Errorf("read f64: %w", err) 508 } 509 actualType = ValueTypeF64 510 case OpcodeGlobalGet: 511 id, _, err := leb128.LoadUint32(expr.Data) 512 if err != nil { 513 return fmt.Errorf("read index of global: %w", err) 514 } 515 if uint32(len(globals)) <= id { 516 return fmt.Errorf("global index out of range") 517 } 518 actualType = globals[id].ValType 519 case OpcodeRefNull: 520 if len(expr.Data) == 0 { 521 return fmt.Errorf("read reference type for ref.null: %w", io.ErrShortBuffer) 522 } 523 reftype := expr.Data[0] 524 if reftype != RefTypeFuncref && reftype != RefTypeExternref { 525 return fmt.Errorf("invalid type for ref.null: 0x%x", reftype) 526 } 527 actualType = reftype 528 case OpcodeRefFunc: 529 index, _, err := leb128.LoadUint32(expr.Data) 530 if err != nil { 531 return fmt.Errorf("read i32: %w", err) 532 } else if index >= numFuncs { 533 return fmt.Errorf("ref.func index out of range [%d] with length %d", index, numFuncs-1) 534 } 535 actualType = ValueTypeFuncref 536 case OpcodeVecV128Const: 537 if len(expr.Data) != 16 { 538 return fmt.Errorf("%s needs 16 bytes but was %d bytes", OpcodeVecV128ConstName, len(expr.Data)) 539 } 540 actualType = ValueTypeV128 541 default: 542 return fmt.Errorf("invalid opcode for const expression: 0x%x", expr.Opcode) 543 } 544 545 if actualType != expectedType { 546 return fmt.Errorf("const expression type mismatch expected %s but got %s", 547 ValueTypeName(expectedType), ValueTypeName(actualType)) 548 } 549 return nil 550 } 551 552 func (m *Module) validateDataCountSection() (err error) { 553 if m.DataCountSection != nil && int(*m.DataCountSection) != len(m.DataSection) { 554 err = fmt.Errorf("data count section (%d) doesn't match the length of data section (%d)", 555 *m.DataCountSection, len(m.DataSection)) 556 } 557 return 558 } 559 560 func (m *Module) buildGlobals(importedGlobals []*GlobalInstance) (globals []*GlobalInstance) { 561 globals = make([]*GlobalInstance, len(m.GlobalSection)) 562 for i, gs := range m.GlobalSection { 563 g := &GlobalInstance{Type: gs.Type} 564 switch v := executeConstExpression(importedGlobals, gs.Init).(type) { 565 case uint32: 566 g.Val = uint64(v) 567 case int32: 568 g.Val = uint64(uint32(v)) 569 case int64: 570 g.Val = uint64(v) 571 case float32: 572 g.Val = api.EncodeF32(v) 573 case float64: 574 g.Val = api.EncodeF64(v) 575 case [2]uint64: 576 g.Val, g.ValHi = v[0], v[1] 577 default: 578 panic(fmt.Errorf("BUG: invalid conversion %d", v)) 579 } 580 globals[i] = g 581 } 582 return 583 } 584 585 // BuildFunctions generates function instances for all host or wasm-defined 586 // functions in this module. 587 // 588 // # Notes 589 // - This relies on data generated by Module.BuildFunctionDefinitions. 590 // - This is exported for tests that don't call Instantiate, notably only 591 // enginetest.go. 592 func (m *ModuleInstance) BuildFunctions(mod *Module) (fns []*FunctionInstance) { 593 importCount := mod.ImportFuncCount() 594 fns = make([]*FunctionInstance, len(mod.FunctionSection)) 595 for i, section := range mod.FunctionSection { 596 code := mod.CodeSection[i] 597 d := mod.FunctionDefinitionSection[uint32(i)+importCount] 598 f := &FunctionInstance{ 599 IsHostFunction: code.IsHostFunction, 600 LocalTypes: code.LocalTypes, 601 Body: code.Body, 602 GoFunc: code.GoFunc, 603 TypeID: m.TypeIDs[section], 604 Module: m, 605 Idx: d.index, 606 Type: d.funcType, 607 Definition: d, 608 } 609 fns[i] = f 610 } 611 return 612 } 613 614 func paramNames(localNames IndirectNameMap, funcIdx uint32, paramLen int) []string { 615 for _, nm := range localNames { 616 // Only build parameter names if we have one for each. 617 if nm.Index != funcIdx || len(nm.NameMap) < paramLen { 618 continue 619 } 620 621 ret := make([]string, paramLen) 622 for _, p := range nm.NameMap { 623 if int(p.Index) < paramLen { 624 ret[p.Index] = p.Name 625 } 626 } 627 return ret 628 } 629 return nil 630 } 631 632 func (m *Module) buildMemory() (mem *MemoryInstance) { 633 memSec := m.MemorySection 634 if memSec != nil { 635 mem = NewMemoryInstance(memSec) 636 } 637 return 638 } 639 640 // Index is the offset in an index namespace, not necessarily an absolute position in a Module section. This is because 641 // index namespaces are often preceded by a corresponding type in the Module.ImportSection. 642 // 643 // For example, the function index namespace starts with any ExternTypeFunc in the Module.ImportSection followed by 644 // the Module.FunctionSection 645 // 646 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-index 647 type Index = uint32 648 649 // FunctionType is a possibly empty function signature. 650 // 651 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#function-types%E2%91%A0 652 type FunctionType struct { 653 // Params are the possibly empty sequence of value types accepted by a function with this signature. 654 Params []ValueType 655 656 // Results are the possibly empty sequence of value types returned by a function with this signature. 657 // 658 // Note: In WebAssembly 1.0 (20191205), there can be at most one result. 659 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#result-types%E2%91%A0 660 Results []ValueType 661 662 // string is cached as it is used both for String and key 663 string string 664 665 // ParamNumInUint64 is the number of uint64 values requires to represent the Wasm param type. 666 ParamNumInUint64 int 667 668 // ResultsNumInUint64 is the number of uint64 values requires to represent the Wasm result type. 669 ResultNumInUint64 int 670 } 671 672 func (f *FunctionType) CacheNumInUint64() { 673 if f.ParamNumInUint64 == 0 { 674 for _, tp := range f.Params { 675 f.ParamNumInUint64++ 676 if tp == ValueTypeV128 { 677 f.ParamNumInUint64++ 678 } 679 } 680 } 681 682 if f.ResultNumInUint64 == 0 { 683 for _, tp := range f.Results { 684 f.ResultNumInUint64++ 685 if tp == ValueTypeV128 { 686 f.ResultNumInUint64++ 687 } 688 } 689 } 690 } 691 692 // EqualsSignature returns true if the function type has the same parameters and results. 693 func (f *FunctionType) EqualsSignature(params []ValueType, results []ValueType) bool { 694 return bytes.Equal(f.Params, params) && bytes.Equal(f.Results, results) 695 } 696 697 // key gets or generates the key for Store.typeIDs. e.g. "i32_v" for one i32 parameter and no (void) result. 698 func (f *FunctionType) key() string { 699 if f.string != "" { 700 return f.string 701 } 702 var ret string 703 for _, b := range f.Params { 704 ret += ValueTypeName(b) 705 } 706 if len(f.Params) == 0 { 707 ret += "v_" 708 } else { 709 ret += "_" 710 } 711 for _, b := range f.Results { 712 ret += ValueTypeName(b) 713 } 714 if len(f.Results) == 0 { 715 ret += "v" 716 } 717 f.string = ret 718 return ret 719 } 720 721 // String implements fmt.Stringer. 722 func (f *FunctionType) String() string { 723 return f.key() 724 } 725 726 // Import is the binary representation of an import indicated by Type 727 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-import 728 type Import struct { 729 Type ExternType 730 // Module is the possibly empty primary namespace of this import 731 Module string 732 // Module is the possibly empty secondary namespace of this import 733 Name string 734 // DescFunc is the index in Module.TypeSection when Type equals ExternTypeFunc 735 DescFunc Index 736 // DescTable is the inlined Table when Type equals ExternTypeTable 737 DescTable *Table 738 // DescMem is the inlined Memory when Type equals ExternTypeMemory 739 DescMem *Memory 740 // DescGlobal is the inlined GlobalType when Type equals ExternTypeGlobal 741 DescGlobal *GlobalType 742 } 743 744 // Memory describes the limits of pages (64KB) in a memory. 745 type Memory struct { 746 Min, Cap, Max uint32 747 // IsMaxEncoded true if the Max is encoded in the original source (binary or text). 748 IsMaxEncoded bool 749 } 750 751 // Validate ensures values assigned to Min, Cap and Max are within valid thresholds. 752 func (m *Memory) Validate(memoryLimitPages uint32) error { 753 min, capacity, max := m.Min, m.Cap, m.Max 754 755 if max > memoryLimitPages { 756 return fmt.Errorf("max %d pages (%s) over limit of %d pages (%s)", 757 max, PagesToUnitOfBytes(max), memoryLimitPages, PagesToUnitOfBytes(memoryLimitPages)) 758 } else if min > memoryLimitPages { 759 return fmt.Errorf("min %d pages (%s) over limit of %d pages (%s)", 760 min, PagesToUnitOfBytes(min), memoryLimitPages, PagesToUnitOfBytes(memoryLimitPages)) 761 } else if min > max { 762 return fmt.Errorf("min %d pages (%s) > max %d pages (%s)", 763 min, PagesToUnitOfBytes(min), max, PagesToUnitOfBytes(max)) 764 } else if capacity < min { 765 return fmt.Errorf("capacity %d pages (%s) less than minimum %d pages (%s)", 766 capacity, PagesToUnitOfBytes(capacity), min, PagesToUnitOfBytes(min)) 767 } else if capacity > memoryLimitPages { 768 return fmt.Errorf("capacity %d pages (%s) over limit of %d pages (%s)", 769 capacity, PagesToUnitOfBytes(capacity), memoryLimitPages, PagesToUnitOfBytes(memoryLimitPages)) 770 } 771 return nil 772 } 773 774 type GlobalType struct { 775 ValType ValueType 776 Mutable bool 777 } 778 779 type Global struct { 780 Type *GlobalType 781 Init *ConstantExpression 782 } 783 784 type ConstantExpression struct { 785 Opcode Opcode 786 Data []byte 787 } 788 789 // Export is the binary representation of an export indicated by Type 790 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-export 791 type Export struct { 792 Type ExternType 793 794 // Name is what the host refers to this definition as. 795 Name string 796 797 // Index is the index of the definition to export, the index namespace is by Type 798 // e.g. If ExternTypeFunc, this is a position in the function index namespace. 799 Index Index 800 } 801 802 // Code is an entry in the Module.CodeSection containing the locals and body of the function. 803 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-code 804 type Code struct { 805 // IsHostFunction returns true if the function was implemented by the 806 // embedder (ex via wazero.HostModuleBuilder) instead of a wasm binary. 807 // 808 // Notably, host functions can use the caller's memory, which might be 809 // different from its defining module. 810 // 811 // See https://www.w3.org/TR/wasm-core-1/#host-functions%E2%91%A0 812 IsHostFunction bool 813 814 // LocalTypes are any function-scoped variables in insertion order. 815 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-local 816 LocalTypes []ValueType 817 818 // Body is a sequence of expressions ending in OpcodeEnd 819 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-expr 820 Body []byte 821 822 // GoFunc is non-nil when IsHostFunction and defined in go, either 823 // api.GoFunction or api.GoModuleFunction. When present, LocalTypes and Body must 824 // be nil. 825 // 826 // Note: This has no serialization format, so is not encodable. 827 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#host-functions%E2%91%A2 828 GoFunc interface{} 829 } 830 831 type DataSegment struct { 832 OffsetExpression *ConstantExpression 833 Init []byte 834 } 835 836 // IsPassive returns true if this data segment is "passive" in the sense that memory offset and 837 // index is determined at runtime and used by OpcodeMemoryInitName instruction in the bulk memory 838 // operations proposal. 839 // 840 // See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/appendix/changes.html#bulk-memory-and-table-instructions 841 func (d *DataSegment) IsPassive() bool { 842 return d.OffsetExpression == nil 843 } 844 845 // NameSection represent the known custom name subsections defined in the WebAssembly Binary Format 846 // 847 // Note: This can be nil if no names were decoded for any reason including configuration. 848 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#name-section%E2%91%A0 849 type NameSection struct { 850 // ModuleName is the symbolic identifier for a module. e.g. math 851 // 852 // Note: This can be empty for any reason including configuration. 853 ModuleName string 854 855 // FunctionNames is an association of a function index to its symbolic identifier. e.g. add 856 // 857 // * the key (idx) is in the function namespace, where module defined functions are preceded by imported ones. 858 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#functions%E2%91%A7 859 // 860 // For example, assuming the below text format is the second import, you would expect FunctionNames[1] = "mul" 861 // (import "Math" "Mul" (func $mul (param $x f32) (param $y f32) (result f32))) 862 // 863 // Note: FunctionNames are only used for debugging. At runtime, functions are called based on raw numeric index. 864 // Note: This can be nil for any reason including configuration. 865 FunctionNames NameMap 866 867 // LocalNames contains symbolic names for function parameters or locals that have one. 868 // 869 // Note: In the Text Format, function local names can inherit parameter 870 // names from their type. Here are some examples: 871 // * (module (import (func (param $x i32) (param i32))) (func (type 0))) = [{0, {x,0}}] 872 // * (module (import (func (param i32) (param $y i32))) (func (type 0) (local $z i32))) = [0, [{y,1},{z,2}]] 873 // * (module (func (param $x i32) (local $y i32) (local $z i32))) = [{x,0},{y,1},{z,2}] 874 // 875 // Note: LocalNames are only used for debugging. At runtime, locals are called based on raw numeric index. 876 // Note: This can be nil for any reason including configuration. 877 LocalNames IndirectNameMap 878 } 879 880 // NameMap associates an index with any associated names. 881 // 882 // Note: Often the index namespace bridges multiple sections. For example, the function index namespace starts with any 883 // ExternTypeFunc in the Module.ImportSection followed by the Module.FunctionSection 884 // 885 // Note: NameMap is unique by NameAssoc.Index, but NameAssoc.Name needn't be unique. 886 // Note: When encoding in the Binary format, this must be ordered by NameAssoc.Index 887 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-namemap 888 type NameMap []*NameAssoc 889 890 type NameAssoc struct { 891 Index Index 892 Name string 893 } 894 895 // IndirectNameMap associates an index with an association of names. 896 // 897 // Note: IndirectNameMap is unique by NameMapAssoc.Index, but NameMapAssoc.NameMap needn't be unique. 898 // Note: When encoding in the Binary format, this must be ordered by NameMapAssoc.Index 899 // https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-indirectnamemap 900 type IndirectNameMap []*NameMapAssoc 901 902 type NameMapAssoc struct { 903 Index Index 904 NameMap NameMap 905 } 906 907 // AllDeclarations returns all declarations for functions, globals, memories and tables in a module including imported ones. 908 func (m *Module) AllDeclarations() (functions []Index, globals []*GlobalType, memory *Memory, tables []*Table, err error) { 909 for _, imp := range m.ImportSection { 910 switch imp.Type { 911 case ExternTypeFunc: 912 functions = append(functions, imp.DescFunc) 913 case ExternTypeGlobal: 914 globals = append(globals, imp.DescGlobal) 915 case ExternTypeMemory: 916 memory = imp.DescMem 917 case ExternTypeTable: 918 tables = append(tables, imp.DescTable) 919 } 920 } 921 922 functions = append(functions, m.FunctionSection...) 923 for _, g := range m.GlobalSection { 924 globals = append(globals, g.Type) 925 } 926 if m.MemorySection != nil { 927 if memory != nil { // shouldn't be possible due to Validate 928 err = errors.New("at most one table allowed in module") 929 return 930 } 931 memory = m.MemorySection 932 } 933 if m.TableSection != nil { 934 tables = append(tables, m.TableSection...) 935 } 936 return 937 } 938 939 // SectionID identifies the sections of a Module in the WebAssembly 1.0 (20191205) Binary Format. 940 // 941 // Note: these are defined in the wasm package, instead of the binary package, as a key per section is needed regardless 942 // of format, and deferring to the binary type avoids confusion. 943 // 944 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0 945 type SectionID = byte 946 947 const ( 948 // SectionIDCustom includes the standard defined NameSection and possibly others not defined in the standard. 949 SectionIDCustom SectionID = iota // don't add anything not in https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0 950 SectionIDType 951 SectionIDImport 952 SectionIDFunction 953 SectionIDTable 954 SectionIDMemory 955 SectionIDGlobal 956 SectionIDExport 957 SectionIDStart 958 SectionIDElement 959 SectionIDCode 960 SectionIDData 961 962 // SectionIDDataCount may exist in WebAssembly 2.0 or WebAssembly 1.0 with CoreFeatureBulkMemoryOperations enabled. 963 // 964 // See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#data-count-section 965 // See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/appendix/changes.html#bulk-memory-and-table-instructions 966 SectionIDDataCount 967 ) 968 969 // SectionIDName returns the canonical name of a module section. 970 // https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0 971 func SectionIDName(sectionID SectionID) string { 972 switch sectionID { 973 case SectionIDCustom: 974 return "custom" 975 case SectionIDType: 976 return "type" 977 case SectionIDImport: 978 return "import" 979 case SectionIDFunction: 980 return "function" 981 case SectionIDTable: 982 return "table" 983 case SectionIDMemory: 984 return "memory" 985 case SectionIDGlobal: 986 return "global" 987 case SectionIDExport: 988 return "export" 989 case SectionIDStart: 990 return "start" 991 case SectionIDElement: 992 return "element" 993 case SectionIDCode: 994 return "code" 995 case SectionIDData: 996 return "data" 997 case SectionIDDataCount: 998 return "data_count" 999 } 1000 return "unknown" 1001 } 1002 1003 // ValueType is an alias of api.ValueType defined to simplify imports. 1004 type ValueType = api.ValueType 1005 1006 const ( 1007 ValueTypeI32 = api.ValueTypeI32 1008 ValueTypeI64 = api.ValueTypeI64 1009 ValueTypeF32 = api.ValueTypeF32 1010 ValueTypeF64 = api.ValueTypeF64 1011 // TODO: ValueTypeV128 is not exposed in the api pkg yet. 1012 ValueTypeV128 ValueType = 0x7b 1013 // TODO: ValueTypeFuncref is not exposed in the api pkg yet. 1014 ValueTypeFuncref ValueType = 0x70 1015 ValueTypeExternref = api.ValueTypeExternref 1016 ) 1017 1018 // ValueTypeName is an alias of api.ValueTypeName defined to simplify imports. 1019 func ValueTypeName(t ValueType) string { 1020 if t == ValueTypeFuncref { 1021 return "funcref" 1022 } else if t == ValueTypeV128 { 1023 return "v128" 1024 } 1025 return api.ValueTypeName(t) 1026 } 1027 1028 func isReferenceValueType(vt ValueType) bool { 1029 return vt == ValueTypeExternref || vt == ValueTypeFuncref 1030 } 1031 1032 // ExternType is an alias of api.ExternType defined to simplify imports. 1033 type ExternType = api.ExternType 1034 1035 const ( 1036 ExternTypeFunc = api.ExternTypeFunc 1037 ExternTypeFuncName = api.ExternTypeFuncName 1038 ExternTypeTable = api.ExternTypeTable 1039 ExternTypeTableName = api.ExternTypeTableName 1040 ExternTypeMemory = api.ExternTypeMemory 1041 ExternTypeMemoryName = api.ExternTypeMemoryName 1042 ExternTypeGlobal = api.ExternTypeGlobal 1043 ExternTypeGlobalName = api.ExternTypeGlobalName 1044 ) 1045 1046 // ExternTypeName is an alias of api.ExternTypeName defined to simplify imports. 1047 func ExternTypeName(t ValueType) string { 1048 return api.ExternTypeName(t) 1049 }