1 package compiler
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7 "reflect"
8 "runtime"
9 "sort"
10 "sync"
11 "unsafe"
12
13 "github.com/tetratelabs/wazero/api"
14 "github.com/tetratelabs/wazero/experimental"
15 "github.com/tetratelabs/wazero/internal/asm"
16 "github.com/tetratelabs/wazero/internal/bitpack"
17 "github.com/tetratelabs/wazero/internal/filecache"
18 "github.com/tetratelabs/wazero/internal/internalapi"
19 "github.com/tetratelabs/wazero/internal/platform"
20 "github.com/tetratelabs/wazero/internal/version"
21 "github.com/tetratelabs/wazero/internal/wasm"
22 "github.com/tetratelabs/wazero/internal/wasmdebug"
23 "github.com/tetratelabs/wazero/internal/wasmruntime"
24 "github.com/tetratelabs/wazero/internal/wazeroir"
25 )
26
27
28
29
30 type (
31
32 engine struct {
33 enabledFeatures api.CoreFeatures
34 codes map[wasm.ModuleID]*compiledModule
35 fileCache filecache.Cache
36 mux sync.RWMutex
37
38 setFinalizer func(obj interface{}, finalizer interface{})
39 wazeroVersion string
40 }
41
42
43 moduleEngine struct {
44
45
46
47
48
49
50 functions []function
51
52
53
54 module *compiledModule
55 }
56
57
58
59
60
61 callEngine struct {
62 internalapi.WazeroOnlyType
63
64
65
66
67
68
69 moduleContext
70 stackContext
71 exitContext
72 archContext
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132 stack []uint64
133
134
135 initialFn *function
136
137
138
139 module *compiledModule
140
141
142
143 stackIterator stackIterator
144 }
145
146
147
148 moduleContext struct {
149
150
151
152 fn *function
153
154
155
156
157
158
159 moduleInstance *wasm.ModuleInstance
160
161
162
163 globalElement0Address uintptr
164
165
166 memoryElement0Address uintptr
167
168 memorySliceLen uint64
169
170 memoryInstance *wasm.MemoryInstance
171
172
173 tablesElement0Address uintptr
174
175
176 functionsElement0Address uintptr
177
178
179 typeIDsElement0Address uintptr
180
181
182 dataInstancesElement0Address uintptr
183
184
185 elementInstancesElement0Address uintptr
186 }
187
188
189 stackContext struct {
190
191
192
193
194
195
196
197 stackPointer uint64
198
199
200
201
202
203
204
205
206 stackBasePointerInBytes uint64
207
208
209
210 stackElement0Address uintptr
211
212
213
214 stackLenInBytes uint64
215 }
216
217
218 exitContext struct {
219
220
221
222 statusCode nativeCallStatusCode
223
224
225
226 builtinFunctionCallIndex wasm.Index
227
228
229
230 returnAddress uintptr
231
232
233 callerModuleInstance *wasm.ModuleInstance
234 }
235
236
237
238
239
240 callFrame struct {
241
242
243
244 returnAddress uintptr
245
246
247 returnStackBasePointerInBytes uint64
248
249
250 function *function
251 }
252
253
254 function struct {
255
256
257
258
259
260
261 codeInitialAddress uintptr
262
263 moduleInstance *wasm.ModuleInstance
264
265 typeID wasm.FunctionTypeID
266
267 funcType *wasm.FunctionType
268
269 parent *compiledFunction
270 }
271
272 compiledModule struct {
273
274
275
276
277
278
279
280
281
282
283 *compiledCode
284 functions []compiledFunction
285
286 ensureTermination bool
287 }
288
289 compiledCode struct {
290 source *wasm.Module
291 executable asm.CodeSegment
292 }
293
294
295
296 compiledFunction struct {
297
298 executableOffset uintptr
299
300
301 stackPointerCeil uint64
302
303 index wasm.Index
304 goFunc interface{}
305 listener experimental.FunctionListener
306 parent *compiledCode
307 sourceOffsetMap sourceOffsetMap
308 }
309
310
311
312
313
314
315
316
317
318
319
320
321
322 sourceOffsetMap struct {
323
324
325
326
327 irOperationOffsetsInNativeBinary bitpack.OffsetArray
328
329
330 irOperationSourceOffsetsInWasmBinary bitpack.OffsetArray
331 }
332
333
334
335 functionListenerInvocation struct {
336 experimental.FunctionListener
337 def api.FunctionDefinition
338 }
339 )
340
341
342
343 const (
344
345 moduleEngineFunctionsOffset = 0
346
347
348 callEngineModuleContextFnOffset = 0
349 callEngineModuleContextModuleInstanceOffset = 8
350 callEngineModuleContextGlobalElement0AddressOffset = 16
351 callEngineModuleContextMemoryElement0AddressOffset = 24
352 callEngineModuleContextMemorySliceLenOffset = 32
353 callEngineModuleContextMemoryInstanceOffset = 40
354 callEngineModuleContextTablesElement0AddressOffset = 48
355 callEngineModuleContextFunctionsElement0AddressOffset = 56
356 callEngineModuleContextTypeIDsElement0AddressOffset = 64
357 callEngineModuleContextDataInstancesElement0AddressOffset = 72
358 callEngineModuleContextElementInstancesElement0AddressOffset = 80
359
360
361 callEngineStackContextStackPointerOffset = 88
362 callEngineStackContextStackBasePointerInBytesOffset = 96
363 callEngineStackContextStackElement0AddressOffset = 104
364 callEngineStackContextStackLenInBytesOffset = 112
365
366
367 callEngineExitContextNativeCallStatusCodeOffset = 120
368 callEngineExitContextBuiltinFunctionCallIndexOffset = 124
369 callEngineExitContextReturnAddressOffset = 128
370 callEngineExitContextCallerModuleInstanceOffset = 136
371
372
373 functionCodeInitialAddressOffset = 0
374 functionModuleInstanceOffset = 8
375 functionTypeIDOffset = 16
376 functionSize = 40
377
378
379 moduleInstanceGlobalsOffset = 24
380 moduleInstanceMemoryOffset = 48
381 moduleInstanceTablesOffset = 56
382 moduleInstanceEngineOffset = 80
383 moduleInstanceTypeIDsOffset = 96
384 moduleInstanceDataInstancesOffset = 120
385 moduleInstanceElementInstancesOffset = 144
386
387
388 tableInstanceTableOffset = 0
389 tableInstanceTableLenOffset = 8
390
391
392 memoryInstanceBufferOffset = 0
393 memoryInstanceBufferLenOffset = 8
394
395
396 globalInstanceValueOffset = 8
397
398
399
400
401 interfaceDataOffset = 8
402
403
404 dataInstanceStructSize = 24
405
406
407 elementInstanceStructSize = 24
408
409
410 pointerSizeLog2 = 3
411
412
413 callFrameDataSizeInUint64 = 24 / 8
414 )
415
416
417
418 type nativeCallStatusCode uint32
419
420 const (
421
422 nativeCallStatusCodeReturned nativeCallStatusCode = iota
423
424 nativeCallStatusCodeCallGoHostFunction
425
426 nativeCallStatusCodeCallBuiltInFunction
427
428 nativeCallStatusCodeUnreachable
429
430 nativeCallStatusCodeInvalidFloatToIntConversion
431
432 nativeCallStatusCodeMemoryOutOfBounds
433
434
435 nativeCallStatusCodeInvalidTableAccess
436
437 nativeCallStatusCodeTypeMismatchOnIndirectCall
438 nativeCallStatusIntegerOverflow
439 nativeCallStatusIntegerDivisionByZero
440 nativeCallStatusModuleClosed
441 )
442
443
444 func (s nativeCallStatusCode) causePanic() {
445 var err error
446 switch s {
447 case nativeCallStatusIntegerOverflow:
448 err = wasmruntime.ErrRuntimeIntegerOverflow
449 case nativeCallStatusIntegerDivisionByZero:
450 err = wasmruntime.ErrRuntimeIntegerDivideByZero
451 case nativeCallStatusCodeInvalidFloatToIntConversion:
452 err = wasmruntime.ErrRuntimeInvalidConversionToInteger
453 case nativeCallStatusCodeUnreachable:
454 err = wasmruntime.ErrRuntimeUnreachable
455 case nativeCallStatusCodeMemoryOutOfBounds:
456 err = wasmruntime.ErrRuntimeOutOfBoundsMemoryAccess
457 case nativeCallStatusCodeInvalidTableAccess:
458 err = wasmruntime.ErrRuntimeInvalidTableAccess
459 case nativeCallStatusCodeTypeMismatchOnIndirectCall:
460 err = wasmruntime.ErrRuntimeIndirectCallTypeMismatch
461 }
462 panic(err)
463 }
464
465 func (s nativeCallStatusCode) String() (ret string) {
466 switch s {
467 case nativeCallStatusCodeReturned:
468 ret = "returned"
469 case nativeCallStatusCodeCallGoHostFunction:
470 ret = "call_host_function"
471 case nativeCallStatusCodeCallBuiltInFunction:
472 ret = "call_builtin_function"
473 case nativeCallStatusCodeUnreachable:
474 ret = "unreachable"
475 case nativeCallStatusCodeInvalidFloatToIntConversion:
476 ret = "invalid float to int conversion"
477 case nativeCallStatusCodeMemoryOutOfBounds:
478 ret = "memory out of bounds"
479 case nativeCallStatusCodeInvalidTableAccess:
480 ret = "invalid table access"
481 case nativeCallStatusCodeTypeMismatchOnIndirectCall:
482 ret = "type mismatch on indirect call"
483 case nativeCallStatusIntegerOverflow:
484 ret = "integer overflow"
485 case nativeCallStatusIntegerDivisionByZero:
486 ret = "integer division by zero"
487 case nativeCallStatusModuleClosed:
488 ret = "module closed"
489 default:
490 panic("BUG")
491 }
492 return
493 }
494
495
496 func releaseCompiledModule(cm *compiledModule) {
497 if err := cm.executable.Unmap(); err != nil {
498
499
500
501 panic(fmt.Errorf("compiler: failed to munmap code segment: %w", err))
502 }
503 }
504
505
506 func (e *engine) CompiledModuleCount() uint32 {
507 return uint32(len(e.codes))
508 }
509
510
511 func (e *engine) DeleteCompiledModule(module *wasm.Module) {
512 e.deleteCompiledModule(module)
513 }
514
515
516 func (e *engine) Close() (err error) {
517 e.mux.Lock()
518 defer e.mux.Unlock()
519
520 e.codes = nil
521 return
522 }
523
524
525 func (e *engine) CompileModule(_ context.Context, module *wasm.Module, listeners []experimental.FunctionListener, ensureTermination bool) error {
526 if _, ok, err := e.getCompiledModule(module, listeners); ok {
527 return nil
528 } else if err != nil {
529 return err
530 }
531
532 irCompiler, err := wazeroir.NewCompiler(e.enabledFeatures, callFrameDataSizeInUint64, module, ensureTermination)
533 if err != nil {
534 return err
535 }
536
537 var withGoFunc bool
538 localFuncs, importedFuncs := len(module.FunctionSection), module.ImportFunctionCount
539 cm := &compiledModule{
540 compiledCode: &compiledCode{
541 source: module,
542 },
543 functions: make([]compiledFunction, localFuncs),
544 ensureTermination: ensureTermination,
545 }
546
547 if localFuncs == 0 {
548 return e.addCompiledModule(module, cm, withGoFunc)
549 }
550
551
552 e.setFinalizer(cm, releaseCompiledModule)
553 ln := len(listeners)
554 cmp := newCompiler()
555 asmNodes := new(asmNodes)
556 offsets := new(offsets)
557
558
559
560 var executable asm.CodeSegment
561 defer func() {
562
563
564
565
566
567 if err := executable.Unmap(); err != nil {
568 panic(fmt.Errorf("compiler: failed to munmap code segment: %w", err))
569 }
570 }()
571
572 for i := range module.CodeSection {
573 typ := &module.TypeSection[module.FunctionSection[i]]
574 buf := executable.NextCodeSection()
575 funcIndex := wasm.Index(i)
576 compiledFn := &cm.functions[i]
577 compiledFn.executableOffset = executable.Size()
578 compiledFn.parent = cm.compiledCode
579 compiledFn.index = importedFuncs + funcIndex
580 if i < ln {
581 compiledFn.listener = listeners[i]
582 }
583
584 if codeSeg := &module.CodeSection[i]; codeSeg.GoFunc != nil {
585 cmp.Init(typ, nil, compiledFn.listener != nil)
586 withGoFunc = true
587 if err = compileGoDefinedHostFunction(buf, cmp); err != nil {
588 def := module.FunctionDefinition(compiledFn.index)
589 return fmt.Errorf("error compiling host go func[%s]: %w", def.DebugName(), err)
590 }
591 compiledFn.goFunc = codeSeg.GoFunc
592 } else {
593 ir, err := irCompiler.Next()
594 if err != nil {
595 return fmt.Errorf("failed to lower func[%d]: %v", i, err)
596 }
597 cmp.Init(typ, ir, compiledFn.listener != nil)
598
599 compiledFn.stackPointerCeil, compiledFn.sourceOffsetMap, err = compileWasmFunction(buf, cmp, ir, asmNodes, offsets)
600 if err != nil {
601 def := module.FunctionDefinition(compiledFn.index)
602 return fmt.Errorf("error compiling wasm func[%s]: %w", def.DebugName(), err)
603 }
604 }
605 }
606
607 if runtime.GOARCH == "arm64" {
608
609 if err := platform.MprotectRX(executable.Bytes()); err != nil {
610 return err
611 }
612 }
613 cm.executable, executable = executable, asm.CodeSegment{}
614 return e.addCompiledModule(module, cm, withGoFunc)
615 }
616
617
618 func (e *engine) NewModuleEngine(module *wasm.Module, instance *wasm.ModuleInstance) (wasm.ModuleEngine, error) {
619 me := &moduleEngine{
620 functions: make([]function, len(module.FunctionSection)+int(module.ImportFunctionCount)),
621 }
622
623
624
625 cm, ok, err := e.getCompiledModule(module,
626
627
628 nil)
629 if !ok {
630 return nil, errors.New("source module must be compiled before instantiation")
631 } else if err != nil {
632 return nil, err
633 }
634
635 for i := range cm.functions {
636 c := &cm.functions[i]
637 offset := int(module.ImportFunctionCount) + i
638 typeIndex := module.FunctionSection[i]
639 me.functions[offset] = function{
640 codeInitialAddress: cm.executable.Addr() + c.executableOffset,
641 moduleInstance: instance,
642 typeID: instance.TypeIDs[typeIndex],
643 funcType: &module.TypeSection[typeIndex],
644 parent: c,
645 }
646 }
647
648 me.module = cm
649 return me, nil
650 }
651
652
653 func (e *moduleEngine) ResolveImportedFunction(index, indexInImportedModule wasm.Index, importedModuleEngine wasm.ModuleEngine) {
654 imported := importedModuleEngine.(*moduleEngine)
655
656 e.functions[index] = imported.functions[indexInImportedModule]
657 }
658
659
660 func (e *moduleEngine) GetGlobalValue(wasm.Index) (lo, hi uint64) {
661 panic("BUG: GetGlobalValue should never be called on compiler mode")
662 }
663
664
665 func (e *moduleEngine) OwnsGlobals() bool { return false }
666
667
668 func (e *moduleEngine) ResolveImportedMemory(wasm.ModuleEngine) {}
669
670
671 func (e *moduleEngine) FunctionInstanceReference(funcIndex wasm.Index) wasm.Reference {
672 return uintptr(unsafe.Pointer(&e.functions[funcIndex]))
673 }
674
675
676 func (e *moduleEngine) DoneInstantiation() {}
677
678
679 func (e *moduleEngine) NewFunction(index wasm.Index) api.Function {
680 return e.newFunction(&e.functions[index])
681 }
682
683 func (e *moduleEngine) newFunction(f *function) api.Function {
684 initStackSize := initialStackSize
685 if initialStackSize < f.parent.stackPointerCeil {
686 initStackSize = f.parent.stackPointerCeil * 2
687 }
688 return e.newCallEngine(initStackSize, f)
689 }
690
691
692 func (e *moduleEngine) LookupFunction(t *wasm.TableInstance, typeId wasm.FunctionTypeID, tableOffset wasm.Index) (*wasm.ModuleInstance, wasm.Index) {
693 if tableOffset >= uint32(len(t.References)) || t.Type != wasm.RefTypeFuncref {
694 panic(wasmruntime.ErrRuntimeInvalidTableAccess)
695 }
696 rawPtr := t.References[tableOffset]
697 if rawPtr == 0 {
698 panic(wasmruntime.ErrRuntimeInvalidTableAccess)
699 }
700
701 tf := functionFromUintptr(rawPtr)
702 if tf.typeID != typeId {
703 panic(wasmruntime.ErrRuntimeIndirectCallTypeMismatch)
704 }
705 return tf.moduleInstance, tf.parent.index
706 }
707
708
709
710 func functionFromUintptr(ptr uintptr) *function {
711
712
713
714
715
716 var wrapped *uintptr = &ptr
717 return *(**function)(unsafe.Pointer(wrapped))
718 }
719
720
721 func (ce *callEngine) Definition() api.FunctionDefinition {
722 return ce.initialFn.definition()
723 }
724
725 func (f *function) definition() api.FunctionDefinition {
726 compiled := f.parent
727 return compiled.parent.source.FunctionDefinition(compiled.index)
728 }
729
730
731 func (ce *callEngine) Call(ctx context.Context, params ...uint64) (results []uint64, err error) {
732 ft := ce.initialFn.funcType
733 if n := ft.ParamNumInUint64; n != len(params) {
734 return nil, fmt.Errorf("expected %d params, but passed %d", n, len(params))
735 }
736 return ce.call(ctx, params, nil)
737 }
738
739
740 func (ce *callEngine) CallWithStack(ctx context.Context, stack []uint64) error {
741 params, results, err := wasm.SplitCallStack(ce.initialFn.funcType, stack)
742 if err != nil {
743 return err
744 }
745 _, err = ce.call(ctx, params, results)
746 return err
747 }
748
749 func (ce *callEngine) call(ctx context.Context, params, results []uint64) (_ []uint64, err error) {
750 m := ce.initialFn.moduleInstance
751 if ce.module.ensureTermination {
752 select {
753 case <-ctx.Done():
754
755
756 m.CloseWithCtxErr(ctx)
757 return nil, m.FailIfClosed()
758 default:
759 }
760 }
761
762
763
764
765
766 defer func() {
767 err = ce.deferredOnCall(ctx, m, recover())
768 if err == nil {
769
770 err = m.FailIfClosed()
771 }
772
773 runtime.KeepAlive(ce.module)
774 }()
775
776 ft := ce.initialFn.funcType
777 ce.initializeStack(ft, params)
778
779 if ce.module.ensureTermination {
780 done := m.CloseModuleOnCanceledOrTimeout(ctx)
781 defer done()
782 }
783
784 ce.execWasmFunction(ctx, m)
785
786
787
788
789 if results == nil && ft.ResultNumInUint64 > 0 {
790 results = make([]uint64, ft.ResultNumInUint64)
791 }
792 copy(results, ce.stack)
793 return results, nil
794 }
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820 func (ce *callEngine) initializeStack(tp *wasm.FunctionType, args []uint64) {
821 for _, v := range args {
822 ce.pushValue(v)
823 }
824
825 ce.stackPointer = uint64(callFrameOffset(tp))
826
827 for i := 0; i < callFrameDataSizeInUint64; i++ {
828 ce.stack[ce.stackPointer] = 0
829 ce.stackPointer++
830 }
831 }
832
833
834
835
836 func callFrameOffset(funcType *wasm.FunctionType) (ret int) {
837 ret = funcType.ResultNumInUint64
838 if ret < funcType.ParamNumInUint64 {
839 ret = funcType.ParamNumInUint64
840 }
841 return
842 }
843
844
845
846
847
848
849 func (ce *callEngine) deferredOnCall(ctx context.Context, m *wasm.ModuleInstance, recovered interface{}) (err error) {
850 if recovered != nil {
851 builder := wasmdebug.NewErrorBuilder()
852
853
854
855 fn := ce.fn
856 pc := uint64(ce.returnAddress)
857 stackBasePointer := int(ce.stackBasePointerInBytes >> 3)
858 functionListeners := make([]functionListenerInvocation, 0, 16)
859
860 for {
861 def := fn.definition()
862
863
864
865 var sources []string
866 if p := fn.parent; p.parent.executable.Bytes() != nil {
867 if fn.parent.sourceOffsetMap.irOperationSourceOffsetsInWasmBinary != nil {
868 offset := fn.getSourceOffsetInWasmBinary(pc)
869 sources = p.parent.source.DWARFLines.Line(offset)
870 }
871 }
872 builder.AddFrame(def.DebugName(), def.ParamTypes(), def.ResultTypes(), sources)
873
874 if fn.parent.listener != nil {
875 functionListeners = append(functionListeners, functionListenerInvocation{
876 FunctionListener: fn.parent.listener,
877 def: fn.definition(),
878 })
879 }
880
881 callFrameOffset := callFrameOffset(fn.funcType)
882 if stackBasePointer != 0 {
883 frame := *(*callFrame)(unsafe.Pointer(&ce.stack[stackBasePointer+callFrameOffset]))
884 fn = frame.function
885 pc = uint64(frame.returnAddress)
886 stackBasePointer = int(frame.returnStackBasePointerInBytes >> 3)
887 } else {
888 break
889 }
890 }
891
892 err = builder.FromRecovered(recovered)
893 for i := range functionListeners {
894 functionListeners[i].Abort(ctx, m, functionListeners[i].def, err)
895 }
896 }
897
898
899 ce.stackBasePointerInBytes, ce.stackPointer, ce.moduleInstance = 0, 0, nil
900 ce.moduleContext.fn = ce.initialFn
901 return
902 }
903
904
905
906
907 func (f *function) getSourceOffsetInWasmBinary(pc uint64) uint64 {
908 srcMap := &f.parent.sourceOffsetMap
909 n := bitpack.OffsetArrayLen(srcMap.irOperationOffsetsInNativeBinary) + 1
910
911
912 pcOffsetInNativeBinary := pc - uint64(f.codeInitialAddress)
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927 index := sort.Search(n, func(i int) bool {
928 if i == n-1 {
929 return true
930 }
931 return srcMap.irOperationOffsetsInNativeBinary.Index(i) >= pcOffsetInNativeBinary
932 })
933 if index == 0 && bitpack.OffsetArrayLen(srcMap.irOperationSourceOffsetsInWasmBinary) > 0 {
934
935
936
937 return srcMap.irOperationSourceOffsetsInWasmBinary.Index(0)
938 }
939
940 if index == n || index == 0 {
941 return 0
942 } else {
943 return srcMap.irOperationSourceOffsetsInWasmBinary.Index(index - 1)
944 }
945 }
946
947 func NewEngine(_ context.Context, enabledFeatures api.CoreFeatures, fileCache filecache.Cache) wasm.Engine {
948 return newEngine(enabledFeatures, fileCache)
949 }
950
951 func newEngine(enabledFeatures api.CoreFeatures, fileCache filecache.Cache) *engine {
952 return &engine{
953 enabledFeatures: enabledFeatures,
954 codes: map[wasm.ModuleID]*compiledModule{},
955 setFinalizer: runtime.SetFinalizer,
956 fileCache: fileCache,
957 wazeroVersion: version.GetWazeroVersion(),
958 }
959 }
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988 var initialStackSize uint64 = 512
989
990 func (e *moduleEngine) newCallEngine(stackSize uint64, fn *function) *callEngine {
991 ce := &callEngine{
992 stack: make([]uint64, stackSize),
993 archContext: newArchContext(),
994 initialFn: fn,
995 moduleContext: moduleContext{fn: fn},
996 module: e.module,
997 }
998
999 stackHeader := (*reflect.SliceHeader)(unsafe.Pointer(&ce.stack))
1000 ce.stackContext = stackContext{
1001 stackElement0Address: stackHeader.Data,
1002 stackLenInBytes: uint64(stackHeader.Len) << 3,
1003 }
1004 return ce
1005 }
1006
1007 func (ce *callEngine) popValue() (ret uint64) {
1008 ce.stackContext.stackPointer--
1009 ret = ce.stack[ce.stackTopIndex()]
1010 return
1011 }
1012
1013 func (ce *callEngine) pushValue(v uint64) {
1014 ce.stack[ce.stackTopIndex()] = v
1015 ce.stackContext.stackPointer++
1016 }
1017
1018 func (ce *callEngine) stackTopIndex() uint64 {
1019 return ce.stackContext.stackPointer + (ce.stackContext.stackBasePointerInBytes >> 3)
1020 }
1021
1022 const (
1023 builtinFunctionIndexMemoryGrow wasm.Index = iota
1024 builtinFunctionIndexGrowStack
1025 builtinFunctionIndexTableGrow
1026 builtinFunctionIndexFunctionListenerBefore
1027 builtinFunctionIndexFunctionListenerAfter
1028 builtinFunctionIndexCheckExitCode
1029
1030 builtinFunctionIndexBreakPoint
1031 )
1032
1033 func (ce *callEngine) execWasmFunction(ctx context.Context, m *wasm.ModuleInstance) {
1034 codeAddr := ce.initialFn.codeInitialAddress
1035 modAddr := ce.initialFn.moduleInstance
1036
1037 entry:
1038 {
1039
1040 nativecall(codeAddr, ce, modAddr)
1041
1042
1043 switch status := ce.exitContext.statusCode; status {
1044 case nativeCallStatusCodeReturned:
1045 case nativeCallStatusCodeCallGoHostFunction:
1046 calleeHostFunction := ce.moduleContext.fn
1047 base := int(ce.stackBasePointerInBytes >> 3)
1048
1049
1050
1051
1052 stackLen := calleeHostFunction.funcType.ParamNumInUint64
1053 if resultLen := calleeHostFunction.funcType.ResultNumInUint64; resultLen > stackLen {
1054 stackLen = resultLen
1055 }
1056 stack := ce.stack[base : base+stackLen]
1057
1058 fn := calleeHostFunction.parent.goFunc
1059 switch fn := fn.(type) {
1060 case api.GoModuleFunction:
1061 fn.Call(ctx, ce.callerModuleInstance, stack)
1062 case api.GoFunction:
1063 fn.Call(ctx, stack)
1064 }
1065
1066 codeAddr, modAddr = ce.returnAddress, ce.moduleInstance
1067 goto entry
1068 case nativeCallStatusCodeCallBuiltInFunction:
1069 caller := ce.moduleContext.fn
1070 switch ce.exitContext.builtinFunctionCallIndex {
1071 case builtinFunctionIndexMemoryGrow:
1072 ce.builtinFunctionMemoryGrow(caller.moduleInstance.MemoryInstance)
1073 case builtinFunctionIndexGrowStack:
1074 ce.builtinFunctionGrowStack(caller.parent.stackPointerCeil)
1075 case builtinFunctionIndexTableGrow:
1076 ce.builtinFunctionTableGrow(caller.moduleInstance.Tables)
1077 case builtinFunctionIndexFunctionListenerBefore:
1078 ce.builtinFunctionFunctionListenerBefore(ctx, m, caller)
1079 case builtinFunctionIndexFunctionListenerAfter:
1080 ce.builtinFunctionFunctionListenerAfter(ctx, m, caller)
1081 case builtinFunctionIndexCheckExitCode:
1082
1083
1084
1085 if err := m.FailIfClosed(); err != nil {
1086 panic(err)
1087 }
1088 }
1089 if false {
1090 if ce.exitContext.builtinFunctionCallIndex == builtinFunctionIndexBreakPoint {
1091 runtime.Breakpoint()
1092 }
1093 }
1094
1095 codeAddr, modAddr = ce.returnAddress, ce.moduleInstance
1096 goto entry
1097 default:
1098 status.causePanic()
1099 }
1100 }
1101 }
1102
1103
1104
1105
1106
1107
1108
1109 var callStackCeiling = uint64(5000000)
1110
1111 func (ce *callEngine) builtinFunctionGrowStack(stackPointerCeil uint64) {
1112 oldLen := uint64(len(ce.stack))
1113 if callStackCeiling < oldLen {
1114 panic(wasmruntime.ErrRuntimeStackOverflow)
1115 }
1116
1117
1118 newLen := oldLen<<1 + (stackPointerCeil)
1119 newStack := make([]uint64, newLen)
1120 top := ce.stackTopIndex()
1121 copy(newStack[:top], ce.stack[:top])
1122 ce.stack = newStack
1123 stackHeader := (*reflect.SliceHeader)(unsafe.Pointer(&ce.stack))
1124 ce.stackContext.stackElement0Address = stackHeader.Data
1125 ce.stackContext.stackLenInBytes = newLen << 3
1126 }
1127
1128 func (ce *callEngine) builtinFunctionMemoryGrow(mem *wasm.MemoryInstance) {
1129 newPages := ce.popValue()
1130
1131 if res, ok := mem.Grow(uint32(newPages)); !ok {
1132 ce.pushValue(uint64(0xffffffff))
1133 } else {
1134 ce.pushValue(uint64(res))
1135 }
1136
1137
1138 bufSliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&mem.Buffer))
1139 ce.moduleContext.memorySliceLen = uint64(bufSliceHeader.Len)
1140 ce.moduleContext.memoryElement0Address = bufSliceHeader.Data
1141 }
1142
1143 func (ce *callEngine) builtinFunctionTableGrow(tables []*wasm.TableInstance) {
1144 tableIndex := uint32(ce.popValue())
1145 table := tables[tableIndex]
1146 num := ce.popValue()
1147 ref := ce.popValue()
1148 res := table.Grow(uint32(num), uintptr(ref))
1149 ce.pushValue(uint64(res))
1150 }
1151
1152
1153 type stackIterator struct {
1154 stack []uint64
1155 fn *function
1156 base int
1157 pc uint64
1158 started bool
1159 }
1160
1161 func (si *stackIterator) reset(stack []uint64, fn *function, base int, pc uint64) {
1162 si.stack = stack
1163 si.fn = fn
1164 si.base = base
1165 si.pc = pc
1166 si.started = false
1167 }
1168
1169 func (si *stackIterator) clear() {
1170 si.stack = nil
1171 si.fn = nil
1172 si.base = 0
1173 si.started = false
1174 }
1175
1176
1177 func (si *stackIterator) Next() bool {
1178 if !si.started {
1179 si.started = true
1180 return true
1181 }
1182
1183 if si.fn == nil || si.base == 0 {
1184 return false
1185 }
1186
1187 frame := si.base + callFrameOffset(si.fn.funcType)
1188 si.pc = si.stack[frame+0]
1189 si.base = int(si.stack[frame+1] >> 3)
1190
1191
1192 si.fn = *(**function)(unsafe.Pointer(&si.stack[frame+2]))
1193 return si.fn != nil
1194 }
1195
1196
1197 func (si *stackIterator) ProgramCounter() experimental.ProgramCounter {
1198 return experimental.ProgramCounter(si.pc)
1199 }
1200
1201
1202 func (si *stackIterator) Function() experimental.InternalFunction {
1203 return internalFunction{si.fn}
1204 }
1205
1206
1207 type internalFunction struct{ *function }
1208
1209
1210 func (f internalFunction) Definition() api.FunctionDefinition {
1211 return f.definition()
1212 }
1213
1214
1215 func (f internalFunction) SourceOffsetForPC(pc experimental.ProgramCounter) uint64 {
1216 p := f.parent
1217 if bitpack.OffsetArrayLen(p.sourceOffsetMap.irOperationSourceOffsetsInWasmBinary) == 0 {
1218 return 0
1219 }
1220 return f.getSourceOffsetInWasmBinary(uint64(pc))
1221 }
1222
1223 func (ce *callEngine) builtinFunctionFunctionListenerBefore(ctx context.Context, mod api.Module, fn *function) {
1224 base := int(ce.stackBasePointerInBytes >> 3)
1225 pc := uint64(ce.returnAddress)
1226 ce.stackIterator.reset(ce.stack, fn, base, pc)
1227
1228 params := ce.stack[base : base+fn.funcType.ParamNumInUint64]
1229 fn.parent.listener.Before(ctx, mod, fn.definition(), params, &ce.stackIterator)
1230
1231 ce.stackIterator.clear()
1232 }
1233
1234 func (ce *callEngine) builtinFunctionFunctionListenerAfter(ctx context.Context, mod api.Module, fn *function) {
1235 base := int(ce.stackBasePointerInBytes >> 3)
1236 fn.parent.listener.After(ctx, mod, fn.definition(), ce.stack[base:base+fn.funcType.ResultNumInUint64])
1237 }
1238
1239 func compileGoDefinedHostFunction(buf asm.Buffer, cmp compiler) error {
1240 if err := cmp.compileGoDefinedHostFunction(); err != nil {
1241 return err
1242 }
1243 _, err := cmp.compile(buf)
1244 return err
1245 }
1246
1247 type asmNodes struct {
1248 nodes []asm.Node
1249 }
1250
1251 type offsets struct {
1252 values []uint64
1253 }
1254
1255 func compileWasmFunction(buf asm.Buffer, cmp compiler, ir *wazeroir.CompilationResult, asmNodes *asmNodes, offsets *offsets) (spCeil uint64, sm sourceOffsetMap, err error) {
1256 if err = cmp.compilePreamble(); err != nil {
1257 err = fmt.Errorf("failed to emit preamble: %w", err)
1258 return
1259 }
1260
1261 needSourceOffsets := len(ir.IROperationSourceOffsetsInWasmBinary) > 0
1262 var irOpBegins []asm.Node
1263 if needSourceOffsets {
1264 irOpBegins = append(asmNodes.nodes[:0], make([]asm.Node, len(ir.Operations))...)
1265 defer func() { asmNodes.nodes = irOpBegins }()
1266 }
1267
1268 var skip bool
1269 for i := range ir.Operations {
1270 op := &ir.Operations[i]
1271 if needSourceOffsets {
1272
1273
1274
1275 irOpBegins[i] = cmp.compileNOP()
1276 }
1277
1278
1279
1280
1281 if op.Kind == wazeroir.OperationKindLabel {
1282 skip = cmp.compileLabel(op)
1283 }
1284 if skip {
1285 continue
1286 }
1287
1288 if false {
1289 fmt.Printf("compiling op=%s: %s\n", op.Kind, cmp)
1290 }
1291 switch op.Kind {
1292 case wazeroir.OperationKindUnreachable:
1293 err = cmp.compileUnreachable()
1294 case wazeroir.OperationKindLabel:
1295
1296 case wazeroir.OperationKindBr:
1297 err = cmp.compileBr(op)
1298 case wazeroir.OperationKindBrIf:
1299 err = cmp.compileBrIf(op)
1300 case wazeroir.OperationKindBrTable:
1301 err = cmp.compileBrTable(op)
1302 case wazeroir.OperationKindCall:
1303 err = cmp.compileCall(op)
1304 case wazeroir.OperationKindCallIndirect:
1305 err = cmp.compileCallIndirect(op)
1306 case wazeroir.OperationKindDrop:
1307 err = cmp.compileDrop(op)
1308 case wazeroir.OperationKindSelect:
1309 err = cmp.compileSelect(op)
1310 case wazeroir.OperationKindPick:
1311 err = cmp.compilePick(op)
1312 case wazeroir.OperationKindSet:
1313 err = cmp.compileSet(op)
1314 case wazeroir.OperationKindGlobalGet:
1315 err = cmp.compileGlobalGet(op)
1316 case wazeroir.OperationKindGlobalSet:
1317 err = cmp.compileGlobalSet(op)
1318 case wazeroir.OperationKindLoad:
1319 err = cmp.compileLoad(op)
1320 case wazeroir.OperationKindLoad8:
1321 err = cmp.compileLoad8(op)
1322 case wazeroir.OperationKindLoad16:
1323 err = cmp.compileLoad16(op)
1324 case wazeroir.OperationKindLoad32:
1325 err = cmp.compileLoad32(op)
1326 case wazeroir.OperationKindStore:
1327 err = cmp.compileStore(op)
1328 case wazeroir.OperationKindStore8:
1329 err = cmp.compileStore8(op)
1330 case wazeroir.OperationKindStore16:
1331 err = cmp.compileStore16(op)
1332 case wazeroir.OperationKindStore32:
1333 err = cmp.compileStore32(op)
1334 case wazeroir.OperationKindMemorySize:
1335 err = cmp.compileMemorySize()
1336 case wazeroir.OperationKindMemoryGrow:
1337 err = cmp.compileMemoryGrow()
1338 case wazeroir.OperationKindConstI32:
1339 err = cmp.compileConstI32(op)
1340 case wazeroir.OperationKindConstI64:
1341 err = cmp.compileConstI64(op)
1342 case wazeroir.OperationKindConstF32:
1343 err = cmp.compileConstF32(op)
1344 case wazeroir.OperationKindConstF64:
1345 err = cmp.compileConstF64(op)
1346 case wazeroir.OperationKindEq:
1347 err = cmp.compileEq(op)
1348 case wazeroir.OperationKindNe:
1349 err = cmp.compileNe(op)
1350 case wazeroir.OperationKindEqz:
1351 err = cmp.compileEqz(op)
1352 case wazeroir.OperationKindLt:
1353 err = cmp.compileLt(op)
1354 case wazeroir.OperationKindGt:
1355 err = cmp.compileGt(op)
1356 case wazeroir.OperationKindLe:
1357 err = cmp.compileLe(op)
1358 case wazeroir.OperationKindGe:
1359 err = cmp.compileGe(op)
1360 case wazeroir.OperationKindAdd:
1361 err = cmp.compileAdd(op)
1362 case wazeroir.OperationKindSub:
1363 err = cmp.compileSub(op)
1364 case wazeroir.OperationKindMul:
1365 err = cmp.compileMul(op)
1366 case wazeroir.OperationKindClz:
1367 err = cmp.compileClz(op)
1368 case wazeroir.OperationKindCtz:
1369 err = cmp.compileCtz(op)
1370 case wazeroir.OperationKindPopcnt:
1371 err = cmp.compilePopcnt(op)
1372 case wazeroir.OperationKindDiv:
1373 err = cmp.compileDiv(op)
1374 case wazeroir.OperationKindRem:
1375 err = cmp.compileRem(op)
1376 case wazeroir.OperationKindAnd:
1377 err = cmp.compileAnd(op)
1378 case wazeroir.OperationKindOr:
1379 err = cmp.compileOr(op)
1380 case wazeroir.OperationKindXor:
1381 err = cmp.compileXor(op)
1382 case wazeroir.OperationKindShl:
1383 err = cmp.compileShl(op)
1384 case wazeroir.OperationKindShr:
1385 err = cmp.compileShr(op)
1386 case wazeroir.OperationKindRotl:
1387 err = cmp.compileRotl(op)
1388 case wazeroir.OperationKindRotr:
1389 err = cmp.compileRotr(op)
1390 case wazeroir.OperationKindAbs:
1391 err = cmp.compileAbs(op)
1392 case wazeroir.OperationKindNeg:
1393 err = cmp.compileNeg(op)
1394 case wazeroir.OperationKindCeil:
1395 err = cmp.compileCeil(op)
1396 case wazeroir.OperationKindFloor:
1397 err = cmp.compileFloor(op)
1398 case wazeroir.OperationKindTrunc:
1399 err = cmp.compileTrunc(op)
1400 case wazeroir.OperationKindNearest:
1401 err = cmp.compileNearest(op)
1402 case wazeroir.OperationKindSqrt:
1403 err = cmp.compileSqrt(op)
1404 case wazeroir.OperationKindMin:
1405 err = cmp.compileMin(op)
1406 case wazeroir.OperationKindMax:
1407 err = cmp.compileMax(op)
1408 case wazeroir.OperationKindCopysign:
1409 err = cmp.compileCopysign(op)
1410 case wazeroir.OperationKindI32WrapFromI64:
1411 err = cmp.compileI32WrapFromI64()
1412 case wazeroir.OperationKindITruncFromF:
1413 err = cmp.compileITruncFromF(op)
1414 case wazeroir.OperationKindFConvertFromI:
1415 err = cmp.compileFConvertFromI(op)
1416 case wazeroir.OperationKindF32DemoteFromF64:
1417 err = cmp.compileF32DemoteFromF64()
1418 case wazeroir.OperationKindF64PromoteFromF32:
1419 err = cmp.compileF64PromoteFromF32()
1420 case wazeroir.OperationKindI32ReinterpretFromF32:
1421 err = cmp.compileI32ReinterpretFromF32()
1422 case wazeroir.OperationKindI64ReinterpretFromF64:
1423 err = cmp.compileI64ReinterpretFromF64()
1424 case wazeroir.OperationKindF32ReinterpretFromI32:
1425 err = cmp.compileF32ReinterpretFromI32()
1426 case wazeroir.OperationKindF64ReinterpretFromI64:
1427 err = cmp.compileF64ReinterpretFromI64()
1428 case wazeroir.OperationKindExtend:
1429 err = cmp.compileExtend(op)
1430 case wazeroir.OperationKindSignExtend32From8:
1431 err = cmp.compileSignExtend32From8()
1432 case wazeroir.OperationKindSignExtend32From16:
1433 err = cmp.compileSignExtend32From16()
1434 case wazeroir.OperationKindSignExtend64From8:
1435 err = cmp.compileSignExtend64From8()
1436 case wazeroir.OperationKindSignExtend64From16:
1437 err = cmp.compileSignExtend64From16()
1438 case wazeroir.OperationKindSignExtend64From32:
1439 err = cmp.compileSignExtend64From32()
1440 case wazeroir.OperationKindMemoryInit:
1441 err = cmp.compileMemoryInit(op)
1442 case wazeroir.OperationKindDataDrop:
1443 err = cmp.compileDataDrop(op)
1444 case wazeroir.OperationKindMemoryCopy:
1445 err = cmp.compileMemoryCopy()
1446 case wazeroir.OperationKindMemoryFill:
1447 err = cmp.compileMemoryFill()
1448 case wazeroir.OperationKindTableInit:
1449 err = cmp.compileTableInit(op)
1450 case wazeroir.OperationKindElemDrop:
1451 err = cmp.compileElemDrop(op)
1452 case wazeroir.OperationKindTableCopy:
1453 err = cmp.compileTableCopy(op)
1454 case wazeroir.OperationKindRefFunc:
1455 err = cmp.compileRefFunc(op)
1456 case wazeroir.OperationKindTableGet:
1457 err = cmp.compileTableGet(op)
1458 case wazeroir.OperationKindTableSet:
1459 err = cmp.compileTableSet(op)
1460 case wazeroir.OperationKindTableGrow:
1461 err = cmp.compileTableGrow(op)
1462 case wazeroir.OperationKindTableSize:
1463 err = cmp.compileTableSize(op)
1464 case wazeroir.OperationKindTableFill:
1465 err = cmp.compileTableFill(op)
1466 case wazeroir.OperationKindV128Const:
1467 err = cmp.compileV128Const(op)
1468 case wazeroir.OperationKindV128Add:
1469 err = cmp.compileV128Add(op)
1470 case wazeroir.OperationKindV128Sub:
1471 err = cmp.compileV128Sub(op)
1472 case wazeroir.OperationKindV128Load:
1473 err = cmp.compileV128Load(op)
1474 case wazeroir.OperationKindV128LoadLane:
1475 err = cmp.compileV128LoadLane(op)
1476 case wazeroir.OperationKindV128Store:
1477 err = cmp.compileV128Store(op)
1478 case wazeroir.OperationKindV128StoreLane:
1479 err = cmp.compileV128StoreLane(op)
1480 case wazeroir.OperationKindV128ExtractLane:
1481 err = cmp.compileV128ExtractLane(op)
1482 case wazeroir.OperationKindV128ReplaceLane:
1483 err = cmp.compileV128ReplaceLane(op)
1484 case wazeroir.OperationKindV128Splat:
1485 err = cmp.compileV128Splat(op)
1486 case wazeroir.OperationKindV128Shuffle:
1487 err = cmp.compileV128Shuffle(op)
1488 case wazeroir.OperationKindV128Swizzle:
1489 err = cmp.compileV128Swizzle(op)
1490 case wazeroir.OperationKindV128AnyTrue:
1491 err = cmp.compileV128AnyTrue(op)
1492 case wazeroir.OperationKindV128AllTrue:
1493 err = cmp.compileV128AllTrue(op)
1494 case wazeroir.OperationKindV128BitMask:
1495 err = cmp.compileV128BitMask(op)
1496 case wazeroir.OperationKindV128And:
1497 err = cmp.compileV128And(op)
1498 case wazeroir.OperationKindV128Not:
1499 err = cmp.compileV128Not(op)
1500 case wazeroir.OperationKindV128Or:
1501 err = cmp.compileV128Or(op)
1502 case wazeroir.OperationKindV128Xor:
1503 err = cmp.compileV128Xor(op)
1504 case wazeroir.OperationKindV128Bitselect:
1505 err = cmp.compileV128Bitselect(op)
1506 case wazeroir.OperationKindV128AndNot:
1507 err = cmp.compileV128AndNot(op)
1508 case wazeroir.OperationKindV128Shl:
1509 err = cmp.compileV128Shl(op)
1510 case wazeroir.OperationKindV128Shr:
1511 err = cmp.compileV128Shr(op)
1512 case wazeroir.OperationKindV128Cmp:
1513 err = cmp.compileV128Cmp(op)
1514 case wazeroir.OperationKindV128AddSat:
1515 err = cmp.compileV128AddSat(op)
1516 case wazeroir.OperationKindV128SubSat:
1517 err = cmp.compileV128SubSat(op)
1518 case wazeroir.OperationKindV128Mul:
1519 err = cmp.compileV128Mul(op)
1520 case wazeroir.OperationKindV128Div:
1521 err = cmp.compileV128Div(op)
1522 case wazeroir.OperationKindV128Neg:
1523 err = cmp.compileV128Neg(op)
1524 case wazeroir.OperationKindV128Sqrt:
1525 err = cmp.compileV128Sqrt(op)
1526 case wazeroir.OperationKindV128Abs:
1527 err = cmp.compileV128Abs(op)
1528 case wazeroir.OperationKindV128Popcnt:
1529 err = cmp.compileV128Popcnt(op)
1530 case wazeroir.OperationKindV128Min:
1531 err = cmp.compileV128Min(op)
1532 case wazeroir.OperationKindV128Max:
1533 err = cmp.compileV128Max(op)
1534 case wazeroir.OperationKindV128AvgrU:
1535 err = cmp.compileV128AvgrU(op)
1536 case wazeroir.OperationKindV128Pmin:
1537 err = cmp.compileV128Pmin(op)
1538 case wazeroir.OperationKindV128Pmax:
1539 err = cmp.compileV128Pmax(op)
1540 case wazeroir.OperationKindV128Ceil:
1541 err = cmp.compileV128Ceil(op)
1542 case wazeroir.OperationKindV128Floor:
1543 err = cmp.compileV128Floor(op)
1544 case wazeroir.OperationKindV128Trunc:
1545 err = cmp.compileV128Trunc(op)
1546 case wazeroir.OperationKindV128Nearest:
1547 err = cmp.compileV128Nearest(op)
1548 case wazeroir.OperationKindV128Extend:
1549 err = cmp.compileV128Extend(op)
1550 case wazeroir.OperationKindV128ExtMul:
1551 err = cmp.compileV128ExtMul(op)
1552 case wazeroir.OperationKindV128Q15mulrSatS:
1553 err = cmp.compileV128Q15mulrSatS(op)
1554 case wazeroir.OperationKindV128ExtAddPairwise:
1555 err = cmp.compileV128ExtAddPairwise(op)
1556 case wazeroir.OperationKindV128FloatPromote:
1557 err = cmp.compileV128FloatPromote(op)
1558 case wazeroir.OperationKindV128FloatDemote:
1559 err = cmp.compileV128FloatDemote(op)
1560 case wazeroir.OperationKindV128FConvertFromI:
1561 err = cmp.compileV128FConvertFromI(op)
1562 case wazeroir.OperationKindV128Dot:
1563 err = cmp.compileV128Dot(op)
1564 case wazeroir.OperationKindV128Narrow:
1565 err = cmp.compileV128Narrow(op)
1566 case wazeroir.OperationKindV128ITruncSatFromF:
1567 err = cmp.compileV128ITruncSatFromF(op)
1568 case wazeroir.OperationKindBuiltinFunctionCheckExitCode:
1569 err = cmp.compileBuiltinFunctionCheckExitCode()
1570 default:
1571 err = errors.New("unsupported")
1572 }
1573 if err != nil {
1574 err = fmt.Errorf("operation %s: %w", op.Kind.String(), err)
1575 return
1576 }
1577 }
1578
1579 spCeil, err = cmp.compile(buf)
1580 if err != nil {
1581 err = fmt.Errorf("failed to compile: %w", err)
1582 return
1583 }
1584
1585 if needSourceOffsets {
1586 offsetInNativeBin := append(offsets.values[:0], make([]uint64, len(irOpBegins))...)
1587 offsets.values = offsetInNativeBin
1588 for i, nop := range irOpBegins {
1589 offsetInNativeBin[i] = nop.OffsetInBinary()
1590 }
1591 sm.irOperationOffsetsInNativeBinary = bitpack.NewOffsetArray(offsetInNativeBin)
1592 sm.irOperationSourceOffsetsInWasmBinary = bitpack.NewOffsetArray(ir.IROperationSourceOffsetsInWasmBinary)
1593 }
1594 return
1595 }
1596
View as plain text