-
Notifications
You must be signed in to change notification settings - Fork 43
/
Copy pathMemory.v3
186 lines (178 loc) · 7.54 KB
/
Memory.v3
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
// Copyright 2020 Ben L. Titzer. All rights reserved.
// See LICENSE for details of Apache 2.0 license.
// An instantiated Wasm memory.
def OOB_RANGE = MaybeTrap<Range<byte>>(null, TrapReason.MEM_OUT_OF_BOUNDS);
class Memory(decl: MemoryDecl) extends Exportable {
def var index_tag: byte = if(decl != null && decl.size.is64, BpTypeCode.I64.code, BpTypeCode.I32.code);
def var num_pages: u64; // size in pages
def var num_bytes: u64; // length in bytes
var oom = false; // set if allocation fails due to out-of-memory
// Get a range of memory from [offset ..+ size], if possible (32-bit)
def range_ol_32(index: u32, size: u32) -> MaybeTrap<Range<byte>> {
var pos = u64.!(index);
var end = pos + u64.!(size);
if (end > num_bytes) return OOB_RANGE;
return MaybeTrap(getReadWriteAlias64(pos, end), TrapReason.NONE);
}
// Get a null-terminated range which is a subrange of [offset += max], if possible (32-bit)
def range_o_32z(index: u32, max: u32) -> MaybeTrap<Range<byte>> {
if (index >= num_bytes) return OOB_RANGE;
var pos = u64.!(index);
var end = pos + u64.!(max);
if (end > num_bytes) end = num_bytes;
var data = getReadWriteAlias64(pos, end);
for (i < max) {
if (data[i] == 0) return MaybeTrap(data[0 ... i], TrapReason.NONE);
}
return OOB_RANGE;
}
// Get a range of memory from [offset ..+ size], if possible (64-bit)
def range_ol_64(offset: u64, size: u64) -> MaybeTrap<Range<byte>> {
if (offset > num_bytes) return OOB_RANGE;
if (size > num_bytes) return OOB_RANGE;
var end = offset + size;
if (end > num_bytes) return OOB_RANGE;
return MaybeTrap(getReadWriteAlias64(offset, end), TrapReason.NONE);
}
// Get a range of memory from [(offset + index) ..+ size], if possible (32-bit)
def range_oil_32(offset: u32, index: u32, size: u32) -> MaybeTrap<Range<byte>> {
var pos = u64.!(offset) + u64.!(index);
var end = pos + u64.!(size);
if (end > num_bytes) return OOB_RANGE;
return MaybeTrap(getReadWriteAlias64(pos, end), TrapReason.NONE);
}
// Get a range of memory from [(offset + index) ..+ size], if possible (64-bit)
def range_oil_64(offset: u64, index: u64, size: u64) -> MaybeTrap<Range<byte>> {
if (offset > num_bytes) return OOB_RANGE;
if (index > num_bytes) return OOB_RANGE;
if (size > num_bytes) return OOB_RANGE;
var pos = offset + index;
var end = pos + size;
if (end > num_bytes) return OOB_RANGE;
return MaybeTrap(getReadWriteAlias64(pos, end), TrapReason.NONE);
}
// Fill in the range [dest ..+ size] with {val}.
def fill(dest: u64, val: u8, size: u64) -> TrapReason {
var r = range_ol_64(dest, size);
if (!r.ok()) return r.reason;
for (i < size) r.result[i] = val; // XXX: use word copy
return TrapReason.NONE;
}
// Memory copy.
def copyM(dst_offset: u64, src: Memory, src_offset: u64, size: u64) -> TrapReason {
var dst = this.range_ol_64(dst_offset, size);
if (!dst.ok()) return dst.reason;
var src = src.range_ol_64(src_offset, size);
if (!src.ok()) return src.reason;
if (src_offset > dst_offset) Target.fastFwCopy(dst.result, src.result);
else for (i = size - 1; i < size; i--) dst.result[i] = src.result[i]; // backwards copy
return TrapReason.NONE;
}
def copyIn(dst_offset: u64, src: Array<byte>, src_offset: u64, size: u64) -> TrapReason {
var dst = this.range_ol_64(dst_offset, size);
if (!dst.ok()) return dst.reason;
var j = ArrayUtil.boundsCheck(src, src_offset, size);
if (j < 0) return TrapReason.MEM_OUT_OF_BOUNDS;
var src_range = src[src_offset ..+ size];
Target.fastFwCopy(dst.result, src_range);
return TrapReason.NONE;
}
def readIn(fd: int, dst_offset: u32, size: u32) -> int {
var dst = range_ol_32(dst_offset, size);
if (!dst.ok()) return -1;
return System.read(fd, dst.result);
}
def writeOut(fd: int, src_offset: u32, size: u32) -> int {
var src = range_ol_32(src_offset, size);
if (!src.ok()) return -1;
System.write(fd, src.result);
return int.!(size);
}
def extract(src_offset: u32, size: u32) -> Array<byte> {
var src = range_ol_32(src_offset, size);
if (!src.ok()) return null;
var result = Array<byte>.new(src.result.length);
//XXX Target.fastFwCopy(result, src.result);
for (i < result.length) result[i] = src.result[i];
return result;
}
def boundsCheck(offset: u64, index: u64, size: u64) -> i64 {
if (offset > num_bytes) return -1;
if (index > num_bytes) return -1;
if (size > num_bytes) return -1;
var pos = offset + index;
var end = pos + size;
if (end > num_bytes) return -1;
return i64.view(pos);
}
def dumpR(offset: u32, size: u32) {
def OUT = Trace.OUT;
OUT.put1("@%d[", offset);
for (i < size) {
OUT.putx_8(read_u8(offset, i).result);
}
OUT.puts("]").ln();
}
// =============================================================================
// Utility methods for reading individual scalar values
def read_u8(offset: u32, index: u32) -> MaybeTrap<u8> {
return range_oil_32(offset, index, 1).then(DataReaders.read_range_u8);
}
def read_u16(offset: u32, index: u32) -> MaybeTrap<u16> {
return range_oil_32(offset, index, 2).then(DataReaders.read_range_u16);
}
def read_u32(offset: u32, index: u32) -> MaybeTrap<u32> {
return range_oil_32(offset, index, 4).then(DataReaders.read_range_u32);
}
def read_u64(offset: u32, index: u32) -> MaybeTrap<u64> {
return range_oil_32(offset, index, 8).then(DataReaders.read_range_u64);
}
def read_float(offset: u32, index: u32) -> MaybeTrap<float> {
return range_oil_32(offset, index, 4).then(DataReaders.read_range_float);
}
def read_double(offset: u32, index: u32) -> MaybeTrap<double> {
return range_oil_32(offset, index, 8).then(DataReaders.read_range_double);
}
def read_u128(offset: u32, index: u32) -> MaybeTrap<(u64, u64)> {
return range_oil_32(offset, index, 16).then(DataReaders.read_range_u128);
}
// =============================================================================
// Utility methods for writing individual scalar values
def write_u8(offset: u32, index: u32, val: u8) -> TrapReason {
return range_oil_32(offset, index, 1).thenP(DataWriters.write_range_u8, val).reason;
}
def write_u16(offset: u32, index: u32, val: u16) -> TrapReason {
return range_oil_32(offset, index, 2).thenP(DataWriters.write_range_u16, val).reason;
}
def write_u32(offset: u32, index: u32, val: u32) -> TrapReason {
return range_oil_32(offset, index, 4).thenP(DataWriters.write_range_u32, val).reason;
}
def write_u64(offset: u32, index: u32, val: u64) -> TrapReason {
return range_oil_32(offset, index, 8).thenP(DataWriters.write_range_u64, val).reason;
}
def write_float(offset: u32, index: u32, val: float) -> TrapReason {
return range_oil_32(offset, index, 4).thenP(DataWriters.write_range_float, val).reason;
}
def write_double(offset: u32, index: u32, val: double) -> TrapReason {
return range_oil_32(offset, index, 8).thenP(DataWriters.write_range_double, val).reason;
}
def write_u128(offset: u32, index: u32, val: (u64, u64)) -> TrapReason {
return range_oil_32(offset, index, 16).thenP(DataWriters.write_range_u128, val).reason;
}
// =============================================================================
// Target-specific implementation
def deallocate() { } // default: do nothing
def grow(pages: u64) -> int {
return -1; // default: growing always fails
}
def getReadWriteAlias64(start: u64, end: u64) -> Range<byte>;
//TODO def readOnlyAlias(start: u64, end: u64) -> range<byte>;
}
component PrivateMemoryAccess {
// Used by (trusted) subclasses or targets to update the internal page count and length.
def setSize(mem: Memory, num_pages: u64, num_bytes: u64) -> Memory {
mem.num_pages = num_pages;
mem.num_bytes = num_bytes;
return mem;
}
}