Chromium Code Reviews| 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 <type_traits> | |
| 6 | |
| 5 #include "src/wasm/wasm-interpreter.h" | 7 #include "src/wasm/wasm-interpreter.h" |
| 6 | 8 |
| 7 #include "src/utils.h" | 9 #include "src/utils.h" |
| 8 #include "src/wasm/decoder.h" | 10 #include "src/wasm/decoder.h" |
| 9 #include "src/wasm/function-body-decoder.h" | 11 #include "src/wasm/function-body-decoder.h" |
| 10 #include "src/wasm/wasm-external-refs.h" | 12 #include "src/wasm/wasm-external-refs.h" |
| 11 #include "src/wasm/wasm-limits.h" | 13 #include "src/wasm/wasm-limits.h" |
| 12 #include "src/wasm/wasm-module.h" | 14 #include "src/wasm/wasm-module.h" |
| 13 | 15 |
| 14 #include "src/zone/accounting-allocator.h" | 16 #include "src/zone/accounting-allocator.h" |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 70 V(F32Le, float, <=) \ | 72 V(F32Le, float, <=) \ |
| 71 V(F32Gt, float, >) \ | 73 V(F32Gt, float, >) \ |
| 72 V(F32Ge, float, >=) \ | 74 V(F32Ge, float, >=) \ |
| 73 V(F64Add, double, +) \ | 75 V(F64Add, double, +) \ |
| 74 V(F64Sub, double, -) \ | 76 V(F64Sub, double, -) \ |
| 75 V(F64Eq, double, ==) \ | 77 V(F64Eq, double, ==) \ |
| 76 V(F64Ne, double, !=) \ | 78 V(F64Ne, double, !=) \ |
| 77 V(F64Lt, double, <) \ | 79 V(F64Lt, double, <) \ |
| 78 V(F64Le, double, <=) \ | 80 V(F64Le, double, <=) \ |
| 79 V(F64Gt, double, >) \ | 81 V(F64Gt, double, >) \ |
| 80 V(F64Ge, double, >=) | 82 V(F64Ge, double, >=) \ |
| 81 | 83 V(F32Mul, float, *) \ |
| 82 #define FOREACH_SIMPLE_BINOP_NAN(V) \ | 84 V(F64Mul, double, *) \ |
| 83 V(F32Mul, float, *) \ | 85 V(F32Div, float, /) \ |
| 84 V(F64Mul, double, *) \ | |
| 85 V(F32Div, float, /) \ | |
| 86 V(F64Div, double, /) | 86 V(F64Div, double, /) |
| 87 | 87 |
| 88 #define FOREACH_OTHER_BINOP(V) \ | 88 #define FOREACH_OTHER_BINOP(V) \ |
| 89 V(I32DivS, int32_t) \ | 89 V(I32DivS, int32_t) \ |
| 90 V(I32DivU, uint32_t) \ | 90 V(I32DivU, uint32_t) \ |
| 91 V(I32RemS, int32_t) \ | 91 V(I32RemS, int32_t) \ |
| 92 V(I32RemU, uint32_t) \ | 92 V(I32RemU, uint32_t) \ |
| 93 V(I32Shl, uint32_t) \ | 93 V(I32Shl, uint32_t) \ |
| 94 V(I32ShrU, uint32_t) \ | 94 V(I32ShrU, uint32_t) \ |
| 95 V(I32ShrS, int32_t) \ | 95 V(I32ShrS, int32_t) \ |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 155 V(F32ReinterpretI32, int32_t) \ | 155 V(F32ReinterpretI32, int32_t) \ |
| 156 V(F64SConvertI32, int32_t) \ | 156 V(F64SConvertI32, int32_t) \ |
| 157 V(F64UConvertI32, uint32_t) \ | 157 V(F64UConvertI32, uint32_t) \ |
| 158 V(F64SConvertI64, int64_t) \ | 158 V(F64SConvertI64, int64_t) \ |
| 159 V(F64UConvertI64, uint64_t) \ | 159 V(F64UConvertI64, uint64_t) \ |
| 160 V(F64ConvertF32, float) \ | 160 V(F64ConvertF32, float) \ |
| 161 V(F64ReinterpretI64, int64_t) \ | 161 V(F64ReinterpretI64, int64_t) \ |
| 162 V(I32AsmjsSConvertF32, float) \ | 162 V(I32AsmjsSConvertF32, float) \ |
| 163 V(I32AsmjsUConvertF32, float) \ | 163 V(I32AsmjsUConvertF32, float) \ |
| 164 V(I32AsmjsSConvertF64, double) \ | 164 V(I32AsmjsSConvertF64, double) \ |
| 165 V(I32AsmjsUConvertF64, double) | 165 V(I32AsmjsUConvertF64, double) \ |
| 166 | 166 V(F32Sqrt, float) \ |
| 167 #define FOREACH_OTHER_UNOP_NAN(V) \ | |
| 168 V(F32Sqrt, float) \ | |
| 169 V(F64Sqrt, double) | 167 V(F64Sqrt, double) |
| 170 | 168 |
| 171 static inline int32_t ExecuteI32DivS(int32_t a, int32_t b, TrapReason* trap) { | 169 static inline int32_t ExecuteI32DivS(int32_t a, int32_t b, TrapReason* trap) { |
| 172 if (b == 0) { | 170 if (b == 0) { |
| 173 *trap = kTrapDivByZero; | 171 *trap = kTrapDivByZero; |
| 174 return 0; | 172 return 0; |
| 175 } | 173 } |
| 176 if (b == -1 && a == std::numeric_limits<int32_t>::min()) { | 174 if (b == -1 && a == std::numeric_limits<int32_t>::min()) { |
| 177 *trap = kTrapDivUnrepresentable; | 175 *trap = kTrapDivUnrepresentable; |
| 178 return 0; | 176 return 0; |
| (...skipping 990 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1169 // ^ 0 ^ stack_.size() | 1167 // ^ 0 ^ stack_.size() |
| 1170 DCHECK_LE(dest, stack_.size()); | 1168 DCHECK_LE(dest, stack_.size()); |
| 1171 DCHECK_LE(dest + arity, stack_.size()); | 1169 DCHECK_LE(dest + arity, stack_.size()); |
| 1172 size_t pop_count = stack_.size() - dest - arity; | 1170 size_t pop_count = stack_.size() - dest - arity; |
| 1173 for (size_t i = 0; i < arity; i++) { | 1171 for (size_t i = 0; i < arity; i++) { |
| 1174 stack_[dest + i] = stack_[dest + pop_count + i]; | 1172 stack_[dest + i] = stack_[dest + pop_count + i]; |
| 1175 } | 1173 } |
| 1176 stack_.resize(stack_.size() - pop_count); | 1174 stack_.resize(stack_.size() - pop_count); |
| 1177 } | 1175 } |
| 1178 | 1176 |
| 1177 template <typename ctype, typename mtype> | |
|
Eric Holk
2017/02/03 03:11:26
I like the template approach way better than prepr
| |
| 1178 bool ExecuteLoad(Decoder* decoder, InterpreterCode* code, pc_t pc, int& len) { | |
| 1179 MemoryAccessOperand operand(decoder, code->at(pc), sizeof(ctype)); | |
| 1180 uint32_t index = Pop().to<uint32_t>(); | |
| 1181 size_t effective_mem_size = instance()->mem_size - sizeof(mtype); | |
| 1182 if (operand.offset > effective_mem_size || | |
| 1183 index > (effective_mem_size - operand.offset)) { | |
| 1184 DoTrap(kTrapMemOutOfBounds, pc); | |
| 1185 return false; | |
| 1186 } | |
| 1187 byte* addr = instance()->mem_start + operand.offset + index; | |
| 1188 WasmVal result(static_cast<ctype>(ReadLittleEndianValue<mtype>(addr))); | |
| 1189 | |
| 1190 Push(pc, result); | |
| 1191 len = 1 + operand.length; | |
| 1192 return true; | |
| 1193 } | |
| 1194 | |
| 1195 template <typename ctype, typename mtype> | |
| 1196 bool ExecuteStore(Decoder* decoder, InterpreterCode* code, pc_t pc, | |
| 1197 int& len) { | |
| 1198 MemoryAccessOperand operand(decoder, code->at(pc), sizeof(ctype)); | |
| 1199 WasmVal val = Pop(); | |
| 1200 | |
| 1201 uint32_t index = Pop().to<uint32_t>(); | |
| 1202 size_t effective_mem_size = instance()->mem_size - sizeof(mtype); | |
| 1203 if (operand.offset > effective_mem_size || | |
| 1204 index > (effective_mem_size - operand.offset)) { | |
| 1205 DoTrap(kTrapMemOutOfBounds, pc); | |
| 1206 return false; | |
| 1207 } | |
| 1208 byte* addr = instance()->mem_start + operand.offset + index; | |
| 1209 WriteLittleEndianValue<mtype>(addr, static_cast<mtype>(val.to<ctype>())); | |
| 1210 len = 1 + operand.length; | |
| 1211 | |
| 1212 if (std::is_same<float, ctype>::value) { | |
| 1213 possible_nondeterminism_ |= std::isnan(val.to<float>()); | |
| 1214 } else if (std::is_same<double, ctype>::value) { | |
| 1215 possible_nondeterminism_ |= std::isnan(val.to<double>()); | |
| 1216 } | |
| 1217 return true; | |
| 1218 } | |
| 1219 | |
| 1179 void Execute(InterpreterCode* code, pc_t pc, int max) { | 1220 void Execute(InterpreterCode* code, pc_t pc, int max) { |
| 1180 Decoder decoder(code->start, code->end); | 1221 Decoder decoder(code->start, code->end); |
| 1181 pc_t limit = code->end - code->start; | 1222 pc_t limit = code->end - code->start; |
| 1182 while (--max >= 0) { | 1223 while (--max >= 0) { |
| 1183 #define PAUSE_IF_BREAK_FLAG(flag) \ | 1224 #define PAUSE_IF_BREAK_FLAG(flag) \ |
| 1184 if (V8_UNLIKELY(break_flags_ & WasmInterpreter::BreakFlag::flag)) max = 0; | 1225 if (V8_UNLIKELY(break_flags_ & WasmInterpreter::BreakFlag::flag)) max = 0; |
| 1185 | 1226 |
| 1186 DCHECK_GT(limit, pc); | 1227 DCHECK_GT(limit, pc); |
| 1187 | 1228 |
| 1188 const char* skip = " "; | 1229 const char* skip = " "; |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1420 *reinterpret_cast<float*>(ptr) = val.to<float>(); | 1461 *reinterpret_cast<float*>(ptr) = val.to<float>(); |
| 1421 } else if (type == kWasmF64) { | 1462 } else if (type == kWasmF64) { |
| 1422 *reinterpret_cast<double*>(ptr) = val.to<double>(); | 1463 *reinterpret_cast<double*>(ptr) = val.to<double>(); |
| 1423 } else { | 1464 } else { |
| 1424 UNREACHABLE(); | 1465 UNREACHABLE(); |
| 1425 } | 1466 } |
| 1426 len = 1 + operand.length; | 1467 len = 1 + operand.length; |
| 1427 break; | 1468 break; |
| 1428 } | 1469 } |
| 1429 | 1470 |
| 1430 #define LOAD_CASE(name, ctype, mtype) \ | 1471 #define LOAD_CASE(name, ctype, mtype) \ |
| 1431 case kExpr##name: { \ | 1472 case kExpr##name: { \ |
| 1432 MemoryAccessOperand operand(&decoder, code->at(pc), sizeof(ctype)); \ | 1473 if (!ExecuteLoad<ctype, mtype>(&decoder, code, pc, len)) return; \ |
| 1433 uint32_t index = Pop().to<uint32_t>(); \ | 1474 break; \ |
| 1434 size_t effective_mem_size = instance()->mem_size - sizeof(mtype); \ | |
| 1435 if (operand.offset > effective_mem_size || \ | |
| 1436 index > (effective_mem_size - operand.offset)) { \ | |
| 1437 return DoTrap(kTrapMemOutOfBounds, pc); \ | |
| 1438 } \ | |
| 1439 byte* addr = instance()->mem_start + operand.offset + index; \ | |
| 1440 WasmVal result(static_cast<ctype>(ReadLittleEndianValue<mtype>(addr))); \ | |
| 1441 Push(pc, result); \ | |
| 1442 len = 1 + operand.length; \ | |
| 1443 break; \ | |
| 1444 } | 1475 } |
| 1445 | 1476 |
| 1446 LOAD_CASE(I32LoadMem8S, int32_t, int8_t); | 1477 LOAD_CASE(I32LoadMem8S, int32_t, int8_t); |
| 1447 LOAD_CASE(I32LoadMem8U, int32_t, uint8_t); | 1478 LOAD_CASE(I32LoadMem8U, int32_t, uint8_t); |
| 1448 LOAD_CASE(I32LoadMem16S, int32_t, int16_t); | 1479 LOAD_CASE(I32LoadMem16S, int32_t, int16_t); |
| 1449 LOAD_CASE(I32LoadMem16U, int32_t, uint16_t); | 1480 LOAD_CASE(I32LoadMem16U, int32_t, uint16_t); |
| 1450 LOAD_CASE(I64LoadMem8S, int64_t, int8_t); | 1481 LOAD_CASE(I64LoadMem8S, int64_t, int8_t); |
| 1451 LOAD_CASE(I64LoadMem8U, int64_t, uint8_t); | 1482 LOAD_CASE(I64LoadMem8U, int64_t, uint8_t); |
| 1452 LOAD_CASE(I64LoadMem16S, int64_t, int16_t); | 1483 LOAD_CASE(I64LoadMem16S, int64_t, int16_t); |
| 1453 LOAD_CASE(I64LoadMem16U, int64_t, uint16_t); | 1484 LOAD_CASE(I64LoadMem16U, int64_t, uint16_t); |
| 1454 LOAD_CASE(I64LoadMem32S, int64_t, int32_t); | 1485 LOAD_CASE(I64LoadMem32S, int64_t, int32_t); |
| 1455 LOAD_CASE(I64LoadMem32U, int64_t, uint32_t); | 1486 LOAD_CASE(I64LoadMem32U, int64_t, uint32_t); |
| 1456 LOAD_CASE(I32LoadMem, int32_t, int32_t); | 1487 LOAD_CASE(I32LoadMem, int32_t, int32_t); |
| 1457 LOAD_CASE(I64LoadMem, int64_t, int64_t); | 1488 LOAD_CASE(I64LoadMem, int64_t, int64_t); |
| 1458 LOAD_CASE(F32LoadMem, float, float); | 1489 LOAD_CASE(F32LoadMem, float, float); |
| 1459 LOAD_CASE(F64LoadMem, double, double); | 1490 LOAD_CASE(F64LoadMem, double, double); |
| 1460 #undef LOAD_CASE | 1491 #undef LOAD_CASE |
| 1461 | 1492 |
| 1462 #define STORE_CASE(name, ctype, mtype) \ | 1493 #define STORE_CASE(name, ctype, mtype) \ |
| 1463 case kExpr##name: { \ | 1494 case kExpr##name: { \ |
| 1464 MemoryAccessOperand operand(&decoder, code->at(pc), sizeof(ctype)); \ | 1495 if (!ExecuteStore<ctype, mtype>(&decoder, code, pc, len)) return; \ |
| 1465 WasmVal val = Pop(); \ | 1496 break; \ |
| 1466 uint32_t index = Pop().to<uint32_t>(); \ | |
| 1467 size_t effective_mem_size = instance()->mem_size - sizeof(mtype); \ | |
| 1468 if (operand.offset > effective_mem_size || \ | |
| 1469 index > (effective_mem_size - operand.offset)) { \ | |
| 1470 return DoTrap(kTrapMemOutOfBounds, pc); \ | |
| 1471 } \ | |
| 1472 byte* addr = instance()->mem_start + operand.offset + index; \ | |
| 1473 WriteLittleEndianValue<mtype>(addr, static_cast<mtype>(val.to<ctype>())); \ | |
| 1474 len = 1 + operand.length; \ | |
| 1475 break; \ | |
| 1476 } | 1497 } |
| 1477 | 1498 |
| 1478 STORE_CASE(I32StoreMem8, int32_t, int8_t); | 1499 STORE_CASE(I32StoreMem8, int32_t, int8_t); |
| 1479 STORE_CASE(I32StoreMem16, int32_t, int16_t); | 1500 STORE_CASE(I32StoreMem16, int32_t, int16_t); |
| 1480 STORE_CASE(I64StoreMem8, int64_t, int8_t); | 1501 STORE_CASE(I64StoreMem8, int64_t, int8_t); |
| 1481 STORE_CASE(I64StoreMem16, int64_t, int16_t); | 1502 STORE_CASE(I64StoreMem16, int64_t, int16_t); |
| 1482 STORE_CASE(I64StoreMem32, int64_t, int32_t); | 1503 STORE_CASE(I64StoreMem32, int64_t, int32_t); |
| 1483 STORE_CASE(I32StoreMem, int32_t, int32_t); | 1504 STORE_CASE(I32StoreMem, int32_t, int32_t); |
| 1484 STORE_CASE(I64StoreMem, int64_t, int64_t); | 1505 STORE_CASE(I64StoreMem, int64_t, int64_t); |
| 1485 STORE_CASE(F32StoreMem, float, float); | 1506 STORE_CASE(F32StoreMem, float, float); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1541 MemoryIndexOperand operand(&decoder, code->at(pc)); | 1562 MemoryIndexOperand operand(&decoder, code->at(pc)); |
| 1542 Push(pc, WasmVal(static_cast<uint32_t>(instance()->mem_size / | 1563 Push(pc, WasmVal(static_cast<uint32_t>(instance()->mem_size / |
| 1543 WasmModule::kPageSize))); | 1564 WasmModule::kPageSize))); |
| 1544 len = 1 + operand.length; | 1565 len = 1 + operand.length; |
| 1545 break; | 1566 break; |
| 1546 } | 1567 } |
| 1547 // We need to treat kExprI32ReinterpretF32 and kExprI64ReinterpretF64 | 1568 // We need to treat kExprI32ReinterpretF32 and kExprI64ReinterpretF64 |
| 1548 // specially to guarantee that the quiet bit of a NaN is preserved on | 1569 // specially to guarantee that the quiet bit of a NaN is preserved on |
| 1549 // ia32 by the reinterpret casts. | 1570 // ia32 by the reinterpret casts. |
| 1550 case kExprI32ReinterpretF32: { | 1571 case kExprI32ReinterpretF32: { |
| 1551 WasmVal result(ExecuteI32ReinterpretF32(Pop())); | 1572 WasmVal val = Pop(); |
| 1573 WasmVal result(ExecuteI32ReinterpretF32(val)); | |
| 1552 Push(pc, result); | 1574 Push(pc, result); |
| 1575 possible_nondeterminism_ |= std::isnan(val.to<float>()); | |
| 1553 break; | 1576 break; |
| 1554 } | 1577 } |
| 1555 case kExprI64ReinterpretF64: { | 1578 case kExprI64ReinterpretF64: { |
| 1556 WasmVal result(ExecuteI64ReinterpretF64(Pop())); | 1579 WasmVal val = Pop(); |
| 1580 WasmVal result(ExecuteI64ReinterpretF64(val)); | |
| 1557 Push(pc, result); | 1581 Push(pc, result); |
| 1582 possible_nondeterminism_ |= std::isnan(val.to<double>()); | |
| 1558 break; | 1583 break; |
| 1559 } | 1584 } |
| 1560 #define EXECUTE_SIMPLE_BINOP(name, ctype, op) \ | 1585 #define EXECUTE_SIMPLE_BINOP(name, ctype, op) \ |
| 1561 case kExpr##name: { \ | 1586 case kExpr##name: { \ |
| 1562 WasmVal rval = Pop(); \ | 1587 WasmVal rval = Pop(); \ |
| 1563 WasmVal lval = Pop(); \ | 1588 WasmVal lval = Pop(); \ |
| 1564 WasmVal result(lval.to<ctype>() op rval.to<ctype>()); \ | 1589 WasmVal result(lval.to<ctype>() op rval.to<ctype>()); \ |
| 1565 Push(pc, result); \ | 1590 Push(pc, result); \ |
| 1566 break; \ | 1591 break; \ |
| 1567 } | 1592 } |
| 1568 FOREACH_SIMPLE_BINOP(EXECUTE_SIMPLE_BINOP) | 1593 FOREACH_SIMPLE_BINOP(EXECUTE_SIMPLE_BINOP) |
| 1569 #undef EXECUTE_SIMPLE_BINOP | 1594 #undef EXECUTE_SIMPLE_BINOP |
| 1570 | 1595 |
| 1571 #define EXECUTE_SIMPLE_BINOP_NAN(name, ctype, op) \ | |
| 1572 case kExpr##name: { \ | |
| 1573 WasmVal rval = Pop(); \ | |
| 1574 WasmVal lval = Pop(); \ | |
| 1575 ctype result = lval.to<ctype>() op rval.to<ctype>(); \ | |
| 1576 possible_nondeterminism_ |= std::isnan(result); \ | |
| 1577 WasmVal result_val(result); \ | |
| 1578 Push(pc, result_val); \ | |
| 1579 break; \ | |
| 1580 } | |
| 1581 FOREACH_SIMPLE_BINOP_NAN(EXECUTE_SIMPLE_BINOP_NAN) | |
| 1582 #undef EXECUTE_SIMPLE_BINOP_NAN | |
| 1583 | |
| 1584 #define EXECUTE_OTHER_BINOP(name, ctype) \ | 1596 #define EXECUTE_OTHER_BINOP(name, ctype) \ |
| 1585 case kExpr##name: { \ | 1597 case kExpr##name: { \ |
| 1586 TrapReason trap = kTrapCount; \ | 1598 TrapReason trap = kTrapCount; \ |
| 1587 volatile ctype rval = Pop().to<ctype>(); \ | 1599 volatile ctype rval = Pop().to<ctype>(); \ |
| 1588 volatile ctype lval = Pop().to<ctype>(); \ | 1600 volatile ctype lval = Pop().to<ctype>(); \ |
| 1589 WasmVal result(Execute##name(lval, rval, &trap)); \ | 1601 WasmVal result(Execute##name(lval, rval, &trap)); \ |
| 1590 if (trap != kTrapCount) return DoTrap(trap, pc); \ | 1602 if (trap != kTrapCount) return DoTrap(trap, pc); \ |
| 1591 Push(pc, result); \ | 1603 Push(pc, result); \ |
| 1592 break; \ | 1604 break; \ |
| 1593 } | 1605 } |
| 1594 FOREACH_OTHER_BINOP(EXECUTE_OTHER_BINOP) | 1606 FOREACH_OTHER_BINOP(EXECUTE_OTHER_BINOP) |
| 1595 #undef EXECUTE_OTHER_BINOP | 1607 #undef EXECUTE_OTHER_BINOP |
| 1596 | 1608 |
| 1597 #define EXECUTE_OTHER_UNOP(name, ctype) \ | 1609 #define EXECUTE_OTHER_UNOP(name, ctype) \ |
| 1598 case kExpr##name: { \ | 1610 case kExpr##name: { \ |
| 1599 TrapReason trap = kTrapCount; \ | 1611 TrapReason trap = kTrapCount; \ |
| 1600 volatile ctype val = Pop().to<ctype>(); \ | 1612 volatile ctype val = Pop().to<ctype>(); \ |
| 1601 WasmVal result(Execute##name(val, &trap)); \ | 1613 WasmVal result(Execute##name(val, &trap)); \ |
| 1602 if (trap != kTrapCount) return DoTrap(trap, pc); \ | 1614 if (trap != kTrapCount) return DoTrap(trap, pc); \ |
| 1603 Push(pc, result); \ | 1615 Push(pc, result); \ |
| 1604 break; \ | 1616 break; \ |
| 1605 } | 1617 } |
| 1606 FOREACH_OTHER_UNOP(EXECUTE_OTHER_UNOP) | 1618 FOREACH_OTHER_UNOP(EXECUTE_OTHER_UNOP) |
| 1607 #undef EXECUTE_OTHER_UNOP | 1619 #undef EXECUTE_OTHER_UNOP |
| 1608 | 1620 |
| 1609 #define EXECUTE_OTHER_UNOP_NAN(name, ctype) \ | |
| 1610 case kExpr##name: { \ | |
| 1611 TrapReason trap = kTrapCount; \ | |
| 1612 volatile ctype val = Pop().to<ctype>(); \ | |
| 1613 ctype result = Execute##name(val, &trap); \ | |
| 1614 possible_nondeterminism_ |= std::isnan(result); \ | |
| 1615 WasmVal result_val(result); \ | |
| 1616 if (trap != kTrapCount) return DoTrap(trap, pc); \ | |
| 1617 Push(pc, result_val); \ | |
| 1618 break; \ | |
| 1619 } | |
| 1620 FOREACH_OTHER_UNOP_NAN(EXECUTE_OTHER_UNOP_NAN) | |
| 1621 #undef EXECUTE_OTHER_UNOP_NAN | |
| 1622 | |
| 1623 default: | 1621 default: |
| 1624 V8_Fatal(__FILE__, __LINE__, "Unknown or unimplemented opcode #%d:%s", | 1622 V8_Fatal(__FILE__, __LINE__, "Unknown or unimplemented opcode #%d:%s", |
| 1625 code->start[pc], OpcodeName(code->start[pc])); | 1623 code->start[pc], OpcodeName(code->start[pc])); |
| 1626 UNREACHABLE(); | 1624 UNREACHABLE(); |
| 1627 } | 1625 } |
| 1628 | 1626 |
| 1629 pc += len; | 1627 pc += len; |
| 1630 if (pc == limit) { | 1628 if (pc == limit) { |
| 1631 // Fell off end of code; do an implicit return. | 1629 // Fell off end of code; do an implicit return. |
| 1632 TRACE("@%-3zu: ImplicitReturn\n", pc); | 1630 TRACE("@%-3zu: ImplicitReturn\n", pc); |
| (...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1922 return none; | 1920 return none; |
| 1923 } | 1921 } |
| 1924 | 1922 |
| 1925 void InterpretedFrame::SetLocalVal(int index, WasmVal val) { UNIMPLEMENTED(); } | 1923 void InterpretedFrame::SetLocalVal(int index, WasmVal val) { UNIMPLEMENTED(); } |
| 1926 | 1924 |
| 1927 void InterpretedFrame::SetExprVal(int pc, WasmVal val) { UNIMPLEMENTED(); } | 1925 void InterpretedFrame::SetExprVal(int pc, WasmVal val) { UNIMPLEMENTED(); } |
| 1928 | 1926 |
| 1929 } // namespace wasm | 1927 } // namespace wasm |
| 1930 } // namespace internal | 1928 } // namespace internal |
| 1931 } // namespace v8 | 1929 } // namespace v8 |
| OLD | NEW |