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

Unified Diff: src/wasm/wasm-interpreter.cc

Issue 2671803002: [wasm] Refactor the non-determinism detection in the interpreter. (Closed)
Patch Set: Also adjust copysign Created 3 years, 10 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | test/cctest/wasm/test-run-wasm-interpreter.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/wasm/wasm-interpreter.cc
diff --git a/src/wasm/wasm-interpreter.cc b/src/wasm/wasm-interpreter.cc
index 9a1df93964e07791c11e6515a68d69aafdee81b6..cbc99eb57ed8eb8220a782f51726bf6b9c54b472 100644
--- a/src/wasm/wasm-interpreter.cc
+++ b/src/wasm/wasm-interpreter.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <type_traits>
+
#include "src/wasm/wasm-interpreter.h"
#include "src/utils.h"
@@ -77,12 +79,10 @@ namespace wasm {
V(F64Lt, double, <) \
V(F64Le, double, <=) \
V(F64Gt, double, >) \
- V(F64Ge, double, >=)
-
-#define FOREACH_SIMPLE_BINOP_NAN(V) \
- V(F32Mul, float, *) \
- V(F64Mul, double, *) \
- V(F32Div, float, /) \
+ V(F64Ge, double, >=) \
+ V(F32Mul, float, *) \
+ V(F64Mul, double, *) \
+ V(F32Div, float, /) \
V(F64Div, double, /)
#define FOREACH_OTHER_BINOP(V) \
@@ -106,10 +106,8 @@ namespace wasm {
V(I64Rol, int64_t) \
V(F32Min, float) \
V(F32Max, float) \
- V(F32CopySign, float) \
V(F64Min, double) \
V(F64Max, double) \
- V(F64CopySign, double) \
V(I32AsmjsDivS, int32_t) \
V(I32AsmjsDivU, uint32_t) \
V(I32AsmjsRemS, int32_t) \
@@ -162,10 +160,8 @@ namespace wasm {
V(I32AsmjsSConvertF32, float) \
V(I32AsmjsUConvertF32, float) \
V(I32AsmjsSConvertF64, double) \
- V(I32AsmjsUConvertF64, double)
-
-#define FOREACH_OTHER_UNOP_NAN(V) \
- V(F32Sqrt, float) \
+ V(I32AsmjsUConvertF64, double) \
+ V(F32Sqrt, float) \
V(F64Sqrt, double)
static inline int32_t ExecuteI32DivS(int32_t a, int32_t b, TrapReason* trap) {
@@ -1176,6 +1172,49 @@ class ThreadImpl {
stack_.resize(stack_.size() - pop_count);
}
+ template <typename ctype, typename mtype>
+ bool ExecuteLoad(Decoder* decoder, InterpreterCode* code, pc_t pc, int& len) {
+ MemoryAccessOperand operand(decoder, code->at(pc), sizeof(ctype));
+ uint32_t index = Pop().to<uint32_t>();
+ size_t effective_mem_size = instance()->mem_size - sizeof(mtype);
+ if (operand.offset > effective_mem_size ||
+ index > (effective_mem_size - operand.offset)) {
+ DoTrap(kTrapMemOutOfBounds, pc);
+ return false;
+ }
+ byte* addr = instance()->mem_start + operand.offset + index;
+ WasmVal result(static_cast<ctype>(ReadLittleEndianValue<mtype>(addr)));
+
+ Push(pc, result);
+ len = 1 + operand.length;
+ return true;
+ }
+
+ template <typename ctype, typename mtype>
+ bool ExecuteStore(Decoder* decoder, InterpreterCode* code, pc_t pc,
+ int& len) {
+ MemoryAccessOperand operand(decoder, code->at(pc), sizeof(ctype));
+ WasmVal val = Pop();
+
+ uint32_t index = Pop().to<uint32_t>();
+ size_t effective_mem_size = instance()->mem_size - sizeof(mtype);
+ if (operand.offset > effective_mem_size ||
+ index > (effective_mem_size - operand.offset)) {
+ DoTrap(kTrapMemOutOfBounds, pc);
+ return false;
+ }
+ byte* addr = instance()->mem_start + operand.offset + index;
+ WriteLittleEndianValue<mtype>(addr, static_cast<mtype>(val.to<ctype>()));
+ len = 1 + operand.length;
+
+ if (std::is_same<float, ctype>::value) {
+ possible_nondeterminism_ |= std::isnan(val.to<float>());
+ } else if (std::is_same<double, ctype>::value) {
+ possible_nondeterminism_ |= std::isnan(val.to<double>());
+ }
+ return true;
+ }
+
void Execute(InterpreterCode* code, pc_t pc, int max) {
Decoder decoder(code->start, code->end);
pc_t limit = code->end - code->start;
@@ -1427,20 +1466,10 @@ class ThreadImpl {
break;
}
-#define LOAD_CASE(name, ctype, mtype) \
- case kExpr##name: { \
- MemoryAccessOperand operand(&decoder, code->at(pc), sizeof(ctype)); \
- uint32_t index = Pop().to<uint32_t>(); \
- size_t effective_mem_size = instance()->mem_size - sizeof(mtype); \
- if (operand.offset > effective_mem_size || \
- index > (effective_mem_size - operand.offset)) { \
- return DoTrap(kTrapMemOutOfBounds, pc); \
- } \
- byte* addr = instance()->mem_start + operand.offset + index; \
- WasmVal result(static_cast<ctype>(ReadLittleEndianValue<mtype>(addr))); \
- Push(pc, result); \
- len = 1 + operand.length; \
- break; \
+#define LOAD_CASE(name, ctype, mtype) \
+ case kExpr##name: { \
+ if (!ExecuteLoad<ctype, mtype>(&decoder, code, pc, len)) return; \
+ break; \
}
LOAD_CASE(I32LoadMem8S, int32_t, int8_t);
@@ -1459,20 +1488,10 @@ class ThreadImpl {
LOAD_CASE(F64LoadMem, double, double);
#undef LOAD_CASE
-#define STORE_CASE(name, ctype, mtype) \
- case kExpr##name: { \
- MemoryAccessOperand operand(&decoder, code->at(pc), sizeof(ctype)); \
- WasmVal val = Pop(); \
- uint32_t index = Pop().to<uint32_t>(); \
- size_t effective_mem_size = instance()->mem_size - sizeof(mtype); \
- if (operand.offset > effective_mem_size || \
- index > (effective_mem_size - operand.offset)) { \
- return DoTrap(kTrapMemOutOfBounds, pc); \
- } \
- byte* addr = instance()->mem_start + operand.offset + index; \
- WriteLittleEndianValue<mtype>(addr, static_cast<mtype>(val.to<ctype>())); \
- len = 1 + operand.length; \
- break; \
+#define STORE_CASE(name, ctype, mtype) \
+ case kExpr##name: { \
+ if (!ExecuteStore<ctype, mtype>(&decoder, code, pc, len)) return; \
+ break; \
}
STORE_CASE(I32StoreMem8, int32_t, int8_t);
@@ -1548,13 +1567,17 @@ class ThreadImpl {
// specially to guarantee that the quiet bit of a NaN is preserved on
// ia32 by the reinterpret casts.
case kExprI32ReinterpretF32: {
- WasmVal result(ExecuteI32ReinterpretF32(Pop()));
+ WasmVal val = Pop();
+ WasmVal result(ExecuteI32ReinterpretF32(val));
Push(pc, result);
+ possible_nondeterminism_ |= std::isnan(val.to<float>());
break;
}
case kExprI64ReinterpretF64: {
- WasmVal result(ExecuteI64ReinterpretF64(Pop()));
+ WasmVal val = Pop();
+ WasmVal result(ExecuteI64ReinterpretF64(val));
Push(pc, result);
+ possible_nondeterminism_ |= std::isnan(val.to<double>());
break;
}
#define EXECUTE_SIMPLE_BINOP(name, ctype, op) \
@@ -1568,19 +1591,6 @@ class ThreadImpl {
FOREACH_SIMPLE_BINOP(EXECUTE_SIMPLE_BINOP)
#undef EXECUTE_SIMPLE_BINOP
-#define EXECUTE_SIMPLE_BINOP_NAN(name, ctype, op) \
- case kExpr##name: { \
- WasmVal rval = Pop(); \
- WasmVal lval = Pop(); \
- ctype result = lval.to<ctype>() op rval.to<ctype>(); \
- possible_nondeterminism_ |= std::isnan(result); \
- WasmVal result_val(result); \
- Push(pc, result_val); \
- break; \
- }
- FOREACH_SIMPLE_BINOP_NAN(EXECUTE_SIMPLE_BINOP_NAN)
-#undef EXECUTE_SIMPLE_BINOP_NAN
-
#define EXECUTE_OTHER_BINOP(name, ctype) \
case kExpr##name: { \
TrapReason trap = kTrapCount; \
@@ -1594,6 +1604,28 @@ class ThreadImpl {
FOREACH_OTHER_BINOP(EXECUTE_OTHER_BINOP)
#undef EXECUTE_OTHER_BINOP
+ case kExprF32CopySign: {
+ // Handle kExprF32CopySign separately because it may introduce
+ // observable non-determinism.
+ TrapReason trap = kTrapCount;
+ volatile float rval = Pop().to<float>();
+ volatile float lval = Pop().to<float>();
+ WasmVal result(ExecuteF32CopySign(lval, rval, &trap));
+ Push(pc, result);
+ possible_nondeterminism_ |= std::isnan(rval);
+ break;
+ }
+ case kExprF64CopySign: {
+ // Handle kExprF32CopySign separately because it may introduce
+ // observable non-determinism.
+ TrapReason trap = kTrapCount;
+ volatile double rval = Pop().to<double>();
+ volatile double lval = Pop().to<double>();
+ WasmVal result(ExecuteF64CopySign(lval, rval, &trap));
+ Push(pc, result);
+ possible_nondeterminism_ |= std::isnan(rval);
+ break;
+ }
#define EXECUTE_OTHER_UNOP(name, ctype) \
case kExpr##name: { \
TrapReason trap = kTrapCount; \
@@ -1606,20 +1638,6 @@ class ThreadImpl {
FOREACH_OTHER_UNOP(EXECUTE_OTHER_UNOP)
#undef EXECUTE_OTHER_UNOP
-#define EXECUTE_OTHER_UNOP_NAN(name, ctype) \
- case kExpr##name: { \
- TrapReason trap = kTrapCount; \
- volatile ctype val = Pop().to<ctype>(); \
- ctype result = Execute##name(val, &trap); \
- possible_nondeterminism_ |= std::isnan(result); \
- WasmVal result_val(result); \
- if (trap != kTrapCount) return DoTrap(trap, pc); \
- Push(pc, result_val); \
- break; \
- }
- FOREACH_OTHER_UNOP_NAN(EXECUTE_OTHER_UNOP_NAN)
-#undef EXECUTE_OTHER_UNOP_NAN
-
default:
V8_Fatal(__FILE__, __LINE__, "Unknown or unimplemented opcode #%d:%s",
code->start[pc], OpcodeName(code->start[pc]));
« no previous file with comments | « no previous file | test/cctest/wasm/test-run-wasm-interpreter.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698