-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmemory.go
120 lines (95 loc) · 2.81 KB
/
memory.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
package fastlike
import (
"bytes"
"encoding/binary"
"github.com/bytecodealliance/wasmtime-go"
)
// MemorySlice represents an underlying slice of memory from a wasm program.
// An implementation of MemorySlice is most often wrapped with a Memory, which provides convenience
// functions to read and write different values.
type MemorySlice interface {
Data() []byte
Len() int
Cap() int
}
// ByteMemory is a MemorySlice mostly used for tests, where you want to be able to write directly into
// the memory slice and read it out
type ByteMemory []byte
// Data returns the underlying byte slice
func (m ByteMemory) Data() []byte {
return m
}
// Len is the current length of the memory slice
func (m ByteMemory) Len() int {
return len(m)
}
// Cap is the total capacity of the memory slice
func (m ByteMemory) Cap() int {
return cap(m)
}
// wasmMemory is a MemorySlice implementation that wraps a wasmtime.Memory
type wasmMemory struct {
mem *wasmtime.Memory
slice []byte
}
func (m *wasmMemory) Len() int {
return len(m.Data())
}
func (m *wasmMemory) Cap() int {
return cap(m.Data())
}
func (m *wasmMemory) Data() []byte {
// If we have a pre-built slice and that slice capacity is the same as the current data size,
// return it. Otherwise, rebuild the slice.
if m.slice != nil && cap(m.slice) == int(m.mem.DataSize()) {
return m.slice
}
m.slice = m.mem.UnsafeData()
return m.slice
}
// Memory is a wrapper around a MemorySlice that adds convenience functions for reading and writing
type Memory struct {
MemorySlice
}
func (m *Memory) ReadUint8(offset int64) uint8 {
return m.Data()[offset]
}
func (m *Memory) Uint16(offset int64) uint16 {
return binary.LittleEndian.Uint16(m.Data()[offset:])
}
func (m *Memory) Uint32(offset int64) uint32 {
return binary.LittleEndian.Uint32(m.Data()[offset:])
}
func (m *Memory) Uint64(offset int64) uint64 {
return binary.LittleEndian.Uint64(m.Data()[offset:])
}
func (m *Memory) PutUint8(v uint8, offset int64) {
m.Data()[offset] = v
}
func (m *Memory) PutUint16(v uint16, offset int64) {
binary.LittleEndian.PutUint16(m.Data()[offset:], v)
}
func (m *Memory) PutUint32(v uint32, offset int64) {
binary.LittleEndian.PutUint32(m.Data()[offset:], v)
}
func (m *Memory) PutInt32(v int32, offset int64) {
var b = new(bytes.Buffer)
binary.Write(b, binary.LittleEndian, v)
m.WriteAt(b.Bytes(), offset)
}
func (m *Memory) PutInt64(v int64, offset int64) {
var b = new(bytes.Buffer)
binary.Write(b, binary.LittleEndian, v)
m.WriteAt(b.Bytes(), offset)
}
func (m *Memory) PutUint64(v uint64, offset int64) {
binary.LittleEndian.PutUint64(m.Data()[offset:], v)
}
func (m *Memory) ReadAt(p []byte, offset int64) (int, error) {
n := copy(p, m.Data()[offset:])
return n, nil
}
func (m *Memory) WriteAt(p []byte, offset int64) (int, error) {
n := copy(m.Data()[offset:], p)
return n, nil
}