OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/wasm/wasm-interpreter.h" | 5 #include "src/wasm/wasm-interpreter.h" |
6 | 6 |
7 #include "src/utils.h" | 7 #include "src/utils.h" |
8 #include "src/wasm/ast-decoder.h" | 8 #include "src/wasm/ast-decoder.h" |
9 #include "src/wasm/decoder.h" | 9 #include "src/wasm/decoder.h" |
10 #include "src/wasm/wasm-external-refs.h" | 10 #include "src/wasm/wasm-external-refs.h" |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
55 V(I64Ne, uint64_t, !=) \ | 55 V(I64Ne, uint64_t, !=) \ |
56 V(I64LtU, uint64_t, <) \ | 56 V(I64LtU, uint64_t, <) \ |
57 V(I64LeU, uint64_t, <=) \ | 57 V(I64LeU, uint64_t, <=) \ |
58 V(I64GtU, uint64_t, >) \ | 58 V(I64GtU, uint64_t, >) \ |
59 V(I64GeU, uint64_t, >=) \ | 59 V(I64GeU, uint64_t, >=) \ |
60 V(I64LtS, int64_t, <) \ | 60 V(I64LtS, int64_t, <) \ |
61 V(I64LeS, int64_t, <=) \ | 61 V(I64LeS, int64_t, <=) \ |
62 V(I64GtS, int64_t, >) \ | 62 V(I64GtS, int64_t, >) \ |
63 V(I64GeS, int64_t, >=) \ | 63 V(I64GeS, int64_t, >=) \ |
64 V(F32Add, float, +) \ | 64 V(F32Add, float, +) \ |
65 V(F32Mul, float, *) \ | |
66 V(F32Div, float, /) \ | |
67 V(F32Eq, float, ==) \ | 65 V(F32Eq, float, ==) \ |
68 V(F32Ne, float, !=) \ | 66 V(F32Ne, float, !=) \ |
69 V(F32Lt, float, <) \ | 67 V(F32Lt, float, <) \ |
70 V(F32Le, float, <=) \ | 68 V(F32Le, float, <=) \ |
71 V(F32Gt, float, >) \ | 69 V(F32Gt, float, >) \ |
72 V(F32Ge, float, >=) \ | 70 V(F32Ge, float, >=) \ |
73 V(F64Add, double, +) \ | 71 V(F64Add, double, +) \ |
74 V(F64Mul, double, *) \ | |
75 V(F64Div, double, /) \ | |
76 V(F64Eq, double, ==) \ | 72 V(F64Eq, double, ==) \ |
77 V(F64Ne, double, !=) \ | 73 V(F64Ne, double, !=) \ |
78 V(F64Lt, double, <) \ | 74 V(F64Lt, double, <) \ |
79 V(F64Le, double, <=) \ | 75 V(F64Le, double, <=) \ |
80 V(F64Gt, double, >) \ | 76 V(F64Gt, double, >) \ |
81 V(F64Ge, double, >=) | 77 V(F64Ge, double, >=) |
82 | 78 |
| 79 #define FOREACH_SIMPLE_BINOP_NAN(V) \ |
| 80 V(F32Mul, float, *) \ |
| 81 V(F64Mul, double, *) \ |
| 82 V(F32Div, float, /) \ |
| 83 V(F64Div, double, /) |
| 84 |
83 #define FOREACH_OTHER_BINOP(V) \ | 85 #define FOREACH_OTHER_BINOP(V) \ |
84 V(I32DivS, int32_t) \ | 86 V(I32DivS, int32_t) \ |
85 V(I32DivU, uint32_t) \ | 87 V(I32DivU, uint32_t) \ |
86 V(I32RemS, int32_t) \ | 88 V(I32RemS, int32_t) \ |
87 V(I32RemU, uint32_t) \ | 89 V(I32RemU, uint32_t) \ |
88 V(I32Shl, uint32_t) \ | 90 V(I32Shl, uint32_t) \ |
89 V(I32ShrU, uint32_t) \ | 91 V(I32ShrU, uint32_t) \ |
90 V(I32ShrS, int32_t) \ | 92 V(I32ShrS, int32_t) \ |
91 V(I64DivS, int64_t) \ | 93 V(I64DivS, int64_t) \ |
92 V(I64DivU, uint64_t) \ | 94 V(I64DivU, uint64_t) \ |
(...skipping 27 matching lines...) Expand all Loading... |
120 V(I64Clz, uint64_t) \ | 122 V(I64Clz, uint64_t) \ |
121 V(I64Ctz, uint64_t) \ | 123 V(I64Ctz, uint64_t) \ |
122 V(I64Popcnt, uint64_t) \ | 124 V(I64Popcnt, uint64_t) \ |
123 V(I64Eqz, uint64_t) \ | 125 V(I64Eqz, uint64_t) \ |
124 V(F32Abs, float) \ | 126 V(F32Abs, float) \ |
125 V(F32Neg, float) \ | 127 V(F32Neg, float) \ |
126 V(F32Ceil, float) \ | 128 V(F32Ceil, float) \ |
127 V(F32Floor, float) \ | 129 V(F32Floor, float) \ |
128 V(F32Trunc, float) \ | 130 V(F32Trunc, float) \ |
129 V(F32NearestInt, float) \ | 131 V(F32NearestInt, float) \ |
130 V(F32Sqrt, float) \ | |
131 V(F64Abs, double) \ | 132 V(F64Abs, double) \ |
132 V(F64Neg, double) \ | 133 V(F64Neg, double) \ |
133 V(F64Ceil, double) \ | 134 V(F64Ceil, double) \ |
134 V(F64Floor, double) \ | 135 V(F64Floor, double) \ |
135 V(F64Trunc, double) \ | 136 V(F64Trunc, double) \ |
136 V(F64NearestInt, double) \ | 137 V(F64NearestInt, double) \ |
137 V(F64Sqrt, double) \ | |
138 V(I32SConvertF32, float) \ | 138 V(I32SConvertF32, float) \ |
139 V(I32SConvertF64, double) \ | 139 V(I32SConvertF64, double) \ |
140 V(I32UConvertF32, float) \ | 140 V(I32UConvertF32, float) \ |
141 V(I32UConvertF64, double) \ | 141 V(I32UConvertF64, double) \ |
142 V(I32ConvertI64, int64_t) \ | 142 V(I32ConvertI64, int64_t) \ |
143 V(I64SConvertF32, float) \ | 143 V(I64SConvertF32, float) \ |
144 V(I64SConvertF64, double) \ | 144 V(I64SConvertF64, double) \ |
145 V(I64UConvertF32, float) \ | 145 V(I64UConvertF32, float) \ |
146 V(I64UConvertF64, double) \ | 146 V(I64UConvertF64, double) \ |
147 V(I64SConvertI32, int32_t) \ | 147 V(I64SConvertI32, int32_t) \ |
(...skipping 10 matching lines...) Expand all Loading... |
158 V(F64UConvertI64, uint64_t) \ | 158 V(F64UConvertI64, uint64_t) \ |
159 V(F64ConvertF32, float) \ | 159 V(F64ConvertF32, float) \ |
160 V(F64ReinterpretI64, int64_t) \ | 160 V(F64ReinterpretI64, int64_t) \ |
161 V(I32ReinterpretF32, float) \ | 161 V(I32ReinterpretF32, float) \ |
162 V(I64ReinterpretF64, double) \ | 162 V(I64ReinterpretF64, double) \ |
163 V(I32AsmjsSConvertF32, float) \ | 163 V(I32AsmjsSConvertF32, float) \ |
164 V(I32AsmjsUConvertF32, float) \ | 164 V(I32AsmjsUConvertF32, float) \ |
165 V(I32AsmjsSConvertF64, double) \ | 165 V(I32AsmjsSConvertF64, double) \ |
166 V(I32AsmjsUConvertF64, double) | 166 V(I32AsmjsUConvertF64, double) |
167 | 167 |
| 168 #define FOREACH_OTHER_UNOP_NAN(V) \ |
| 169 V(F32Sqrt, float) \ |
| 170 V(F64Sqrt, double) |
| 171 |
168 static inline int32_t ExecuteI32DivS(int32_t a, int32_t b, TrapReason* trap) { | 172 static inline int32_t ExecuteI32DivS(int32_t a, int32_t b, TrapReason* trap) { |
169 if (b == 0) { | 173 if (b == 0) { |
170 *trap = kTrapDivByZero; | 174 *trap = kTrapDivByZero; |
171 return 0; | 175 return 0; |
172 } | 176 } |
173 if (b == -1 && a == std::numeric_limits<int32_t>::min()) { | 177 if (b == -1 && a == std::numeric_limits<int32_t>::min()) { |
174 *trap = kTrapDivUnrepresentable; | 178 *trap = kTrapDivUnrepresentable; |
175 return 0; | 179 return 0; |
176 } | 180 } |
177 return a / b; | 181 return a / b; |
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
453 | 457 |
454 static inline float ExecuteF32Trunc(float a, TrapReason* trap) { | 458 static inline float ExecuteF32Trunc(float a, TrapReason* trap) { |
455 return truncf(a); | 459 return truncf(a); |
456 } | 460 } |
457 | 461 |
458 static inline float ExecuteF32NearestInt(float a, TrapReason* trap) { | 462 static inline float ExecuteF32NearestInt(float a, TrapReason* trap) { |
459 return nearbyintf(a); | 463 return nearbyintf(a); |
460 } | 464 } |
461 | 465 |
462 static inline float ExecuteF32Sqrt(float a, TrapReason* trap) { | 466 static inline float ExecuteF32Sqrt(float a, TrapReason* trap) { |
463 return sqrtf(a); | 467 float result = sqrtf(a); |
| 468 return result; |
464 } | 469 } |
465 | 470 |
466 static inline double ExecuteF64Abs(double a, TrapReason* trap) { | 471 static inline double ExecuteF64Abs(double a, TrapReason* trap) { |
467 return bit_cast<double>(bit_cast<uint64_t>(a) & 0x7fffffffffffffff); | 472 return bit_cast<double>(bit_cast<uint64_t>(a) & 0x7fffffffffffffff); |
468 } | 473 } |
469 | 474 |
470 static inline double ExecuteF64Neg(double a, TrapReason* trap) { | 475 static inline double ExecuteF64Neg(double a, TrapReason* trap) { |
471 return bit_cast<double>(bit_cast<uint64_t>(a) ^ 0x8000000000000000); | 476 return bit_cast<double>(bit_cast<uint64_t>(a) ^ 0x8000000000000000); |
472 } | 477 } |
473 | 478 |
(...skipping 494 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
968 class ThreadImpl : public WasmInterpreter::Thread { | 973 class ThreadImpl : public WasmInterpreter::Thread { |
969 public: | 974 public: |
970 ThreadImpl(Zone* zone, CodeMap* codemap, WasmInstance* instance) | 975 ThreadImpl(Zone* zone, CodeMap* codemap, WasmInstance* instance) |
971 : codemap_(codemap), | 976 : codemap_(codemap), |
972 instance_(instance), | 977 instance_(instance), |
973 stack_(zone), | 978 stack_(zone), |
974 frames_(zone), | 979 frames_(zone), |
975 blocks_(zone), | 980 blocks_(zone), |
976 state_(WasmInterpreter::STOPPED), | 981 state_(WasmInterpreter::STOPPED), |
977 break_pc_(kInvalidPc), | 982 break_pc_(kInvalidPc), |
978 trap_reason_(kTrapCount) {} | 983 trap_reason_(kTrapCount), |
| 984 possible_nondeterminism_(false) {} |
979 | 985 |
980 virtual ~ThreadImpl() {} | 986 virtual ~ThreadImpl() {} |
981 | 987 |
982 //========================================================================== | 988 //========================================================================== |
983 // Implementation of public interface for WasmInterpreter::Thread. | 989 // Implementation of public interface for WasmInterpreter::Thread. |
984 //========================================================================== | 990 //========================================================================== |
985 | 991 |
986 virtual WasmInterpreter::State state() { return state_; } | 992 virtual WasmInterpreter::State state() { return state_; } |
987 | 993 |
988 virtual void PushFrame(const WasmFunction* function, WasmVal* args) { | 994 virtual void PushFrame(const WasmFunction* function, WasmVal* args) { |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1023 } | 1029 } |
1024 | 1030 |
1025 virtual void Pause() { UNIMPLEMENTED(); } | 1031 virtual void Pause() { UNIMPLEMENTED(); } |
1026 | 1032 |
1027 virtual void Reset() { | 1033 virtual void Reset() { |
1028 TRACE("----- RESET -----\n"); | 1034 TRACE("----- RESET -----\n"); |
1029 stack_.clear(); | 1035 stack_.clear(); |
1030 frames_.clear(); | 1036 frames_.clear(); |
1031 state_ = WasmInterpreter::STOPPED; | 1037 state_ = WasmInterpreter::STOPPED; |
1032 trap_reason_ = kTrapCount; | 1038 trap_reason_ = kTrapCount; |
| 1039 possible_nondeterminism_ = false; |
1033 } | 1040 } |
1034 | 1041 |
1035 virtual int GetFrameCount() { return static_cast<int>(frames_.size()); } | 1042 virtual int GetFrameCount() { return static_cast<int>(frames_.size()); } |
1036 | 1043 |
1037 virtual const WasmFrame* GetFrame(int index) { | 1044 virtual const WasmFrame* GetFrame(int index) { |
1038 UNIMPLEMENTED(); | 1045 UNIMPLEMENTED(); |
1039 return nullptr; | 1046 return nullptr; |
1040 } | 1047 } |
1041 | 1048 |
1042 virtual WasmFrame* GetMutableFrame(int index) { | 1049 virtual WasmFrame* GetMutableFrame(int index) { |
1043 UNIMPLEMENTED(); | 1050 UNIMPLEMENTED(); |
1044 return nullptr; | 1051 return nullptr; |
1045 } | 1052 } |
1046 | 1053 |
1047 virtual WasmVal GetReturnValue(int index) { | 1054 virtual WasmVal GetReturnValue(int index) { |
1048 if (state_ == WasmInterpreter::TRAPPED) return WasmVal(0xdeadbeef); | 1055 if (state_ == WasmInterpreter::TRAPPED) return WasmVal(0xdeadbeef); |
1049 CHECK_EQ(WasmInterpreter::FINISHED, state_); | 1056 CHECK_EQ(WasmInterpreter::FINISHED, state_); |
1050 CHECK_LT(static_cast<size_t>(index), stack_.size()); | 1057 CHECK_LT(static_cast<size_t>(index), stack_.size()); |
1051 return stack_[index]; | 1058 return stack_[index]; |
1052 } | 1059 } |
1053 | 1060 |
1054 virtual pc_t GetBreakpointPc() { return break_pc_; } | 1061 virtual pc_t GetBreakpointPc() { return break_pc_; } |
1055 | 1062 |
| 1063 virtual bool PossibleNondeterminism() { return possible_nondeterminism_; } |
| 1064 |
1056 bool Terminated() { | 1065 bool Terminated() { |
1057 return state_ == WasmInterpreter::TRAPPED || | 1066 return state_ == WasmInterpreter::TRAPPED || |
1058 state_ == WasmInterpreter::FINISHED; | 1067 state_ == WasmInterpreter::FINISHED; |
1059 } | 1068 } |
1060 | 1069 |
1061 private: | 1070 private: |
1062 // Entries on the stack of functions being evaluated. | 1071 // Entries on the stack of functions being evaluated. |
1063 struct Frame { | 1072 struct Frame { |
1064 InterpreterCode* code; | 1073 InterpreterCode* code; |
1065 pc_t call_pc; | 1074 pc_t call_pc; |
(...skipping 14 matching lines...) Expand all Loading... |
1080 }; | 1089 }; |
1081 | 1090 |
1082 CodeMap* codemap_; | 1091 CodeMap* codemap_; |
1083 WasmInstance* instance_; | 1092 WasmInstance* instance_; |
1084 ZoneVector<WasmVal> stack_; | 1093 ZoneVector<WasmVal> stack_; |
1085 ZoneVector<Frame> frames_; | 1094 ZoneVector<Frame> frames_; |
1086 ZoneVector<Block> blocks_; | 1095 ZoneVector<Block> blocks_; |
1087 WasmInterpreter::State state_; | 1096 WasmInterpreter::State state_; |
1088 pc_t break_pc_; | 1097 pc_t break_pc_; |
1089 TrapReason trap_reason_; | 1098 TrapReason trap_reason_; |
| 1099 bool possible_nondeterminism_; |
1090 | 1100 |
1091 CodeMap* codemap() { return codemap_; } | 1101 CodeMap* codemap() { return codemap_; } |
1092 WasmInstance* instance() { return instance_; } | 1102 WasmInstance* instance() { return instance_; } |
1093 const WasmModule* module() { return instance_->module; } | 1103 const WasmModule* module() { return instance_->module; } |
1094 | 1104 |
1095 void DoTrap(TrapReason trap, pc_t pc) { | 1105 void DoTrap(TrapReason trap, pc_t pc) { |
1096 state_ = WasmInterpreter::TRAPPED; | 1106 state_ = WasmInterpreter::TRAPPED; |
1097 trap_reason_ = trap; | 1107 trap_reason_ = trap; |
1098 CommitPc(pc); | 1108 CommitPc(pc); |
1099 } | 1109 } |
(...skipping 495 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1595 case kExpr##name: { \ | 1605 case kExpr##name: { \ |
1596 WasmVal rval = Pop(); \ | 1606 WasmVal rval = Pop(); \ |
1597 WasmVal lval = Pop(); \ | 1607 WasmVal lval = Pop(); \ |
1598 WasmVal result(lval.to<ctype>() op rval.to<ctype>()); \ | 1608 WasmVal result(lval.to<ctype>() op rval.to<ctype>()); \ |
1599 Push(pc, result); \ | 1609 Push(pc, result); \ |
1600 break; \ | 1610 break; \ |
1601 } | 1611 } |
1602 FOREACH_SIMPLE_BINOP(EXECUTE_SIMPLE_BINOP) | 1612 FOREACH_SIMPLE_BINOP(EXECUTE_SIMPLE_BINOP) |
1603 #undef EXECUTE_SIMPLE_BINOP | 1613 #undef EXECUTE_SIMPLE_BINOP |
1604 | 1614 |
| 1615 #define EXECUTE_SIMPLE_BINOP_NAN(name, ctype, op) \ |
| 1616 case kExpr##name: { \ |
| 1617 WasmVal rval = Pop(); \ |
| 1618 WasmVal lval = Pop(); \ |
| 1619 ctype result = lval.to<ctype>() op rval.to<ctype>(); \ |
| 1620 possible_nondeterminism_ |= std::isnan(result); \ |
| 1621 WasmVal result_val(result); \ |
| 1622 Push(pc, result_val); \ |
| 1623 break; \ |
| 1624 } |
| 1625 FOREACH_SIMPLE_BINOP_NAN(EXECUTE_SIMPLE_BINOP_NAN) |
| 1626 #undef EXECUTE_SIMPLE_BINOP_NAN |
| 1627 |
1605 #define EXECUTE_OTHER_BINOP(name, ctype) \ | 1628 #define EXECUTE_OTHER_BINOP(name, ctype) \ |
1606 case kExpr##name: { \ | 1629 case kExpr##name: { \ |
1607 TrapReason trap = kTrapCount; \ | 1630 TrapReason trap = kTrapCount; \ |
1608 volatile ctype rval = Pop().to<ctype>(); \ | 1631 volatile ctype rval = Pop().to<ctype>(); \ |
1609 volatile ctype lval = Pop().to<ctype>(); \ | 1632 volatile ctype lval = Pop().to<ctype>(); \ |
1610 WasmVal result(Execute##name(lval, rval, &trap)); \ | 1633 WasmVal result(Execute##name(lval, rval, &trap)); \ |
1611 if (trap != kTrapCount) return DoTrap(trap, pc); \ | 1634 if (trap != kTrapCount) return DoTrap(trap, pc); \ |
1612 Push(pc, result); \ | 1635 Push(pc, result); \ |
1613 break; \ | 1636 break; \ |
1614 } | 1637 } |
1615 FOREACH_OTHER_BINOP(EXECUTE_OTHER_BINOP) | 1638 FOREACH_OTHER_BINOP(EXECUTE_OTHER_BINOP) |
1616 #undef EXECUTE_OTHER_BINOP | 1639 #undef EXECUTE_OTHER_BINOP |
1617 | 1640 |
1618 #define EXECUTE_OTHER_UNOP(name, ctype) \ | 1641 #define EXECUTE_OTHER_UNOP(name, ctype) \ |
1619 case kExpr##name: { \ | 1642 case kExpr##name: { \ |
1620 TrapReason trap = kTrapCount; \ | 1643 TrapReason trap = kTrapCount; \ |
1621 volatile ctype val = Pop().to<ctype>(); \ | 1644 volatile ctype val = Pop().to<ctype>(); \ |
1622 WasmVal result(Execute##name(val, &trap)); \ | 1645 WasmVal result(Execute##name(val, &trap)); \ |
1623 if (trap != kTrapCount) return DoTrap(trap, pc); \ | 1646 if (trap != kTrapCount) return DoTrap(trap, pc); \ |
1624 Push(pc, result); \ | 1647 Push(pc, result); \ |
1625 break; \ | 1648 break; \ |
1626 } | 1649 } |
1627 FOREACH_OTHER_UNOP(EXECUTE_OTHER_UNOP) | 1650 FOREACH_OTHER_UNOP(EXECUTE_OTHER_UNOP) |
1628 #undef EXECUTE_OTHER_UNOP | 1651 #undef EXECUTE_OTHER_UNOP |
1629 | 1652 |
| 1653 #define EXECUTE_OTHER_UNOP_NAN(name, ctype) \ |
| 1654 case kExpr##name: { \ |
| 1655 TrapReason trap = kTrapCount; \ |
| 1656 volatile ctype val = Pop().to<ctype>(); \ |
| 1657 ctype result = Execute##name(val, &trap); \ |
| 1658 possible_nondeterminism_ |= std::isnan(result); \ |
| 1659 WasmVal result_val(result); \ |
| 1660 if (trap != kTrapCount) return DoTrap(trap, pc); \ |
| 1661 Push(pc, result_val); \ |
| 1662 break; \ |
| 1663 } |
| 1664 FOREACH_OTHER_UNOP_NAN(EXECUTE_OTHER_UNOP_NAN) |
| 1665 #undef EXECUTE_OTHER_UNOP_NAN |
| 1666 |
1630 default: | 1667 default: |
1631 V8_Fatal(__FILE__, __LINE__, "Unknown or unimplemented opcode #%d:%s", | 1668 V8_Fatal(__FILE__, __LINE__, "Unknown or unimplemented opcode #%d:%s", |
1632 code->start[pc], OpcodeName(code->start[pc])); | 1669 code->start[pc], OpcodeName(code->start[pc])); |
1633 UNREACHABLE(); | 1670 UNREACHABLE(); |
1634 } | 1671 } |
1635 | 1672 |
1636 pc += len; | 1673 pc += len; |
1637 } | 1674 } |
1638 UNREACHABLE(); // above decoding loop should run forever. | 1675 UNREACHABLE(); // above decoding loop should run forever. |
1639 } | 1676 } |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1844 | 1881 |
1845 ControlTransferMap WasmInterpreter::ComputeControlTransfersForTesting( | 1882 ControlTransferMap WasmInterpreter::ComputeControlTransfersForTesting( |
1846 Zone* zone, const byte* start, const byte* end) { | 1883 Zone* zone, const byte* start, const byte* end) { |
1847 ControlTransfers targets(zone, nullptr, nullptr, start, end); | 1884 ControlTransfers targets(zone, nullptr, nullptr, start, end); |
1848 return targets.map_; | 1885 return targets.map_; |
1849 } | 1886 } |
1850 | 1887 |
1851 } // namespace wasm | 1888 } // namespace wasm |
1852 } // namespace internal | 1889 } // namespace internal |
1853 } // namespace v8 | 1890 } // namespace v8 |
OLD | NEW |