1
2
3 package goarch
4
5 import (
6 "context"
7 "encoding/binary"
8
9 "github.com/tetratelabs/wazero/api"
10 "github.com/tetratelabs/wazero/internal/gojs/custom"
11 "github.com/tetratelabs/wazero/internal/gojs/util"
12 "github.com/tetratelabs/wazero/internal/wasm"
13 )
14
15
16
17 func StubFunction(name string) *wasm.HostFunc {
18 return &wasm.HostFunc{
19 ExportName: name,
20 Name: name,
21 ParamTypes: []wasm.ValueType{wasm.ValueTypeI32},
22 ParamNames: []string{"sp"},
23 Code: wasm.Code{GoFunc: api.GoModuleFunc(func(ctx context.Context, _ api.Module, stack []uint64) {})},
24 }
25 }
26
27 var le = binary.LittleEndian
28
29 type Stack interface {
30
31 Name() string
32
33 Param(i int) uint64
34
35
36
37 ParamBytes(mem api.Memory, i int) []byte
38
39
40
41 ParamString(mem api.Memory, i int) string
42
43 ParamInt32(i int) int32
44
45 ParamUint32(i int) uint32
46
47
48
49
50
51 Refresh(api.Module)
52
53 SetResult(i int, v uint64)
54
55 SetResultBool(i int, v bool)
56
57 SetResultI32(i int, v int32)
58
59 SetResultI64(i int, v int64)
60
61 SetResultUint32(i int, v uint32)
62 }
63
64 func NewStack(name string, mem api.Memory, sp uint32) Stack {
65 names := custom.NameSection[name]
66 s := &stack{name: name, paramCount: len(names.ParamNames), resultCount: len(names.ResultNames)}
67 s.refresh(mem, sp)
68 return s
69 }
70
71 type stack struct {
72 name string
73 paramCount, resultCount int
74 buf []byte
75 }
76
77
78 func (s *stack) Name() string {
79 return s.name
80 }
81
82
83 func (s *stack) Param(i int) (res uint64) {
84 pos := i << 3
85 res = le.Uint64(s.buf[pos:])
86 return
87 }
88
89
90 func (s *stack) ParamBytes(mem api.Memory, i int) (res []byte) {
91 offset := s.ParamUint32(i)
92 byteCount := s.ParamUint32(i + 1)
93 return util.MustRead(mem, s.name, i, offset, byteCount)
94 }
95
96
97 func (s *stack) ParamString(mem api.Memory, i int) string {
98 return string(s.ParamBytes(mem, i))
99 }
100
101
102 func (s *stack) ParamInt32(i int) int32 {
103 return int32(s.Param(i))
104 }
105
106
107 func (s *stack) ParamUint32(i int) uint32 {
108 return uint32(s.Param(i))
109 }
110
111
112 func (s *stack) Refresh(mod api.Module) {
113 s.refresh(mod.Memory(), GetSP(mod))
114 }
115
116 func (s *stack) refresh(mem api.Memory, sp uint32) {
117 count := uint32(s.paramCount + s.resultCount)
118 buf, ok := mem.Read(sp+8, count<<3)
119 if !ok {
120 panic("out of memory reading stack")
121 }
122 s.buf = buf
123 }
124
125
126 func (s *stack) SetResult(i int, v uint64) {
127 pos := (s.paramCount + i) << 3
128 le.PutUint64(s.buf[pos:], v)
129 }
130
131
132 func (s *stack) SetResultBool(i int, v bool) {
133 if v {
134 s.SetResultUint32(i, 1)
135 } else {
136 s.SetResultUint32(i, 0)
137 }
138 }
139
140
141 func (s *stack) SetResultI32(i int, v int32) {
142 s.SetResult(i, uint64(v))
143 }
144
145
146 func (s *stack) SetResultI64(i int, v int64) {
147 s.SetResult(i, uint64(v))
148 }
149
150
151 func (s *stack) SetResultUint32(i int, v uint32) {
152 s.SetResult(i, uint64(v))
153 }
154
155
156
157
158
159 func GetSP(mod api.Module) uint32 {
160
161
162 return uint32(mod.(*wasm.ModuleInstance).GlobalVal(0))
163 }
164
165 func NewFunc(name string, goFunc Func) *wasm.HostFunc {
166 return util.NewFunc(name, (&stackFunc{name: name, f: goFunc}).Call)
167 }
168
169 type Func func(context.Context, api.Module, Stack)
170
171 type stackFunc struct {
172 name string
173 f Func
174 }
175
176
177 func (f *stackFunc) Call(ctx context.Context, mod api.Module, wasmStack []uint64) {
178 s := NewStack(f.name, mod.Memory(), uint32(wasmStack[0]))
179 f.f(ctx, mod, s)
180 }
181
View as plain text