]> git.proxmox.com Git - rustc.git/blob - src/binaryen/src/wasm-interpreter.h
New upstream version 1.23.0+dfsg1
[rustc.git] / src / binaryen / src / wasm-interpreter.h
1 /*
2 * Copyright 2015 WebAssembly Community Group participants
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //
18 // Simple WebAssembly interpreter. This operates directly on the AST,
19 // for simplicity and clarity. A goal is for it to be possible for
20 // people to read this code and understand WebAssembly semantics.
21 //
22
23 #ifndef wasm_wasm_interpreter_h
24 #define wasm_wasm_interpreter_h
25
26 #include <cmath>
27 #include <limits.h>
28 #include <sstream>
29
30 #include "support/bits.h"
31 #include "support/safe_integer.h"
32 #include "wasm.h"
33 #include "wasm-traversal.h"
34
35
36 #ifdef WASM_INTERPRETER_DEBUG
37 #include "wasm-printing.h"
38 #endif
39
40
41 namespace wasm {
42
43 using namespace cashew;
44
45 // Utilities
46
47 extern Name WASM, RETURN_FLOW;
48
49 enum {
50 maxCallDepth = 250
51 };
52
53 // Stuff that flows around during executing expressions: a literal, or a change in control flow.
54 class Flow {
55 public:
56 Flow() {}
57 Flow(Literal value) : value(value) {}
58 Flow(Name breakTo) : breakTo(breakTo) {}
59
60 Literal value;
61 Name breakTo; // if non-null, a break is going on
62
63 bool breaking() { return breakTo.is(); }
64
65 void clearIf(Name target) {
66 if (breakTo == target) {
67 breakTo.clear();
68 }
69 }
70
71 friend std::ostream& operator<<(std::ostream& o, Flow& flow) {
72 o << "(flow " << (flow.breakTo.is() ? flow.breakTo.str : "-") << " : " << flow.value << ')';
73 return o;
74 }
75 };
76
77 // A list of literals, for function calls
78 typedef std::vector<Literal> LiteralList;
79
80 // Debugging helpers
81 #ifdef WASM_INTERPRETER_DEBUG
82 class Indenter {
83 static int indentLevel;
84
85 const char* entryName;
86
87 public:
88 Indenter(const char* entry);
89 ~Indenter();
90
91 static void print();
92 };
93
94 #define NOTE_ENTER(x) Indenter _int_blah(x); { \
95 Indenter::print(); \
96 std::cout << "visit " << x << " : " << curr << "\n"; }
97 #define NOTE_ENTER_(x) Indenter _int_blah(x); { \
98 Indenter::print(); \
99 std::cout << "visit " << x << "\n"; }
100 #define NOTE_NAME(p0) { \
101 Indenter::print(); \
102 std::cout << "name " << '(' << Name(p0) << ")\n"; }
103 #define NOTE_EVAL1(p0) { \
104 Indenter::print(); \
105 std::cout << "eval " #p0 " (" << p0 << ")\n"; }
106 #define NOTE_EVAL2(p0, p1) { \
107 Indenter::print(); \
108 std::cout << "eval " #p0 " (" << p0 << "), " #p1 " (" << p1 << ")\n"; }
109 #else // WASM_INTERPRETER_DEBUG
110 #define NOTE_ENTER(x)
111 #define NOTE_ENTER_(x)
112 #define NOTE_NAME(p0)
113 #define NOTE_EVAL1(p0)
114 #define NOTE_EVAL2(p0, p1)
115 #endif // WASM_INTERPRETER_DEBUG
116
117 // Execute an expression
118 template<typename SubType>
119 class ExpressionRunner : public Visitor<SubType, Flow> {
120 public:
121 Flow visit(Expression *curr) {
122 auto ret = Visitor<SubType, Flow>::visit(curr);
123 if (!ret.breaking() && (isConcreteWasmType(curr->type) || isConcreteWasmType(ret.value.type))) {
124 #if 1 // def WASM_INTERPRETER_DEBUG
125 if (ret.value.type != curr->type) {
126 std::cerr << "expected " << printWasmType(curr->type) << ", seeing " << printWasmType(ret.value.type) << " from\n" << curr << '\n';
127 }
128 #endif
129 assert(ret.value.type == curr->type);
130 }
131 return ret;
132 }
133
134 Flow visitBlock(Block *curr) {
135 NOTE_ENTER("Block");
136 // special-case Block, because Block nesting (in their first element) can be incredibly deep
137 std::vector<Block*> stack;
138 stack.push_back(curr);
139 while (curr->list.size() > 0 && curr->list[0]->is<Block>()) {
140 curr = curr->list[0]->cast<Block>();
141 stack.push_back(curr);
142 }
143 Flow flow;
144 auto* top = stack.back();
145 while (stack.size() > 0) {
146 curr = stack.back();
147 stack.pop_back();
148 if (flow.breaking()) {
149 flow.clearIf(curr->name);
150 continue;
151 }
152 auto& list = curr->list;
153 for (size_t i = 0; i < list.size(); i++) {
154 if (curr != top && i == 0) {
155 // one of the block recursions we already handled
156 continue;
157 }
158 flow = visit(list[i]);
159 if (flow.breaking()) {
160 flow.clearIf(curr->name);
161 break;
162 }
163 }
164 }
165 return flow;
166 }
167 Flow visitIf(If *curr) {
168 NOTE_ENTER("If");
169 Flow flow = visit(curr->condition);
170 if (flow.breaking()) return flow;
171 NOTE_EVAL1(flow.value);
172 if (flow.value.geti32()) {
173 Flow flow = visit(curr->ifTrue);
174 if (!flow.breaking() && !curr->ifFalse) flow.value = Literal(); // if_else returns a value, but if does not
175 return flow;
176 }
177 if (curr->ifFalse) return visit(curr->ifFalse);
178 return Flow();
179 }
180 Flow visitLoop(Loop *curr) {
181 NOTE_ENTER("Loop");
182 while (1) {
183 Flow flow = visit(curr->body);
184 if (flow.breaking()) {
185 if (flow.breakTo == curr->name) continue; // lol
186 }
187 return flow; // loop does not loop automatically, only continue achieves that
188 }
189 }
190 Flow visitBreak(Break *curr) {
191 NOTE_ENTER("Break");
192 bool condition = true;
193 Flow flow;
194 if (curr->value) {
195 flow = visit(curr->value);
196 if (flow.breaking()) return flow;
197 }
198 if (curr->condition) {
199 Flow conditionFlow = visit(curr->condition);
200 if (conditionFlow.breaking()) return conditionFlow;
201 condition = conditionFlow.value.getInteger() != 0;
202 if (!condition) return flow;
203 }
204 flow.breakTo = curr->name;
205 return flow;
206 }
207 Flow visitSwitch(Switch *curr) {
208 NOTE_ENTER("Switch");
209 Flow flow;
210 Literal value;
211 if (curr->value) {
212 flow = visit(curr->value);
213 if (flow.breaking()) return flow;
214 value = flow.value;
215 NOTE_EVAL1(value);
216 }
217 flow = visit(curr->condition);
218 if (flow.breaking()) return flow;
219 int64_t index = flow.value.getInteger();
220 Name target = curr->default_;
221 if (index >= 0 && (size_t)index < curr->targets.size()) {
222 target = curr->targets[(size_t)index];
223 }
224 flow.breakTo = target;
225 flow.value = value;
226 return flow;
227 }
228
229 Flow visitConst(Const *curr) {
230 NOTE_ENTER("Const");
231 NOTE_EVAL1(curr->value);
232 return Flow(curr->value); // heh
233 }
234 Flow visitUnary(Unary *curr) {
235 NOTE_ENTER("Unary");
236 Flow flow = visit(curr->value);
237 if (flow.breaking()) return flow;
238 Literal value = flow.value;
239 NOTE_EVAL1(value);
240 if (value.type == i32) {
241 switch (curr->op) {
242 case ClzInt32: return value.countLeadingZeroes();
243 case CtzInt32: return value.countTrailingZeroes();
244 case PopcntInt32: return value.popCount();
245 case EqZInt32: return Literal(int32_t(value == Literal(int32_t(0))));
246 case ReinterpretInt32: return value.castToF32();
247 case ExtendSInt32: return value.extendToSI64();
248 case ExtendUInt32: return value.extendToUI64();
249 case ConvertUInt32ToFloat32: return value.convertUToF32();
250 case ConvertUInt32ToFloat64: return value.convertUToF64();
251 case ConvertSInt32ToFloat32: return value.convertSToF32();
252 case ConvertSInt32ToFloat64: return value.convertSToF64();
253 default: WASM_UNREACHABLE();
254 }
255 }
256 if (value.type == i64) {
257 switch (curr->op) {
258 case ClzInt64: return value.countLeadingZeroes();
259 case CtzInt64: return value.countTrailingZeroes();
260 case PopcntInt64: return value.popCount();
261 case EqZInt64: return Literal(int32_t(value == Literal(int64_t(0))));
262 case WrapInt64: return value.truncateToI32();
263 case ReinterpretInt64: return value.castToF64();
264 case ConvertUInt64ToFloat32: return value.convertUToF32();
265 case ConvertUInt64ToFloat64: return value.convertUToF64();
266 case ConvertSInt64ToFloat32: return value.convertSToF32();
267 case ConvertSInt64ToFloat64: return value.convertSToF64();
268 default: WASM_UNREACHABLE();
269 }
270 }
271 if (value.type == f32) {
272 switch (curr->op) {
273 case NegFloat32: return value.neg();
274 case AbsFloat32: return value.abs();
275 case CeilFloat32: return value.ceil();
276 case FloorFloat32: return value.floor();
277 case TruncFloat32: return value.trunc();
278 case NearestFloat32: return value.nearbyint();
279 case SqrtFloat32: return value.sqrt();
280 case TruncSFloat32ToInt32:
281 case TruncSFloat32ToInt64: return truncSFloat(curr, value);
282 case TruncUFloat32ToInt32:
283 case TruncUFloat32ToInt64: return truncUFloat(curr, value);
284 case ReinterpretFloat32: return value.castToI32();
285 case PromoteFloat32: return value.extendToF64();
286 default: WASM_UNREACHABLE();
287 }
288 }
289 if (value.type == f64) {
290 switch (curr->op) {
291 case NegFloat64: return value.neg();
292 case AbsFloat64: return value.abs();
293 case CeilFloat64: return value.ceil();
294 case FloorFloat64: return value.floor();
295 case TruncFloat64: return value.trunc();
296 case NearestFloat64: return value.nearbyint();
297 case SqrtFloat64: return value.sqrt();
298 case TruncSFloat64ToInt32:
299 case TruncSFloat64ToInt64: return truncSFloat(curr, value);
300 case TruncUFloat64ToInt32:
301 case TruncUFloat64ToInt64: return truncUFloat(curr, value);
302 case ReinterpretFloat64: return value.castToI64();
303 case DemoteFloat64: {
304 double val = value.getFloat();
305 if (std::isnan(val)) return Literal(float(val));
306 if (std::isinf(val)) return Literal(float(val));
307 // when close to the limit, but still truncatable to a valid value, do that
308 // see https://github.com/WebAssembly/sexpr-wasm-prototype/blob/2d375e8d502327e814d62a08f22da9d9b6b675dc/src/wasm-interpreter.c#L247
309 uint64_t bits = value.reinterpreti64();
310 if (bits > 0x47efffffe0000000ULL && bits < 0x47effffff0000000ULL) return Literal(std::numeric_limits<float>::max());
311 if (bits > 0xc7efffffe0000000ULL && bits < 0xc7effffff0000000ULL) return Literal(-std::numeric_limits<float>::max());
312 // when we must convert to infinity, do that
313 if (val < -std::numeric_limits<float>::max()) return Literal(-std::numeric_limits<float>::infinity());
314 if (val > std::numeric_limits<float>::max()) return Literal(std::numeric_limits<float>::infinity());
315 return value.truncateToF32();
316 }
317 default: WASM_UNREACHABLE();
318 }
319 }
320 WASM_UNREACHABLE();
321 }
322 Flow visitBinary(Binary *curr) {
323 NOTE_ENTER("Binary");
324 Flow flow = visit(curr->left);
325 if (flow.breaking()) return flow;
326 Literal left = flow.value;
327 flow = visit(curr->right);
328 if (flow.breaking()) return flow;
329 Literal right = flow.value;
330 NOTE_EVAL2(left, right);
331 assert(isConcreteWasmType(curr->left->type) ? left.type == curr->left->type : true);
332 assert(isConcreteWasmType(curr->right->type) ? right.type == curr->right->type : true);
333 if (left.type == i32) {
334 switch (curr->op) {
335 case AddInt32: return left.add(right);
336 case SubInt32: return left.sub(right);
337 case MulInt32: return left.mul(right);
338 case DivSInt32: {
339 if (right.getInteger() == 0) trap("i32.div_s by 0");
340 if (left.getInteger() == std::numeric_limits<int32_t>::min() && right.getInteger() == -1) trap("i32.div_s overflow"); // signed division overflow
341 return left.divS(right);
342 }
343 case DivUInt32: {
344 if (right.getInteger() == 0) trap("i32.div_u by 0");
345 return left.divU(right);
346 }
347 case RemSInt32: {
348 if (right.getInteger() == 0) trap("i32.rem_s by 0");
349 if (left.getInteger() == std::numeric_limits<int32_t>::min() && right.getInteger() == -1) return Literal(int32_t(0));
350 return left.remS(right);
351 }
352 case RemUInt32: {
353 if (right.getInteger() == 0) trap("i32.rem_u by 0");
354 return left.remU(right);
355 }
356 case AndInt32: return left.and_(right);
357 case OrInt32: return left.or_(right);
358 case XorInt32: return left.xor_(right);
359 case ShlInt32: return left.shl(right.and_(Literal(int32_t(31))));
360 case ShrUInt32: return left.shrU(right.and_(Literal(int32_t(31))));
361 case ShrSInt32: return left.shrS(right.and_(Literal(int32_t(31))));
362 case RotLInt32: return left.rotL(right);
363 case RotRInt32: return left.rotR(right);
364 case EqInt32: return left.eq(right);
365 case NeInt32: return left.ne(right);
366 case LtSInt32: return left.ltS(right);
367 case LtUInt32: return left.ltU(right);
368 case LeSInt32: return left.leS(right);
369 case LeUInt32: return left.leU(right);
370 case GtSInt32: return left.gtS(right);
371 case GtUInt32: return left.gtU(right);
372 case GeSInt32: return left.geS(right);
373 case GeUInt32: return left.geU(right);
374 default: WASM_UNREACHABLE();
375 }
376 } else if (left.type == i64) {
377 switch (curr->op) {
378 case AddInt64: return left.add(right);
379 case SubInt64: return left.sub(right);
380 case MulInt64: return left.mul(right);
381 case DivSInt64: {
382 if (right.getInteger() == 0) trap("i64.div_s by 0");
383 if (left.getInteger() == LLONG_MIN && right.getInteger() == -1LL) trap("i64.div_s overflow"); // signed division overflow
384 return left.divS(right);
385 }
386 case DivUInt64: {
387 if (right.getInteger() == 0) trap("i64.div_u by 0");
388 return left.divU(right);
389 }
390 case RemSInt64: {
391 if (right.getInteger() == 0) trap("i64.rem_s by 0");
392 if (left.getInteger() == LLONG_MIN && right.getInteger() == -1LL) return Literal(int64_t(0));
393 return left.remS(right);
394 }
395 case RemUInt64: {
396 if (right.getInteger() == 0) trap("i64.rem_u by 0");
397 return left.remU(right);
398 }
399 case AndInt64: return left.and_(right);
400 case OrInt64: return left.or_(right);
401 case XorInt64: return left.xor_(right);
402 case ShlInt64: return left.shl(right.and_(Literal(int64_t(63))));
403 case ShrUInt64: return left.shrU(right.and_(Literal(int64_t(63))));
404 case ShrSInt64: return left.shrS(right.and_(Literal(int64_t(63))));
405 case RotLInt64: return left.rotL(right);
406 case RotRInt64: return left.rotR(right);
407 case EqInt64: return left.eq(right);
408 case NeInt64: return left.ne(right);
409 case LtSInt64: return left.ltS(right);
410 case LtUInt64: return left.ltU(right);
411 case LeSInt64: return left.leS(right);
412 case LeUInt64: return left.leU(right);
413 case GtSInt64: return left.gtS(right);
414 case GtUInt64: return left.gtU(right);
415 case GeSInt64: return left.geS(right);
416 case GeUInt64: return left.geU(right);
417 default: WASM_UNREACHABLE();
418 }
419 } else if (left.type == f32 || left.type == f64) {
420 switch (curr->op) {
421 case AddFloat32: case AddFloat64: return left.add(right);
422 case SubFloat32: case SubFloat64: return left.sub(right);
423 case MulFloat32: case MulFloat64: return left.mul(right);
424 case DivFloat32: case DivFloat64: return left.div(right);
425 case CopySignFloat32: case CopySignFloat64: return left.copysign(right);
426 case MinFloat32: case MinFloat64: return left.min(right);
427 case MaxFloat32: case MaxFloat64: return left.max(right);
428 case EqFloat32: case EqFloat64: return left.eq(right);
429 case NeFloat32: case NeFloat64: return left.ne(right);
430 case LtFloat32: case LtFloat64: return left.lt(right);
431 case LeFloat32: case LeFloat64: return left.le(right);
432 case GtFloat32: case GtFloat64: return left.gt(right);
433 case GeFloat32: case GeFloat64: return left.ge(right);
434 default: WASM_UNREACHABLE();
435 }
436 }
437 WASM_UNREACHABLE();
438 }
439 Flow visitSelect(Select *curr) {
440 NOTE_ENTER("Select");
441 Flow ifTrue = visit(curr->ifTrue);
442 if (ifTrue.breaking()) return ifTrue;
443 Flow ifFalse = visit(curr->ifFalse);
444 if (ifFalse.breaking()) return ifFalse;
445 Flow condition = visit(curr->condition);
446 if (condition.breaking()) return condition;
447 NOTE_EVAL1(condition.value);
448 return condition.value.geti32() ? ifTrue : ifFalse; // ;-)
449 }
450 Flow visitDrop(Drop *curr) {
451 NOTE_ENTER("Drop");
452 Flow value = visit(curr->value);
453 if (value.breaking()) return value;
454 return Flow();
455 }
456 Flow visitReturn(Return *curr) {
457 NOTE_ENTER("Return");
458 Flow flow;
459 if (curr->value) {
460 flow = visit(curr->value);
461 if (flow.breaking()) return flow;
462 NOTE_EVAL1(flow.value);
463 }
464 flow.breakTo = RETURN_FLOW;
465 return flow;
466 }
467 Flow visitNop(Nop *curr) {
468 NOTE_ENTER("Nop");
469 return Flow();
470 }
471 Flow visitUnreachable(Unreachable *curr) {
472 NOTE_ENTER("Unreachable");
473 trap("unreachable");
474 WASM_UNREACHABLE();
475 }
476
477 Literal truncSFloat(Unary* curr, Literal value) {
478 double val = value.getFloat();
479 if (std::isnan(val)) trap("truncSFloat of nan");
480 if (curr->type == i32) {
481 if (value.type == f32) {
482 if (!isInRangeI32TruncS(value.reinterpreti32())) trap("i32.truncSFloat overflow");
483 } else {
484 if (!isInRangeI32TruncS(value.reinterpreti64())) trap("i32.truncSFloat overflow");
485 }
486 return Literal(int32_t(val));
487 } else {
488 if (value.type == f32) {
489 if (!isInRangeI64TruncS(value.reinterpreti32())) trap("i64.truncSFloat overflow");
490 } else {
491 if (!isInRangeI64TruncS(value.reinterpreti64())) trap("i64.truncSFloat overflow");
492 }
493 return Literal(int64_t(val));
494 }
495 }
496
497 Literal truncUFloat(Unary* curr, Literal value) {
498 double val = value.getFloat();
499 if (std::isnan(val)) trap("truncUFloat of nan");
500 if (curr->type == i32) {
501 if (value.type == f32) {
502 if (!isInRangeI32TruncU(value.reinterpreti32())) trap("i32.truncUFloat overflow");
503 } else {
504 if (!isInRangeI32TruncU(value.reinterpreti64())) trap("i32.truncUFloat overflow");
505 }
506 return Literal(uint32_t(val));
507 } else {
508 if (value.type == f32) {
509 if (!isInRangeI64TruncU(value.reinterpreti32())) trap("i64.truncUFloat overflow");
510 } else {
511 if (!isInRangeI64TruncU(value.reinterpreti64())) trap("i64.truncUFloat overflow");
512 }
513 return Literal(uint64_t(val));
514 }
515 }
516
517 virtual void trap(const char* why) {
518 WASM_UNREACHABLE();
519 }
520 };
521
522 // Execute an constant expression in a global init or memory offset
523 template<typename GlobalManager>
524 class ConstantExpressionRunner : public ExpressionRunner<ConstantExpressionRunner<GlobalManager>> {
525 GlobalManager& globals;
526 public:
527 ConstantExpressionRunner(GlobalManager& globals) : globals(globals) {}
528
529 Flow visitLoop(Loop* curr) { WASM_UNREACHABLE(); }
530 Flow visitCall(Call* curr) { WASM_UNREACHABLE(); }
531 Flow visitCallImport(CallImport* curr) { WASM_UNREACHABLE(); }
532 Flow visitCallIndirect(CallIndirect* curr) { WASM_UNREACHABLE(); }
533 Flow visitGetLocal(GetLocal *curr) { WASM_UNREACHABLE(); }
534 Flow visitSetLocal(SetLocal *curr) { WASM_UNREACHABLE(); }
535 Flow visitGetGlobal(GetGlobal *curr) {
536 return Flow(globals[curr->name]);
537 }
538 Flow visitSetGlobal(SetGlobal *curr) { WASM_UNREACHABLE(); }
539 Flow visitLoad(Load *curr) { WASM_UNREACHABLE(); }
540 Flow visitStore(Store *curr) { WASM_UNREACHABLE(); }
541 Flow visitHost(Host *curr) { WASM_UNREACHABLE(); }
542 };
543
544 //
545 // An instance of a WebAssembly module, which can execute it via AST interpretation.
546 //
547 // To embed this interpreter, you need to provide an ExternalInterface instance
548 // (see below) which provides the embedding-specific details, that is, how to
549 // connect to the embedding implementation.
550 //
551 // To call into the interpreter, use callExport.
552 //
553
554 template<typename GlobalManager, typename SubType>
555 class ModuleInstanceBase {
556 public:
557 //
558 // You need to implement one of these to create a concrete interpreter. The
559 // ExternalInterface provides embedding-specific functionality like calling
560 // an imported function or accessing memory.
561 //
562 struct ExternalInterface {
563 virtual void init(Module& wasm, SubType& instance) {}
564 virtual void importGlobals(GlobalManager& globals, Module& wasm) = 0;
565 virtual Literal callImport(Import* import, LiteralList& arguments) = 0;
566 virtual Literal callTable(Index index, LiteralList& arguments, WasmType result, SubType& instance) = 0;
567 virtual void growMemory(Address oldSize, Address newSize) = 0;
568 virtual void trap(const char* why) = 0;
569
570 // the default impls for load and store switch on the sizes. you can either
571 // customize load/store, or the sub-functions which they call
572 virtual Literal load(Load* load, Address addr) {
573 switch (load->type) {
574 case i32: {
575 switch (load->bytes) {
576 case 1: return load->signed_ ? Literal((int32_t)load8s(addr)) : Literal((int32_t)load8u(addr));
577 case 2: return load->signed_ ? Literal((int32_t)load16s(addr)) : Literal((int32_t)load16u(addr));
578 case 4: return Literal((int32_t)load32s(addr));
579 default: WASM_UNREACHABLE();
580 }
581 break;
582 }
583 case i64: {
584 switch (load->bytes) {
585 case 1: return load->signed_ ? Literal((int64_t)load8s(addr)) : Literal((int64_t)load8u(addr));
586 case 2: return load->signed_ ? Literal((int64_t)load16s(addr)) : Literal((int64_t)load16u(addr));
587 case 4: return load->signed_ ? Literal((int64_t)load32s(addr)) : Literal((int64_t)load32u(addr));
588 case 8: return Literal((int64_t)load64s(addr));
589 default: WASM_UNREACHABLE();
590 }
591 break;
592 }
593 case f32: return Literal(load32u(addr)).castToF32();
594 case f64: return Literal(load64u(addr)).castToF64();
595 default: WASM_UNREACHABLE();
596 }
597 }
598 virtual void store(Store* store, Address addr, Literal value) {
599 switch (store->valueType) {
600 case i32: {
601 switch (store->bytes) {
602 case 1: store8(addr, value.geti32()); break;
603 case 2: store16(addr, value.geti32()); break;
604 case 4: store32(addr, value.geti32()); break;
605 default: WASM_UNREACHABLE();
606 }
607 break;
608 }
609 case i64: {
610 switch (store->bytes) {
611 case 1: store8(addr, value.geti64()); break;
612 case 2: store16(addr, value.geti64()); break;
613 case 4: store32(addr, value.geti64()); break;
614 case 8: store64(addr, value.geti64()); break;
615 default: WASM_UNREACHABLE();
616 }
617 break;
618 }
619 // write floats carefully, ensuring all bits reach memory
620 case f32: store32(addr, value.reinterpreti32()); break;
621 case f64: store64(addr, value.reinterpreti64()); break;
622 default: WASM_UNREACHABLE();
623 }
624 }
625
626 virtual int8_t load8s(Address addr) { WASM_UNREACHABLE(); }
627 virtual uint8_t load8u(Address addr) { WASM_UNREACHABLE(); }
628 virtual int16_t load16s(Address addr) { WASM_UNREACHABLE(); }
629 virtual uint16_t load16u(Address addr) { WASM_UNREACHABLE(); }
630 virtual int32_t load32s(Address addr) { WASM_UNREACHABLE(); }
631 virtual uint32_t load32u(Address addr) { WASM_UNREACHABLE(); }
632 virtual int64_t load64s(Address addr) { WASM_UNREACHABLE(); }
633 virtual uint64_t load64u(Address addr) { WASM_UNREACHABLE(); }
634
635 virtual void store8(Address addr, int8_t value) { WASM_UNREACHABLE(); }
636 virtual void store16(Address addr, int16_t value) { WASM_UNREACHABLE(); }
637 virtual void store32(Address addr, int32_t value) { WASM_UNREACHABLE(); }
638 virtual void store64(Address addr, int64_t value) { WASM_UNREACHABLE(); }
639 };
640
641 SubType* self() {
642 return static_cast<SubType*>(this);
643 }
644
645 Module& wasm;
646
647 // Values of globals
648 GlobalManager globals;
649
650 ModuleInstanceBase(Module& wasm, ExternalInterface* externalInterface) : wasm(wasm), externalInterface(externalInterface) {
651 // import globals from the outside
652 externalInterface->importGlobals(globals, wasm);
653 // prepare memory
654 memorySize = wasm.memory.initial;
655 // generate internal (non-imported) globals
656 for (auto& global : wasm.globals) {
657 globals[global->name] = ConstantExpressionRunner<GlobalManager>(globals).visit(global->init).value;
658 }
659 // initialize the rest of the external interface
660 externalInterface->init(wasm, *self());
661 // run start, if present
662 if (wasm.start.is()) {
663 LiteralList arguments;
664 callFunction(wasm.start, arguments);
665 }
666 }
667
668 // call an exported function
669 Literal callExport(Name name, LiteralList& arguments) {
670 Export *export_ = wasm.getExportOrNull(name);
671 if (!export_) externalInterface->trap("callExport not found");
672 return callFunction(export_->value, arguments);
673 }
674
675 Literal callExport(Name name) {
676 LiteralList arguments;
677 return callExport(name, arguments);
678 }
679
680 // get an exported global
681 Literal getExport(Name name) {
682 Export *export_ = wasm.getExportOrNull(name);
683 if (!export_) externalInterface->trap("getExport external not found");
684 Name internalName = export_->value;
685 auto iter = globals.find(internalName);
686 if (iter == globals.end()) externalInterface->trap("getExport internal not found");
687 return iter->second;
688 }
689
690 std::string printFunctionStack() {
691 std::string ret = "/== (binaryen interpreter stack trace)\n";
692 for (int i = int(functionStack.size()) - 1; i >= 0; i--) {
693 ret += std::string("|: ") + functionStack[i].str + "\n";
694 }
695 ret += std::string("\\==\n");
696 return ret;
697 }
698
699 private:
700 // Keep a record of call depth, to guard against excessive recursion.
701 size_t callDepth;
702
703 // Function name stack. We maintain this explicitly to allow printing of
704 // stack traces.
705 std::vector<Name> functionStack;
706
707 public:
708 // Call a function, starting an invocation.
709 Literal callFunction(Name name, LiteralList& arguments) {
710 // if the last call ended in a jump up the stack, it might have left stuff for us to clean up here
711 callDepth = 0;
712 functionStack.clear();
713 return callFunctionInternal(name, arguments);
714 }
715
716 // Internal function call. Must be public so that callTable implementations can use it (refactor?)
717 Literal callFunctionInternal(Name name, LiteralList& arguments) {
718
719 class FunctionScope {
720 public:
721 std::vector<Literal> locals;
722 Function* function;
723
724 FunctionScope(Function* function, LiteralList& arguments)
725 : function(function) {
726 if (function->params.size() != arguments.size()) {
727 std::cerr << "Function `" << function->name << "` expects "
728 << function->params.size() << " parameters, got "
729 << arguments.size() << " arguments." << std::endl;
730 WASM_UNREACHABLE();
731 }
732 locals.resize(function->getNumLocals());
733 for (size_t i = 0; i < function->getNumLocals(); i++) {
734 if (i < arguments.size()) {
735 assert(function->isParam(i));
736 if (function->params[i] != arguments[i].type) {
737 std::cerr << "Function `" << function->name << "` expects type "
738 << printWasmType(function->params[i])
739 << " for parameter " << i << ", got "
740 << printWasmType(arguments[i].type) << "." << std::endl;
741 WASM_UNREACHABLE();
742 }
743 locals[i] = arguments[i];
744 } else {
745 assert(function->isVar(i));
746 locals[i].type = function->getLocalType(i);
747 }
748 }
749 }
750 };
751
752 // Executes expresions with concrete runtime info, the function and module at runtime
753 class RuntimeExpressionRunner : public ExpressionRunner<RuntimeExpressionRunner> {
754 ModuleInstanceBase& instance;
755 FunctionScope& scope;
756
757 public:
758 RuntimeExpressionRunner(ModuleInstanceBase& instance, FunctionScope& scope) : instance(instance), scope(scope) {}
759
760 Flow generateArguments(const ExpressionList& operands, LiteralList& arguments) {
761 NOTE_ENTER_("generateArguments");
762 arguments.reserve(operands.size());
763 for (auto expression : operands) {
764 Flow flow = this->visit(expression);
765 if (flow.breaking()) return flow;
766 NOTE_EVAL1(flow.value);
767 arguments.push_back(flow.value);
768 }
769 return Flow();
770 }
771
772 Flow visitCall(Call *curr) {
773 NOTE_ENTER("Call");
774 NOTE_NAME(curr->target);
775 LiteralList arguments;
776 Flow flow = generateArguments(curr->operands, arguments);
777 if (flow.breaking()) return flow;
778 Flow ret = instance.callFunctionInternal(curr->target, arguments);
779 #ifdef WASM_INTERPRETER_DEBUG
780 std::cout << "(returned to " << scope.function->name << ")\n";
781 #endif
782 return ret;
783 }
784 Flow visitCallImport(CallImport *curr) {
785 NOTE_ENTER("CallImport");
786 LiteralList arguments;
787 Flow flow = generateArguments(curr->operands, arguments);
788 if (flow.breaking()) return flow;
789 return instance.externalInterface->callImport(instance.wasm.getImport(curr->target), arguments);
790 }
791 Flow visitCallIndirect(CallIndirect *curr) {
792 NOTE_ENTER("CallIndirect");
793 LiteralList arguments;
794 Flow flow = generateArguments(curr->operands, arguments);
795 if (flow.breaking()) return flow;
796 Flow target = this->visit(curr->target);
797 if (target.breaking()) return target;
798 Index index = target.value.geti32();
799 return instance.externalInterface->callTable(index, arguments, curr->type, *instance.self());
800 }
801
802 Flow visitGetLocal(GetLocal *curr) {
803 NOTE_ENTER("GetLocal");
804 auto index = curr->index;
805 NOTE_EVAL1(index);
806 NOTE_EVAL1(scope.locals[index]);
807 return scope.locals[index];
808 }
809 Flow visitSetLocal(SetLocal *curr) {
810 NOTE_ENTER("SetLocal");
811 auto index = curr->index;
812 Flow flow = this->visit(curr->value);
813 if (flow.breaking()) return flow;
814 NOTE_EVAL1(index);
815 NOTE_EVAL1(flow.value);
816 assert(curr->isTee() ? flow.value.type == curr->type : true);
817 scope.locals[index] = flow.value;
818 return curr->isTee() ? flow : Flow();
819 }
820
821 Flow visitGetGlobal(GetGlobal *curr) {
822 NOTE_ENTER("GetGlobal");
823 auto name = curr->name;
824 NOTE_EVAL1(name);
825 assert(instance.globals.find(name) != instance.globals.end());
826 NOTE_EVAL1(instance.globals[name]);
827 return instance.globals[name];
828 }
829 Flow visitSetGlobal(SetGlobal *curr) {
830 NOTE_ENTER("SetGlobal");
831 auto name = curr->name;
832 Flow flow = this->visit(curr->value);
833 if (flow.breaking()) return flow;
834 NOTE_EVAL1(name);
835 NOTE_EVAL1(flow.value);
836 instance.globals[name] = flow.value;
837 return Flow();
838 }
839
840 Flow visitLoad(Load *curr) {
841 NOTE_ENTER("Load");
842 Flow flow = this->visit(curr->ptr);
843 if (flow.breaking()) return flow;
844 NOTE_EVAL1(flow);
845 auto addr = instance.getFinalAddress(curr, flow.value);
846 auto ret = instance.externalInterface->load(curr, addr);
847 NOTE_EVAL1(addr);
848 NOTE_EVAL1(ret);
849 return ret;
850 }
851 Flow visitStore(Store *curr) {
852 NOTE_ENTER("Store");
853 Flow ptr = this->visit(curr->ptr);
854 if (ptr.breaking()) return ptr;
855 Flow value = this->visit(curr->value);
856 if (value.breaking()) return value;
857 auto addr = instance.getFinalAddress(curr, ptr.value);
858 NOTE_EVAL1(addr);
859 NOTE_EVAL1(value);
860 instance.externalInterface->store(curr, addr, value.value);
861 return Flow();
862 }
863
864 Flow visitAtomicRMW(AtomicRMW *curr) {
865 NOTE_ENTER("AtomicRMW");
866 Flow ptr = this->visit(curr->ptr);
867 if (ptr.breaking()) return ptr;
868 auto value = this->visit(curr->value);
869 if (value.breaking()) return value;
870 NOTE_EVAL1(ptr);
871 auto addr = instance.getFinalAddress(curr, ptr.value);
872 NOTE_EVAL1(addr);
873 NOTE_EVAL1(value);
874 auto loaded = instance.doAtomicLoad(addr, curr->bytes, curr->type);
875 NOTE_EVAL1(loaded);
876 auto computed = value.value;
877 switch (curr->op) {
878 case Add: computed = computed.add(value.value); break;
879 case Sub: computed = computed.sub(value.value); break;
880 case And: computed = computed.and_(value.value); break;
881 case Or: computed = computed.or_(value.value); break;
882 case Xor: computed = computed.xor_(value.value); break;
883 case Xchg: computed = value.value; break;
884 default: WASM_UNREACHABLE();
885 }
886 instance.doAtomicStore(addr, curr->bytes, computed);
887 return loaded;
888 }
889 Flow visitAtomicCmpxchg(AtomicCmpxchg *curr) {
890 NOTE_ENTER("AtomicCmpxchg");
891 Flow ptr = this->visit(curr->ptr);
892 if (ptr.breaking()) return ptr;
893 NOTE_EVAL1(ptr);
894 auto expected = this->visit(curr->expected);
895 if (expected.breaking()) return expected;
896 auto replacement = this->visit(curr->replacement);
897 if (replacement.breaking()) return replacement;
898 auto addr = instance.getFinalAddress(curr, ptr.value);
899 NOTE_EVAL1(addr);
900 NOTE_EVAL1(expected);
901 NOTE_EVAL1(replacement);
902 auto loaded = instance.doAtomicLoad(addr, curr->bytes, curr->type);
903 NOTE_EVAL1(loaded);
904 if (loaded == expected.value) {
905 instance.doAtomicStore(addr, curr->bytes, replacement.value);
906 }
907 return loaded;
908 }
909 Flow visitAtomicWait(AtomicWait *curr) {
910 NOTE_ENTER("AtomicWait");
911 Flow ptr = this->visit(curr->ptr);
912 if (ptr.breaking()) return ptr;
913 NOTE_EVAL1(ptr);
914 auto expected = this->visit(curr->expected);
915 NOTE_EVAL1(expected);
916 if (expected.breaking()) return expected;
917 auto timeout = this->visit(curr->timeout);
918 NOTE_EVAL1(timeout);
919 if (timeout.breaking()) return timeout;
920 auto bytes = getWasmTypeSize(curr->expectedType);
921 auto addr = instance.getFinalAddress(ptr.value, bytes);
922 auto loaded = instance.doAtomicLoad(addr, bytes, curr->expectedType);
923 NOTE_EVAL1(loaded);
924 if (loaded != expected.value) {
925 return Literal(int32_t(1)); // not equal
926 }
927 // TODO: add threads support!
928 // for now, just assume we are woken up
929 return Literal(int32_t(0)); // woken up
930 }
931 Flow visitAtomicWake(AtomicWake *curr) {
932 NOTE_ENTER("AtomicWake");
933 Flow ptr = this->visit(curr->ptr);
934 if (ptr.breaking()) return ptr;
935 NOTE_EVAL1(ptr);
936 auto count = this->visit(curr->wakeCount);
937 NOTE_EVAL1(count);
938 if (count.breaking()) return count;
939 // TODO: add threads support!
940 return Literal(int32_t(0)); // none woken up
941 }
942
943 Flow visitHost(Host *curr) {
944 NOTE_ENTER("Host");
945 switch (curr->op) {
946 case PageSize: return Literal((int32_t)Memory::kPageSize);
947 case CurrentMemory: return Literal(int32_t(instance.memorySize));
948 case GrowMemory: {
949 auto fail = Literal(int32_t(-1));
950 Flow flow = this->visit(curr->operands[0]);
951 if (flow.breaking()) return flow;
952 int32_t ret = instance.memorySize;
953 uint32_t delta = flow.value.geti32();
954 if (delta > uint32_t(-1) /Memory::kPageSize) return fail;
955 if (instance.memorySize >= uint32_t(-1) - delta) return fail;
956 uint32_t newSize = instance.memorySize + delta;
957 if (newSize > instance.wasm.memory.max) return fail;
958 instance.externalInterface->growMemory(instance.memorySize * Memory::kPageSize, newSize * Memory::kPageSize);
959 instance.memorySize = newSize;
960 return Literal(int32_t(ret));
961 }
962 case HasFeature: {
963 Name id = curr->nameOperand;
964 if (id == WASM) return Literal(1);
965 return Literal((int32_t)0);
966 }
967 default: WASM_UNREACHABLE();
968 }
969 }
970
971 void trap(const char* why) override {
972 instance.externalInterface->trap(why);
973 }
974 };
975
976 if (callDepth > maxCallDepth) externalInterface->trap("stack limit");
977 auto previousCallDepth = callDepth;
978 callDepth++;
979 auto previousFunctionStackSize = functionStack.size();
980 functionStack.push_back(name);
981
982 Function *function = wasm.getFunction(name);
983 assert(function);
984 FunctionScope scope(function, arguments);
985
986 #ifdef WASM_INTERPRETER_DEBUG
987 std::cout << "entering " << function->name
988 << "\n with arguments:\n";
989 for (unsigned i = 0; i < arguments.size(); ++i) {
990 std::cout << " $" << i << ": " << arguments[i] << '\n';
991 }
992 #endif
993
994 Flow flow = RuntimeExpressionRunner(*this, scope).visit(function->body);
995 assert(!flow.breaking() || flow.breakTo == RETURN_FLOW); // cannot still be breaking, it means we missed our stop
996 Literal ret = flow.value;
997 if (function->result != ret.type) {
998 std::cerr << "calling " << function->name << " resulted in " << ret << " but the function type is " << function->result << '\n';
999 WASM_UNREACHABLE();
1000 }
1001 callDepth = previousCallDepth; // may decrease more than one, if we jumped up the stack
1002 // if we jumped up the stack, we also need to pop higher frames
1003 while (functionStack.size() > previousFunctionStackSize) {
1004 functionStack.pop_back();
1005 }
1006 #ifdef WASM_INTERPRETER_DEBUG
1007 std::cout << "exiting " << function->name << " with " << ret << '\n';
1008 #endif
1009 return ret;
1010 }
1011
1012 protected:
1013
1014 Address memorySize; // in pages
1015
1016 void trapIfGt(uint64_t lhs, uint64_t rhs, const char* msg) {
1017 if (lhs > rhs) {
1018 std::stringstream ss;
1019 ss << msg << ": " << lhs << " > " << rhs;
1020 externalInterface->trap(ss.str().c_str());
1021 }
1022 }
1023
1024 template <class LS>
1025 Address getFinalAddress(LS* curr, Literal ptr) {
1026 Address memorySizeBytes = memorySize * Memory::kPageSize;
1027 uint64_t addr = ptr.type == i32 ? ptr.geti32() : ptr.geti64();
1028 trapIfGt(curr->offset, memorySizeBytes, "offset > memory");
1029 trapIfGt(addr, memorySizeBytes - curr->offset, "final > memory");
1030 addr += curr->offset;
1031 trapIfGt(curr->bytes, memorySizeBytes, "bytes > memory");
1032 checkLoadAddress(addr, curr->bytes);
1033 return addr;
1034 }
1035
1036 Address getFinalAddress(Literal ptr, Index bytes) {
1037 Address memorySizeBytes = memorySize * Memory::kPageSize;
1038 uint64_t addr = ptr.type == i32 ? ptr.geti32() : ptr.geti64();
1039 trapIfGt(addr, memorySizeBytes - bytes, "highest > memory");
1040 return addr;
1041 }
1042
1043 void checkLoadAddress(Address addr, Index bytes) {
1044 Address memorySizeBytes = memorySize * Memory::kPageSize;
1045 trapIfGt(addr, memorySizeBytes - bytes, "highest > memory");
1046 }
1047
1048 Literal doAtomicLoad(Address addr, Index bytes, WasmType type) {
1049 checkLoadAddress(addr, bytes);
1050 Const ptr;
1051 ptr.value = Literal(int32_t(addr));
1052 ptr.type = i32;
1053 Load load;
1054 load.bytes = bytes;
1055 load.signed_ = true;
1056 load.align = bytes;
1057 load.isAtomic = true; // understatement
1058 load.ptr = &ptr;
1059 load.type = type;
1060 return externalInterface->load(&load, addr);
1061 }
1062
1063 void doAtomicStore(Address addr, Index bytes, Literal toStore) {
1064 Const ptr;
1065 ptr.value = Literal(int32_t(addr));
1066 ptr.type = i32;
1067 Const value;
1068 value.value = toStore;
1069 value.type = toStore.type;
1070 Store store;
1071 store.bytes = bytes;
1072 store.align = bytes;
1073 store.isAtomic = true; // understatement
1074 store.ptr = &ptr;
1075 store.value = &value;
1076 store.valueType = value.type;
1077 return externalInterface->store(&store, addr, toStore);
1078 }
1079
1080 ExternalInterface* externalInterface;
1081 };
1082
1083 // The default ModuleInstance uses a trivial global manager
1084 typedef std::map<Name, Literal> TrivialGlobalManager;
1085 class ModuleInstance : public ModuleInstanceBase<TrivialGlobalManager, ModuleInstance> {
1086 public:
1087 ModuleInstance(Module& wasm, ExternalInterface* externalInterface) : ModuleInstanceBase(wasm, externalInterface) {}
1088 };
1089
1090 } // namespace wasm
1091
1092 #endif // wasm_wasm_interpreter_h