Skip to content

Commit 8c05151

Browse files
wip gemini
1 parent 5261763 commit 8c05151

File tree

5 files changed

+469
-821
lines changed

5 files changed

+469
-821
lines changed

src/ir/runtime-memory.h

Lines changed: 222 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#ifndef wasm_ir_runtime_memory_h
1818
#define wasm_ir_runtime_memory_h
1919

20+
#include "fp16.h"
2021
#include "interpreter/exception.h"
2122
#include "wasm.h"
2223

@@ -26,95 +27,266 @@ namespace {
2627

2728
void trapIfGt(uint64_t lhs, uint64_t rhs, const char* msg) {
2829
if (lhs > rhs) {
29-
// std::stringstream ss;
3030
std::cerr << msg << ": " << lhs << " > " << rhs << "\n";
31-
// ss.str();
32-
// std::cerr<<ss
3331
throw TrapException{};
3432
}
3533
}
3634

37-
// void checkAtomicAddress(Address addr, Index bytes, Address memorySize) {
38-
// checkLoadAddress(addr, bytes, memorySize);
39-
// // Unaligned atomics trap.
40-
// if (bytes > 1) {
41-
// if (addr & (bytes - 1)) {
42-
// // "unaligned atomic operation"
43-
// throw TrapException{};
44-
// }
45-
// }
46-
// }
47-
4835
Address getFinalAddress(Address addr,
4936
Address offset,
5037
Index bytes,
5138
Address memorySizeBytes) {
5239
trapIfGt(offset, memorySizeBytes, "offset > memory");
5340
trapIfGt(addr, memorySizeBytes - offset, "final > memory");
5441

55-
// TODO: overflow here?
5642
addr = size_t(addr) + offset;
5743
trapIfGt(bytes, memorySizeBytes, "bytes > memory");
5844

59-
// checkLoadAddress(addr, bytes, memorySizeBytes);
6045
trapIfGt(addr, memorySizeBytes - bytes, "highest > memory");
6146
return addr;
6247
}
6348

64-
template<typename T> static bool aligned(const uint8_t* address) {
65-
static_assert(!(sizeof(T) & (sizeof(T) - 1)), "must be a power of 2");
66-
return 0 == (reinterpret_cast<uintptr_t>(address) & (sizeof(T) - 1));
67-
}
68-
69-
template<typename T>
70-
T asdf(const std::vector<uint8_t>& memory, size_t address) {
71-
if (aligned<T>(&memory[address])) {
72-
return *reinterpret_cast<const T*>(&memory[address]);
73-
} else {
74-
T loaded;
75-
std::memcpy(&loaded, &memory[address], sizeof(T));
76-
return loaded;
77-
}
78-
}
7949
} // namespace
8050

81-
// TODO split into pure virtual class
8251
class RuntimeMemory {
8352
public:
84-
// todo: might want a constructor that takes data segments
85-
RuntimeMemory(Memory memory)
86-
: memoryDefinition(std::move(memory)), memory(memory.initialByteSize(), 0) {
87-
// this->memory.reserve(memory.initialByteSize());
53+
RuntimeMemory(Memory memory) : memoryDefinition(std::move(memory)) {
54+
resize(memoryDefinition.initialByteSize());
8855
}
8956

9057
virtual ~RuntimeMemory() = default;
9158

92-
// variants for load8 etc?
93-
// Do we care about the order here?
94-
// todo: address types? Address::address32_t is strange
95-
// todo: type of offset?
9659
virtual Literal load(Address addr,
9760
Address offset,
9861
uint8_t byteCount,
99-
MemoryOrder order) const {
100-
Address final = getFinalAddress(addr, offset, byteCount, memory.size());
101-
(void) final;
62+
MemoryOrder order,
63+
Type type,
64+
bool signed_) const {
65+
Address final = getFinalAddress(addr, offset, byteCount, size());
66+
if (order != MemoryOrder::Unordered) {
67+
checkAtomicAddress(final, byteCount, size());
68+
}
69+
switch (type.getBasic()) {
70+
case Type::i32: {
71+
switch (byteCount) {
72+
case 1:
73+
return signed_ ? Literal((int32_t)get<int8_t>(final))
74+
: Literal((int32_t)get<uint8_t>(final));
75+
case 2:
76+
return signed_ ? Literal((int32_t)get<int16_t>(final))
77+
: Literal((int32_t)get<uint16_t>(final));
78+
case 4:
79+
return Literal((int32_t)get<int32_t>(final));
80+
default:
81+
WASM_UNREACHABLE("invalid size");
82+
}
83+
}
84+
case Type::i64: {
85+
switch (byteCount) {
86+
case 1:
87+
return signed_ ? Literal((int64_t)get<int8_t>(final))
88+
: Literal((int64_t)get<uint8_t>(final));
89+
case 2:
90+
return signed_ ? Literal((int64_t)get<int16_t>(final))
91+
: Literal((int64_t)get<uint16_t>(final));
92+
case 4:
93+
return signed_ ? Literal((int64_t)get<int32_t>(final))
94+
: Literal((int64_t)get<uint32_t>(final));
95+
case 8:
96+
return Literal((int64_t)get<int64_t>(final));
97+
default:
98+
WASM_UNREACHABLE("invalid size");
99+
}
100+
}
101+
case Type::f32: {
102+
switch (byteCount) {
103+
case 2:
104+
return Literal(bit_cast<int32_t>(
105+
fp16_ieee_to_fp32_value(get<uint16_t>(final))))
106+
.castToF32();
107+
case 4:
108+
return Literal(get<uint32_t>(final)).castToF32();
109+
default:
110+
WASM_UNREACHABLE("invalid size");
111+
}
112+
}
113+
case Type::f64:
114+
return Literal(get<uint64_t>(final)).castToF64();
115+
case Type::v128:
116+
return Literal(get<std::array<uint8_t, 16>>(final).data());
117+
default:
118+
WASM_UNREACHABLE("unexpected type");
119+
}
120+
}
121+
122+
virtual void store(Address addr,
123+
Address offset,
124+
uint8_t byteCount,
125+
MemoryOrder order,
126+
Literal value,
127+
Type type) {
128+
Address final = getFinalAddress(addr, offset, byteCount, size());
129+
if (order != MemoryOrder::Unordered) {
130+
checkAtomicAddress(final, byteCount, size());
131+
}
132+
switch (type.getBasic()) {
133+
case Type::i32: {
134+
switch (byteCount) {
135+
case 1:
136+
set<int8_t>(final, value.geti32());
137+
break;
138+
case 2:
139+
set<int16_t>(final, value.geti32());
140+
break;
141+
case 4:
142+
set<int32_t>(final, value.geti32());
143+
break;
144+
default:
145+
WASM_UNREACHABLE("invalid size");
146+
}
147+
break;
148+
}
149+
case Type::i64: {
150+
switch (byteCount) {
151+
case 1:
152+
set<int8_t>(final, value.geti64());
153+
break;
154+
case 2:
155+
set<int16_t>(final, value.geti64());
156+
break;
157+
case 4:
158+
set<int32_t>(final, value.geti64());
159+
break;
160+
case 8:
161+
set<int64_t>(final, value.geti64());
162+
break;
163+
default:
164+
WASM_UNREACHABLE("invalid size");
165+
}
166+
break;
167+
}
168+
case Type::f32: {
169+
switch (byteCount) {
170+
case 2:
171+
set<uint16_t>(final,
172+
fp16_ieee_from_fp32_value(
173+
bit_cast<float>(value.reinterpreti32())));
174+
break;
175+
case 4:
176+
set<int32_t>(final, value.reinterpreti32());
177+
break;
178+
default:
179+
WASM_UNREACHABLE("invalid size");
180+
}
181+
break;
182+
}
183+
case Type::f64:
184+
set<int64_t>(final, value.reinterpreti64());
185+
break;
186+
case Type::v128:
187+
set<std::array<uint8_t, 16>>(final, value.getv128());
188+
break;
189+
default:
190+
WASM_UNREACHABLE("unexpected type");
191+
}
192+
}
193+
194+
virtual bool grow(Address delta) {
195+
Address pageSize = memoryDefinition.pageSize();
196+
Address oldPages = intendedSize / pageSize;
197+
Address newPages = oldPages + delta;
198+
if (newPages > memoryDefinition.max && memoryDefinition.hasMax()) {
199+
return false;
200+
}
201+
// Apply a reasonable limit on memory size, 1GB, to avoid DOS on the
202+
// interpreter.
203+
if (newPages * pageSize > 1024 * 1024 * 1024) {
204+
return false;
205+
}
206+
resize(newPages * pageSize);
207+
return true;
208+
}
209+
210+
virtual Address size() const { return intendedSize; }
211+
212+
virtual void
213+
init(Address dest, Address src, Address byteCount, const DataSegment* data) {
214+
trapIfGt(uint64_t(src), uint64_t(data->data.size()), "src > data");
215+
trapIfGt(uint64_t(byteCount),
216+
uint64_t(data->data.size() - src),
217+
"src + size > data");
218+
Address final = getFinalAddress(dest, 0, byteCount, size());
219+
std::memcpy(&memory[final], &data->data[src], byteCount);
220+
}
102221

103-
// return memory.get()
222+
virtual void
223+
copy(Address dest, Address src, Address byteCount, const RuntimeMemory* srcMemory) {
224+
Address finalDest = getFinalAddress(dest, 0, byteCount, size());
225+
Address finalSrc = getFinalAddress(src, 0, byteCount, srcMemory->size());
226+
std::memmove(&memory[finalDest], &srcMemory->memory[finalSrc], byteCount);
227+
}
104228

105-
return Literal(asdf<int32_t>(memory, (size_t) final));
229+
virtual void fill(Address dest, uint8_t value, Address byteCount) {
230+
Address final = getFinalAddress(dest, 0, byteCount, size());
231+
std::memset(&memory[final], value, byteCount);
232+
}
106233

107-
// return Literal(1);
234+
void resize(size_t newSize) {
235+
intendedSize = newSize;
236+
const size_t minSize = 1 << 12;
237+
size_t oldAllocatedSize = memory.size();
238+
memory.resize(std::max(minSize, newSize), 0);
239+
if (newSize < oldAllocatedSize && newSize < minSize) {
240+
std::memset(&memory[newSize], 0, minSize - newSize);
241+
}
108242
}
109-
virtual Literal load(uint64_t addr) const { return {}; }
110243

111244
const Memory* getDefinition() const { return &memoryDefinition; }
112245

246+
template<typename T> T get(size_t address) const {
247+
if (aligned<T>(&memory[address])) {
248+
return *reinterpret_cast<const T*>(&memory[address]);
249+
} else {
250+
T loaded;
251+
std::memcpy(&loaded, &memory[address], sizeof(T));
252+
return loaded;
253+
}
254+
}
255+
256+
template<typename T> void set(size_t address, T value) {
257+
if (aligned<T>(&memory[address])) {
258+
*reinterpret_cast<T*>(&memory[address]) = value;
259+
} else {
260+
std::memcpy(&memory[address], &value, sizeof(T));
261+
}
262+
}
263+
264+
void checkLoadAddress(Address addr, Index bytes, Address memorySizeBytes) const {
265+
trapIfGt(addr, memorySizeBytes - bytes, "highest > memory");
266+
}
267+
268+
void
269+
checkAtomicAddress(Address addr, Index bytes, Address memorySizeBytes) const {
270+
checkLoadAddress(addr, bytes, memorySizeBytes);
271+
// Unaligned atomics trap.
272+
if (bytes > 1) {
273+
if (addr & (bytes - 1)) {
274+
std::cerr << "unaligned atomic operation: " << addr << " " << bytes
275+
<< "\n";
276+
throw TrapException{};
277+
}
278+
}
279+
}
280+
113281
protected:
114282
const Memory memoryDefinition;
115-
116-
private:
117283
std::vector<uint8_t> memory;
284+
Address intendedSize = 0;
285+
286+
template<typename T> static bool aligned(const uint8_t* address) {
287+
static_assert(!(sizeof(T) & (sizeof(T) - 1)), "must be a power of 2");
288+
return 0 == (reinterpret_cast<uintptr_t>(address) & (sizeof(T) - 1));
289+
}
118290
};
119291

120292
class RealRuntimeMemory : public RuntimeMemory {
@@ -124,4 +296,4 @@ class RealRuntimeMemory : public RuntimeMemory {
124296

125297
} // namespace wasm
126298

127-
#endif // wasm_ir_runtime_memory_h
299+
#endif // wasm_ir_runtime_memory_h

0 commit comments

Comments
 (0)