1 package wasm
2
3 import (
4 "encoding/binary"
5 "fmt"
6 "math"
7 "reflect"
8 "unsafe"
9
10 "github.com/tetratelabs/wazero/api"
11 "github.com/tetratelabs/wazero/internal/internalapi"
12 )
13
14 const (
15
16
17
18 MemoryPageSize = uint32(65536)
19
20
21 MemoryLimitPages = uint32(65536)
22
23 MemoryPageSizeInBits = 16
24 )
25
26
27 var _ api.Memory = &MemoryInstance{}
28
29
30
31
32
33
34 type MemoryInstance struct {
35 internalapi.WazeroOnlyType
36
37 Buffer []byte
38 Min, Cap, Max uint32
39
40 definition api.MemoryDefinition
41 }
42
43
44 func NewMemoryInstance(memSec *Memory) *MemoryInstance {
45 min := MemoryPagesToBytesNum(memSec.Min)
46 capacity := MemoryPagesToBytesNum(memSec.Cap)
47 return &MemoryInstance{
48 Buffer: make([]byte, min, capacity),
49 Min: memSec.Min,
50 Cap: memSec.Cap,
51 Max: memSec.Max,
52 }
53 }
54
55
56 func (m *MemoryInstance) Definition() api.MemoryDefinition {
57 return m.definition
58 }
59
60
61 func (m *MemoryInstance) Size() uint32 {
62 return m.size()
63 }
64
65
66 func (m *MemoryInstance) ReadByte(offset uint32) (byte, bool) {
67 if offset >= m.size() {
68 return 0, false
69 }
70 return m.Buffer[offset], true
71 }
72
73
74 func (m *MemoryInstance) ReadUint16Le(offset uint32) (uint16, bool) {
75 if !m.hasSize(offset, 2) {
76 return 0, false
77 }
78 return binary.LittleEndian.Uint16(m.Buffer[offset : offset+2]), true
79 }
80
81
82 func (m *MemoryInstance) ReadUint32Le(offset uint32) (uint32, bool) {
83 return m.readUint32Le(offset)
84 }
85
86
87 func (m *MemoryInstance) ReadFloat32Le(offset uint32) (float32, bool) {
88 v, ok := m.readUint32Le(offset)
89 if !ok {
90 return 0, false
91 }
92 return math.Float32frombits(v), true
93 }
94
95
96 func (m *MemoryInstance) ReadUint64Le(offset uint32) (uint64, bool) {
97 return m.readUint64Le(offset)
98 }
99
100
101 func (m *MemoryInstance) ReadFloat64Le(offset uint32) (float64, bool) {
102 v, ok := m.readUint64Le(offset)
103 if !ok {
104 return 0, false
105 }
106 return math.Float64frombits(v), true
107 }
108
109
110 func (m *MemoryInstance) Read(offset, byteCount uint32) ([]byte, bool) {
111 if !m.hasSize(offset, uint64(byteCount)) {
112 return nil, false
113 }
114 return m.Buffer[offset : offset+byteCount : offset+byteCount], true
115 }
116
117
118 func (m *MemoryInstance) WriteByte(offset uint32, v byte) bool {
119 if offset >= m.size() {
120 return false
121 }
122 m.Buffer[offset] = v
123 return true
124 }
125
126
127 func (m *MemoryInstance) WriteUint16Le(offset uint32, v uint16) bool {
128 if !m.hasSize(offset, 2) {
129 return false
130 }
131 binary.LittleEndian.PutUint16(m.Buffer[offset:], v)
132 return true
133 }
134
135
136 func (m *MemoryInstance) WriteUint32Le(offset, v uint32) bool {
137 return m.writeUint32Le(offset, v)
138 }
139
140
141 func (m *MemoryInstance) WriteFloat32Le(offset uint32, v float32) bool {
142 return m.writeUint32Le(offset, math.Float32bits(v))
143 }
144
145
146 func (m *MemoryInstance) WriteUint64Le(offset uint32, v uint64) bool {
147 return m.writeUint64Le(offset, v)
148 }
149
150
151 func (m *MemoryInstance) WriteFloat64Le(offset uint32, v float64) bool {
152 return m.writeUint64Le(offset, math.Float64bits(v))
153 }
154
155
156 func (m *MemoryInstance) Write(offset uint32, val []byte) bool {
157 if !m.hasSize(offset, uint64(len(val))) {
158 return false
159 }
160 copy(m.Buffer[offset:], val)
161 return true
162 }
163
164
165 func (m *MemoryInstance) WriteString(offset uint32, val string) bool {
166 if !m.hasSize(offset, uint64(len(val))) {
167 return false
168 }
169 copy(m.Buffer[offset:], val)
170 return true
171 }
172
173
174 func MemoryPagesToBytesNum(pages uint32) (bytesNum uint64) {
175 return uint64(pages) << MemoryPageSizeInBits
176 }
177
178
179 func (m *MemoryInstance) Grow(delta uint32) (result uint32, ok bool) {
180 currentPages := memoryBytesNumToPages(uint64(len(m.Buffer)))
181 if delta == 0 {
182 return currentPages, true
183 }
184
185
186 newPages := currentPages + delta
187 if newPages > m.Max {
188 return 0, false
189 } else if newPages > m.Cap {
190 m.Buffer = append(m.Buffer, make([]byte, MemoryPagesToBytesNum(delta))...)
191 m.Cap = newPages
192 return currentPages, true
193 } else {
194 sp := (*reflect.SliceHeader)(unsafe.Pointer(&m.Buffer))
195 sp.Len = int(MemoryPagesToBytesNum(newPages))
196 return currentPages, true
197 }
198 }
199
200
201 func (m *MemoryInstance) PageSize() (result uint32) {
202 return memoryBytesNumToPages(uint64(len(m.Buffer)))
203 }
204
205
206
207
208 func PagesToUnitOfBytes(pages uint32) string {
209 k := pages * 64
210 if k < 1024 {
211 return fmt.Sprintf("%d Ki", k)
212 }
213 m := k / 1024
214 if m < 1024 {
215 return fmt.Sprintf("%d Mi", m)
216 }
217 g := m / 1024
218 if g < 1024 {
219 return fmt.Sprintf("%d Gi", g)
220 }
221 return fmt.Sprintf("%d Ti", g/1024)
222 }
223
224
225
226
227 func memoryBytesNumToPages(bytesNum uint64) (pages uint32) {
228 return uint32(bytesNum >> MemoryPageSizeInBits)
229 }
230
231
232 func (m *MemoryInstance) size() uint32 {
233 return uint32(len(m.Buffer))
234 }
235
236
237
238
239 func (m *MemoryInstance) hasSize(offset uint32, byteCount uint64) bool {
240 return uint64(offset)+byteCount <= uint64(len(m.Buffer))
241 }
242
243
244
245 func (m *MemoryInstance) readUint32Le(offset uint32) (uint32, bool) {
246 if !m.hasSize(offset, 4) {
247 return 0, false
248 }
249 return binary.LittleEndian.Uint32(m.Buffer[offset : offset+4]), true
250 }
251
252
253
254 func (m *MemoryInstance) readUint64Le(offset uint32) (uint64, bool) {
255 if !m.hasSize(offset, 8) {
256 return 0, false
257 }
258 return binary.LittleEndian.Uint64(m.Buffer[offset : offset+8]), true
259 }
260
261
262
263 func (m *MemoryInstance) writeUint32Le(offset uint32, v uint32) bool {
264 if !m.hasSize(offset, 4) {
265 return false
266 }
267 binary.LittleEndian.PutUint32(m.Buffer[offset:], v)
268 return true
269 }
270
271
272
273 func (m *MemoryInstance) writeUint64Le(offset uint32, v uint64) bool {
274 if !m.hasSize(offset, 8) {
275 return false
276 }
277 binary.LittleEndian.PutUint64(m.Buffer[offset:], v)
278 return true
279 }
280
View as plain text