-
Notifications
You must be signed in to change notification settings - Fork 2
/
store.go
234 lines (188 loc) · 5.33 KB
/
store.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
package wypes
import (
"context"
)
type Raw = uint64
type Addr = uint32
type ValueType = byte
const (
// ValueTypeI32 is a 32-bit integer.
ValueTypeI32 ValueType = 0x7f
// ValueTypeI64 is a 64-bit integer.
ValueTypeI64 ValueType = 0x7e
// ValueTypeF32 is a 32-bit floating point number.
ValueTypeF32 ValueType = 0x7d
// ValueTypeF64 is a 64-bit floating point number.
ValueTypeF64 ValueType = 0x7c
// ValueTypeExternref is an externref type.
//
// Not supported by many guests including TinyGo, so we don't use it.
// https://github.com/tinygo-org/tinygo/issues/2702
ValueTypeExternref ValueType = 0x6f
)
// Store provides access for host-defined functions to the runtime data.
//
// Store itself implements [Lift] and so can be used as a host-defined function argument.
type Store struct {
// Stack is where [Lift] takes the values from and [Lower] puts values to.
Stack Stack
// Memory is used by [Lift] and [Lower] of memory-based types,
// like [Bytes] and [String].
Memory Memory
// Refs is used by [HostRef] to pass through the gues module references
// to complex objects in the host environment that cannot be lowered into wasm.
Refs Refs
// Context can be retrieved by the [Context] type.
Context context.Context
// Error holds the latest error that happened during [Lift] or [Lower].
Error error
}
// ValueTypes implements [Value] interface.
func (*Store) ValueTypes() []ValueType {
return []ValueType{}
}
// Lift implements [Lift] interface.
func (*Store) Lift(s *Store) *Store {
return s
}
// Memory provides access to the linear memory of the wasm runtime.
//
// The interface is compatible with wazero memory.
type Memory interface {
// Read is used to [Lift] values of memory-backed types, like [Bytes] and [String].
Read(offset Addr, count uint32) ([]byte, bool)
// Read is used to [Lower] values of memory-backed types, like [Bytes] and [String].
Write(offset Addr, v []byte) bool
}
// Wraps a slice of bytes to be used as [Memory].
type SliceMemory []byte
// Create new memory instance that internally stores data in a slice.
func NewSliceMemory(size int) *SliceMemory {
s := make(SliceMemory, size)
return &s
}
// Read implements the [Memory] interface.
func (m *SliceMemory) Read(offset Addr, count uint32) ([]byte, bool) {
if !m.hasSize(offset, uint64(count)) {
return nil, false
}
return (*m)[offset : offset+count : offset+count], true
}
// Write implements the [Memory] interface.
func (m *SliceMemory) Write(offset Addr, v []byte) bool {
if !m.hasSize(offset, uint64(len(v))) {
return false
}
copy((*m)[offset:], v)
return true
}
// hasSize returns true if Len is sufficient for byteCount at the given offset.
func (m *SliceMemory) hasSize(offset uint32, byteCount uint64) bool {
return uint64(offset)+byteCount <= uint64(len(*m)) // uint64 prevents overflow on add
}
func (s *SliceMemory) Len() int {
return len(*s)
}
// Refs holds references to Go values that you want to reference from wasm using [HostRef].
type Refs interface {
Get(idx uint32, def any) (any, bool)
Set(idx uint32, val any)
Put(val any) uint32
Drop(idx uint32)
}
// MapRefs is a simple [Refs] implementation powered by a map.
//
// Must be constructed with [NewMapRefs].
type MapRefs struct {
Raw map[uint32]any
idx uint32
}
func NewMapRefs() MapRefs {
return MapRefs{Raw: make(map[uint32]any)}
}
func (r MapRefs) Get(idx uint32, def any) (any, bool) {
val, found := r.Raw[idx]
if !found {
return def, false
}
return val, true
}
func (r MapRefs) Set(idx uint32, val any) {
r.Raw[idx] = val
}
func (r MapRefs) Put(val any) uint32 {
r.idx += 1
// skip already used cells
_, used := r.Raw[r.idx]
for used {
r.idx += 1
_, used = r.Raw[r.idx]
}
r.Raw[r.idx] = val
return r.idx
}
func (r MapRefs) Drop(idx uint32) {
delete(r.Raw, idx)
}
type Stack interface {
Push(Raw)
Pop() Raw
}
// SliceStack adapts a slice of raw values into a [Stack].
type SliceStack []uint64
func NewSliceStack(cap int) *SliceStack {
s := make(SliceStack, 0, cap)
return &s
}
func (s *SliceStack) Push(v uint64) {
*s = append(*s, v)
}
func (s *SliceStack) Pop() uint64 {
idx := len(*s) - 1
v := (*s)[idx]
*s = (*s)[:idx]
return v
}
func (s *SliceStack) Len() int {
return len(*s)
}
// Value is an interface implemented by all the types in wypes.
type Value interface {
ValueTypes() []ValueType
}
// Lift reads values from [Store] into a native Go value.
type Lift[T any] interface {
Value
Lift(*Store) T
}
// Lower writes a native Go value into the [Store].
type Lower interface {
Value
Lower(*Store)
}
// LiftLower is a type that implements both [Lift] and [Lower].
type LiftLower[T any] interface {
Lift[T]
Lower
}
// MemoryLift reads values from [Store.Memory] into a native Go value.
type MemoryLift[T any] interface {
MemoryLift(*Store, Addr) (T, uint32)
}
// MemoryLower writes a native Go value into the [Store.Memory].
type MemoryLower[T any] interface {
MemoryLower(*Store, Addr) uint32
}
// MemoryLiftLower is a type that implements both [MemoryLift] and [MemoryLower].
type MemoryLiftLower[T any] interface {
MemoryLift[T]
MemoryLower[T]
}
// Modules is a collection of host-defined modules.
//
// It maps module names to the module definitions.
type Modules map[string]Module
// Module is a collection of host-defined functions in a module with the same name.
//
// It maps function names to function definitions.
type Module map[string]HostFunc