Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(148)

Side by Side Diff: src/wasm/wasm-interpreter.cc

Issue 2438603003: [wasm] Track in the interpreter if a NaN could have been produced. (Closed)
Patch Set: Fixed nits. Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/wasm/wasm-interpreter.h ('k') | test/cctest/wasm/test-run-wasm-interpreter.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/wasm/wasm-interpreter.h ('k') | test/cctest/wasm/test-run-wasm-interpreter.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698