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
2728void 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-
4835Address 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
8251class RuntimeMemory {
8352public:
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+
113281protected:
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
120292class 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