1 package wasm
2
3 import (
4 "context"
5 "encoding/binary"
6 "fmt"
7 "sync"
8 "sync/atomic"
9
10 "github.com/tetratelabs/wazero/api"
11 "github.com/tetratelabs/wazero/internal/close"
12 "github.com/tetratelabs/wazero/internal/internalapi"
13 "github.com/tetratelabs/wazero/internal/leb128"
14 internalsys "github.com/tetratelabs/wazero/internal/sys"
15 "github.com/tetratelabs/wazero/sys"
16 )
17
18
19
20
21 const nameToModuleShrinkThreshold = 100
22
23 type (
24
25
26
27
28
29
30
31
32
33
34
35 Store struct {
36
37 moduleList *ModuleInstance
38
39
40
41 nameToModule map[string]*ModuleInstance
42
43
44
45 nameToModuleCap int
46
47
48 EnabledFeatures api.CoreFeatures
49
50
51 Engine Engine
52
53
54
55 typeIDs map[string]FunctionTypeID
56
57
58
59 functionMaxTypes uint32
60
61
62 mux sync.RWMutex
63 }
64
65
66
67
68
69
70
71
72 ModuleInstance struct {
73 internalapi.WazeroOnlyType
74
75 ModuleName string
76 Exports map[string]*Export
77 Globals []*GlobalInstance
78 MemoryInstance *MemoryInstance
79 Tables []*TableInstance
80
81
82 Engine ModuleEngine
83
84
85
86 TypeIDs []FunctionTypeID
87
88
89
90
91
92 DataInstances []DataInstance
93
94
95
96 ElementInstances []ElementInstance
97
98
99
100
101
102
103
104
105
106
107 Sys *internalsys.Context
108
109
110
111
112
113
114
115 Closed atomic.Uint64
116
117
118 CodeCloser api.Closer
119
120
121 s *Store
122
123 prev, next *ModuleInstance
124
125 Source *Module
126
127
128 CloseNotifier close.Notifier
129 }
130
131
132
133
134 DataInstance = []byte
135
136
137
138 GlobalInstance struct {
139 Type GlobalType
140
141
142 Val uint64
143
144
145 ValHi uint64
146
147
148
149 Me ModuleEngine
150 Index Index
151 }
152
153
154
155
156 FunctionTypeID uint32
157 )
158
159
160 const maximumFunctionTypes = 1 << 27
161
162
163 func (m *ModuleInstance) GetFunctionTypeID(t *FunctionType) FunctionTypeID {
164 id, err := m.s.GetFunctionTypeID(t)
165 if err != nil {
166
167
168 panic(err)
169 }
170 return id
171 }
172
173 func (m *ModuleInstance) buildElementInstances(elements []ElementSegment) {
174 m.ElementInstances = make([][]Reference, len(elements))
175 for i, elm := range elements {
176 if elm.Type == RefTypeFuncref && elm.Mode == ElementModePassive {
177
178
179 inits := elm.Init
180 inst := make([]Reference, len(inits))
181 m.ElementInstances[i] = inst
182 for j, idx := range inits {
183 if idx != ElementInitNullReference {
184 inst[j] = m.Engine.FunctionInstanceReference(idx)
185 }
186 }
187 }
188 }
189 }
190
191 func (m *ModuleInstance) applyElements(elems []ElementSegment) {
192 for elemI := range elems {
193 elem := &elems[elemI]
194 if !elem.IsActive() ||
195
196 len(elem.Init) == 0 {
197 continue
198 }
199 var offset uint32
200 if elem.OffsetExpr.Opcode == OpcodeGlobalGet {
201
202 globalIdx, _, _ := leb128.LoadUint32(elem.OffsetExpr.Data)
203 global := m.Globals[globalIdx]
204 offset = uint32(global.Val)
205 } else {
206
207 o, _, _ := leb128.LoadInt32(elem.OffsetExpr.Data)
208 offset = uint32(o)
209 }
210
211 table := m.Tables[elem.TableIndex]
212 references := table.References
213 if int(offset)+len(elem.Init) > len(references) {
214
215
216
217
218
219
220
221 return
222 }
223
224 if table.Type == RefTypeExternref {
225 for i := 0; i < len(elem.Init); i++ {
226 references[offset+uint32(i)] = Reference(0)
227 }
228 } else {
229 for i, init := range elem.Init {
230 if init == ElementInitNullReference {
231 continue
232 }
233
234 var ref Reference
235 if index, ok := unwrapElementInitGlobalReference(init); ok {
236 global := m.Globals[index]
237 ref = Reference(global.Val)
238 } else {
239 ref = m.Engine.FunctionInstanceReference(index)
240 }
241 references[offset+uint32(i)] = ref
242 }
243 }
244 }
245 }
246
247
248
249 func (m *ModuleInstance) validateData(data []DataSegment) (err error) {
250 for i := range data {
251 d := &data[i]
252 if !d.IsPassive() {
253 offset := int(executeConstExpressionI32(m.Globals, &d.OffsetExpression))
254 ceil := offset + len(d.Init)
255 if offset < 0 || ceil > len(m.MemoryInstance.Buffer) {
256 return fmt.Errorf("%s[%d]: out of bounds memory access", SectionIDName(SectionIDData), i)
257 }
258 }
259 }
260 return
261 }
262
263
264
265
266 func (m *ModuleInstance) applyData(data []DataSegment) error {
267 m.DataInstances = make([][]byte, len(data))
268 for i := range data {
269 d := &data[i]
270 m.DataInstances[i] = d.Init
271 if !d.IsPassive() {
272 offset := executeConstExpressionI32(m.Globals, &d.OffsetExpression)
273 if offset < 0 || int(offset)+len(d.Init) > len(m.MemoryInstance.Buffer) {
274 return fmt.Errorf("%s[%d]: out of bounds memory access", SectionIDName(SectionIDData), i)
275 }
276 copy(m.MemoryInstance.Buffer[offset:], d.Init)
277 }
278 }
279 return nil
280 }
281
282
283 func (m *ModuleInstance) getExport(name string, et ExternType) (*Export, error) {
284 exp, ok := m.Exports[name]
285 if !ok {
286 return nil, fmt.Errorf("%q is not exported in module %q", name, m.ModuleName)
287 }
288 if exp.Type != et {
289 return nil, fmt.Errorf("export %q in module %q is a %s, not a %s", name, m.ModuleName, ExternTypeName(exp.Type), ExternTypeName(et))
290 }
291 return exp, nil
292 }
293
294 func NewStore(enabledFeatures api.CoreFeatures, engine Engine) *Store {
295 return &Store{
296 nameToModule: map[string]*ModuleInstance{},
297 nameToModuleCap: nameToModuleShrinkThreshold,
298 EnabledFeatures: enabledFeatures,
299 Engine: engine,
300 typeIDs: map[string]FunctionTypeID{},
301 functionMaxTypes: maximumFunctionTypes,
302 }
303 }
304
305
306
307
308
309
310
311
312
313 func (s *Store) Instantiate(
314 ctx context.Context,
315 module *Module,
316 name string,
317 sys *internalsys.Context,
318 typeIDs []FunctionTypeID,
319 ) (*ModuleInstance, error) {
320
321 m, err := s.instantiate(ctx, module, name, sys, typeIDs)
322 if err != nil {
323 return nil, err
324 }
325
326
327 if err = s.registerModule(m); err != nil {
328 _ = m.Close(ctx)
329 return nil, err
330 }
331 return m, nil
332 }
333
334 func (s *Store) instantiate(
335 ctx context.Context,
336 module *Module,
337 name string,
338 sysCtx *internalsys.Context,
339 typeIDs []FunctionTypeID,
340 ) (m *ModuleInstance, err error) {
341 m = &ModuleInstance{ModuleName: name, TypeIDs: typeIDs, Sys: sysCtx, s: s, Source: module}
342
343 m.Tables = make([]*TableInstance, int(module.ImportTableCount)+len(module.TableSection))
344 m.Globals = make([]*GlobalInstance, int(module.ImportGlobalCount)+len(module.GlobalSection))
345 m.Engine, err = s.Engine.NewModuleEngine(module, m)
346 if err != nil {
347 return nil, err
348 }
349
350 if err = m.resolveImports(module); err != nil {
351 return nil, err
352 }
353
354 err = m.buildTables(module,
355
356 s.EnabledFeatures.IsEnabled(api.CoreFeatureReferenceTypes))
357 if err != nil {
358 return nil, err
359 }
360
361 m.buildGlobals(module, m.Engine.FunctionInstanceReference)
362 m.buildMemory(module)
363 m.Exports = module.Exports
364
365
366
367
368 if !s.EnabledFeatures.IsEnabled(api.CoreFeatureReferenceTypes) {
369 if err = m.validateData(module.DataSection); err != nil {
370 return nil, err
371 }
372 }
373
374
375 m.buildElementInstances(module.ElementSection)
376
377
378 if err = m.applyData(module.DataSection); err != nil {
379 return nil, err
380 }
381
382 m.applyElements(module.ElementSection)
383
384 m.Engine.DoneInstantiation()
385
386
387 if module.StartSection != nil {
388 funcIdx := *module.StartSection
389 ce := m.Engine.NewFunction(funcIdx)
390 _, err = ce.Call(ctx)
391 if exitErr, ok := err.(*sys.ExitError); ok {
392 return nil, exitErr
393 } else if err != nil {
394 return nil, fmt.Errorf("start %s failed: %w", module.funcDesc(SectionIDFunction, funcIdx), err)
395 }
396 }
397 return
398 }
399
400 func (m *ModuleInstance) resolveImports(module *Module) (err error) {
401 for moduleName, imports := range module.ImportPerModule {
402 var importedModule *ModuleInstance
403 importedModule, err = m.s.module(moduleName)
404 if err != nil {
405 return err
406 }
407
408 for _, i := range imports {
409 var imported *Export
410 imported, err = importedModule.getExport(i.Name, i.Type)
411 if err != nil {
412 return
413 }
414
415 switch i.Type {
416 case ExternTypeFunc:
417 expectedType := &module.TypeSection[i.DescFunc]
418 src := importedModule.Source
419 actual := src.typeOfFunction(imported.Index)
420 if !actual.EqualsSignature(expectedType.Params, expectedType.Results) {
421 err = errorInvalidImport(i, fmt.Errorf("signature mismatch: %s != %s", expectedType, actual))
422 return
423 }
424
425 m.Engine.ResolveImportedFunction(i.IndexPerType, imported.Index, importedModule.Engine)
426 case ExternTypeTable:
427 expected := i.DescTable
428 importedTable := importedModule.Tables[imported.Index]
429 if expected.Type != importedTable.Type {
430 err = errorInvalidImport(i, fmt.Errorf("table type mismatch: %s != %s",
431 RefTypeName(expected.Type), RefTypeName(importedTable.Type)))
432 return
433 }
434
435 if expected.Min > importedTable.Min {
436 err = errorMinSizeMismatch(i, expected.Min, importedTable.Min)
437 return
438 }
439
440 if expected.Max != nil {
441 expectedMax := *expected.Max
442 if importedTable.Max == nil {
443 err = errorNoMax(i, expectedMax)
444 return
445 } else if expectedMax < *importedTable.Max {
446 err = errorMaxSizeMismatch(i, expectedMax, *importedTable.Max)
447 return
448 }
449 }
450 m.Tables[i.IndexPerType] = importedTable
451 case ExternTypeMemory:
452 expected := i.DescMem
453 importedMemory := importedModule.MemoryInstance
454
455 if expected.Min > memoryBytesNumToPages(uint64(len(importedMemory.Buffer))) {
456 err = errorMinSizeMismatch(i, expected.Min, importedMemory.Min)
457 return
458 }
459
460 if expected.Max < importedMemory.Max {
461 err = errorMaxSizeMismatch(i, expected.Max, importedMemory.Max)
462 return
463 }
464 m.MemoryInstance = importedMemory
465 m.Engine.ResolveImportedMemory(importedModule.Engine)
466 case ExternTypeGlobal:
467 expected := i.DescGlobal
468 importedGlobal := importedModule.Globals[imported.Index]
469
470 if expected.Mutable != importedGlobal.Type.Mutable {
471 err = errorInvalidImport(i, fmt.Errorf("mutability mismatch: %t != %t",
472 expected.Mutable, importedGlobal.Type.Mutable))
473 return
474 }
475
476 if expected.ValType != importedGlobal.Type.ValType {
477 err = errorInvalidImport(i, fmt.Errorf("value type mismatch: %s != %s",
478 ValueTypeName(expected.ValType), ValueTypeName(importedGlobal.Type.ValType)))
479 return
480 }
481 m.Globals[i.IndexPerType] = importedGlobal
482 }
483 }
484 }
485 return
486 }
487
488 func errorMinSizeMismatch(i *Import, expected, actual uint32) error {
489 return errorInvalidImport(i, fmt.Errorf("minimum size mismatch: %d > %d", expected, actual))
490 }
491
492 func errorNoMax(i *Import, expected uint32) error {
493 return errorInvalidImport(i, fmt.Errorf("maximum size mismatch: %d, but actual has no max", expected))
494 }
495
496 func errorMaxSizeMismatch(i *Import, expected, actual uint32) error {
497 return errorInvalidImport(i, fmt.Errorf("maximum size mismatch: %d < %d", expected, actual))
498 }
499
500 func errorInvalidImport(i *Import, err error) error {
501 return fmt.Errorf("import %s[%s.%s]: %w", ExternTypeName(i.Type), i.Module, i.Name, err)
502 }
503
504
505
506
507 func executeConstExpressionI32(importedGlobals []*GlobalInstance, expr *ConstantExpression) (ret int32) {
508 switch expr.Opcode {
509 case OpcodeI32Const:
510 ret, _, _ = leb128.LoadInt32(expr.Data)
511 case OpcodeGlobalGet:
512 id, _, _ := leb128.LoadUint32(expr.Data)
513 g := importedGlobals[id]
514 ret = int32(g.Val)
515 }
516 return
517 }
518
519
520
521
522
523
524 func (g *GlobalInstance) initialize(importedGlobals []*GlobalInstance, expr *ConstantExpression, funcRefResolver func(funcIndex Index) Reference) {
525 switch expr.Opcode {
526 case OpcodeI32Const:
527
528 v, _, _ := leb128.LoadInt32(expr.Data)
529 g.Val = uint64(uint32(v))
530 case OpcodeI64Const:
531
532 v, _, _ := leb128.LoadInt64(expr.Data)
533 g.Val = uint64(v)
534 case OpcodeF32Const:
535 g.Val = uint64(binary.LittleEndian.Uint32(expr.Data))
536 case OpcodeF64Const:
537 g.Val = binary.LittleEndian.Uint64(expr.Data)
538 case OpcodeGlobalGet:
539 id, _, _ := leb128.LoadUint32(expr.Data)
540 importedG := importedGlobals[id]
541 switch importedG.Type.ValType {
542 case ValueTypeI32:
543 g.Val = uint64(uint32(importedG.Val))
544 case ValueTypeI64:
545 g.Val = importedG.Val
546 case ValueTypeF32:
547 g.Val = importedG.Val
548 case ValueTypeF64:
549 g.Val = importedG.Val
550 case ValueTypeV128:
551 g.Val, g.ValHi = importedG.Val, importedG.ValHi
552 case ValueTypeFuncref, ValueTypeExternref:
553 g.Val = importedG.Val
554 }
555 case OpcodeRefNull:
556 switch expr.Data[0] {
557 case ValueTypeExternref, ValueTypeFuncref:
558 g.Val = 0
559 }
560 case OpcodeRefFunc:
561 v, _, _ := leb128.LoadUint32(expr.Data)
562 g.Val = uint64(funcRefResolver(v))
563 case OpcodeVecV128Const:
564 g.Val, g.ValHi = binary.LittleEndian.Uint64(expr.Data[0:8]), binary.LittleEndian.Uint64(expr.Data[8:16])
565 }
566 }
567
568
569 func (g *GlobalInstance) String() string {
570 switch g.Type.ValType {
571 case ValueTypeI32, ValueTypeI64:
572 return fmt.Sprintf("global(%d)", g.Val)
573 case ValueTypeF32:
574 return fmt.Sprintf("global(%f)", api.DecodeF32(g.Val))
575 case ValueTypeF64:
576 return fmt.Sprintf("global(%f)", api.DecodeF64(g.Val))
577 default:
578 panic(fmt.Errorf("BUG: unknown value type %X", g.Type.ValType))
579 }
580 }
581
582 func (g *GlobalInstance) Value() (uint64, uint64) {
583 if g.Me != nil {
584 return g.Me.GetGlobalValue(g.Index)
585 }
586 return g.Val, g.ValHi
587 }
588
589 func (s *Store) GetFunctionTypeIDs(ts []FunctionType) ([]FunctionTypeID, error) {
590 ret := make([]FunctionTypeID, len(ts))
591 for i := range ts {
592 t := &ts[i]
593 inst, err := s.GetFunctionTypeID(t)
594 if err != nil {
595 return nil, err
596 }
597 ret[i] = inst
598 }
599 return ret, nil
600 }
601
602 func (s *Store) GetFunctionTypeID(t *FunctionType) (FunctionTypeID, error) {
603 s.mux.RLock()
604 key := t.key()
605 id, ok := s.typeIDs[key]
606 s.mux.RUnlock()
607 if !ok {
608 s.mux.Lock()
609 defer s.mux.Unlock()
610
611 if id, ok = s.typeIDs[key]; ok {
612 return id, nil
613 }
614 l := len(s.typeIDs)
615 if uint32(l) >= s.functionMaxTypes {
616 return 0, fmt.Errorf("too many function types in a store")
617 }
618 id = FunctionTypeID(l)
619 s.typeIDs[key] = id
620 }
621 return id, nil
622 }
623
624
625 func (s *Store) CloseWithExitCode(ctx context.Context, exitCode uint32) (err error) {
626 s.mux.Lock()
627 defer s.mux.Unlock()
628
629 for m := s.moduleList; m != nil; m = m.next {
630
631 if e := m.closeWithExitCode(ctx, exitCode); e != nil && err == nil {
632
633 err = e
634 }
635 }
636 s.moduleList = nil
637 s.nameToModule = nil
638 s.nameToModuleCap = 0
639 s.typeIDs = nil
640 return
641 }
642
View as plain text