Commit 79570f87 authored by ahaas's avatar ahaas Committed by Commit bot

[wasm] Do not use setjmp/longjmp in cctests.

The use of setjmp/longjmp makes the cctests in test-run-wasm and
test-run-wasm-64 flaky on Windows, and I think that it is better not
to use it. With this CL I replace it as follows:

Similar to the setjmp/longjmp implementation we still call a C
function when a trap happens. However, instead of calling longjmp in
this C function we just set a flag which indicates that a trap
happened and then return. After we return from the C function we leave
the frame of the current wasm function and return with a RET
instruction. At the end of a test the wasm test runner checks the flag
to see if a trap happened.

Please take a special look at the LeaveFrame function on arm64.

R=titzer@chromium.org, clemensh@chromium.org, v8-arm-ports@googlegroups.com
CC=jarin@chromium.org

Review-Url: https://codereview.chromium.org/2685583003
Cr-Commit-Position: refs/heads/master@{#43095}
parent e03a2206
...@@ -2651,13 +2651,13 @@ void MacroAssembler::EnterFrame(StackFrame::Type type) { ...@@ -2651,13 +2651,13 @@ void MacroAssembler::EnterFrame(StackFrame::Type type) {
} else if (type == StackFrame::WASM_COMPILED) { } else if (type == StackFrame::WASM_COMPILED) {
DCHECK(csp.Is(StackPointer())); DCHECK(csp.Is(StackPointer()));
Mov(type_reg, Smi::FromInt(type)); Mov(type_reg, Smi::FromInt(type));
Push(xzr, lr); Push(lr, fp);
Push(fp, type_reg); Mov(fp, csp);
Add(fp, csp, TypedFrameConstants::kFixedFrameSizeFromFp); Push(type_reg, xzr);
// csp[3] for alignment // csp[3] : lr
// csp[2] : lr // csp[2] : fp
// csp[1] : fp // csp[1] : type
// csp[0] : type // csp[0] : for alignment
} else { } else {
DCHECK(jssp.Is(StackPointer())); DCHECK(jssp.Is(StackPointer()));
Mov(type_reg, Smi::FromInt(type)); Mov(type_reg, Smi::FromInt(type));
...@@ -2672,12 +2672,19 @@ void MacroAssembler::EnterFrame(StackFrame::Type type) { ...@@ -2672,12 +2672,19 @@ void MacroAssembler::EnterFrame(StackFrame::Type type) {
void MacroAssembler::LeaveFrame(StackFrame::Type type) { void MacroAssembler::LeaveFrame(StackFrame::Type type) {
if (type == StackFrame::WASM_COMPILED) {
DCHECK(csp.Is(StackPointer()));
Mov(csp, fp);
AssertStackConsistency();
Pop(fp, lr);
} else {
DCHECK(jssp.Is(StackPointer())); DCHECK(jssp.Is(StackPointer()));
// Drop the execution stack down to the frame pointer and restore // Drop the execution stack down to the frame pointer and restore
// the caller frame pointer and return address. // the caller frame pointer and return address.
Mov(jssp, fp); Mov(jssp, fp);
AssertStackConsistency(); AssertStackConsistency();
Pop(fp, lr); Pop(fp, lr);
}
} }
......
...@@ -2026,9 +2026,6 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr, ...@@ -2026,9 +2026,6 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
if (frame_elided_) { if (frame_elided_) {
__ set_has_frame(old_has_frame); __ set_has_frame(old_has_frame);
} }
if (FLAG_debug_code) {
__ stop(GetBailoutReason(kUnexpectedReturnFromWasmTrap));
}
} }
private: private:
...@@ -2042,15 +2039,20 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr, ...@@ -2042,15 +2039,20 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
__ CallCFunction( __ CallCFunction(
ExternalReference::wasm_call_trap_callback_for_testing(isolate()), ExternalReference::wasm_call_trap_callback_for_testing(isolate()),
0); 0);
__ LeaveFrame(StackFrame::WASM_COMPILED);
__ Ret();
} else { } else {
__ Move(cp, Smi::kZero); __ Move(cp, Smi::kZero);
gen_->AssembleSourcePosition(instr_); gen_->AssembleSourcePosition(instr_);
__ CallRuntime(trap_id); __ CallRuntime(trap_id);
}
ReferenceMap* reference_map = ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone()); new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0, gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
Safepoint::kNoLazyDeopt); Safepoint::kNoLazyDeopt);
if (FLAG_debug_code) {
__ stop(GetBailoutReason(kUnexpectedReturnFromWasmTrap));
}
}
} }
bool frame_elided_; bool frame_elided_;
......
...@@ -1721,10 +1721,6 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr, ...@@ -1721,10 +1721,6 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
if (frame_elided_) { if (frame_elided_) {
__ set_has_frame(old_has_frame); __ set_has_frame(old_has_frame);
} }
if (FLAG_debug_code) {
// The trap code should never return.
__ Brk(0);
}
} }
private: private:
...@@ -1735,6 +1731,8 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr, ...@@ -1735,6 +1731,8 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
__ CallCFunction( __ CallCFunction(
ExternalReference::wasm_call_trap_callback_for_testing(isolate()), ExternalReference::wasm_call_trap_callback_for_testing(isolate()),
0); 0);
__ LeaveFrame(StackFrame::WASM_COMPILED);
__ Ret();
} else { } else {
DCHECK(csp.Is(__ StackPointer())); DCHECK(csp.Is(__ StackPointer()));
__ Move(cp, Smi::kZero); __ Move(cp, Smi::kZero);
...@@ -1742,11 +1740,15 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr, ...@@ -1742,11 +1740,15 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
__ Mov(jssp, csp); __ Mov(jssp, csp);
gen_->AssembleSourcePosition(instr_); gen_->AssembleSourcePosition(instr_);
__ CallRuntime(trap_id); __ CallRuntime(trap_id);
}
ReferenceMap* reference_map = ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone()); new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0, gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
Safepoint::kNoLazyDeopt); Safepoint::kNoLazyDeopt);
if (FLAG_debug_code) {
// The trap code should never return.
__ Brk(0);
}
}
} }
bool frame_elided_; bool frame_elided_;
Instruction* instr_; Instruction* instr_;
...@@ -1887,7 +1889,6 @@ void CodeGenerator::AssembleConstructFrame() { ...@@ -1887,7 +1889,6 @@ void CodeGenerator::AssembleConstructFrame() {
osr_pc_offset_ = __ pc_offset(); osr_pc_offset_ = __ pc_offset();
shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots(); shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
} }
// Build remainder of frame, including accounting for and filling-in // Build remainder of frame, including accounting for and filling-in
// frame-specific header information, e.g. claiming the extra slot that // frame-specific header information, e.g. claiming the extra slot that
// other platforms explicitly push for STUB frames and frames recording // other platforms explicitly push for STUB frames and frames recording
......
...@@ -1697,9 +1697,6 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr, ...@@ -1697,9 +1697,6 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
if (frame_elided_) { if (frame_elided_) {
__ set_has_frame(old_has_frame); __ set_has_frame(old_has_frame);
} }
if (FLAG_debug_code) {
__ ud2();
}
} }
private: private:
...@@ -1711,15 +1708,20 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr, ...@@ -1711,15 +1708,20 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
__ CallCFunction( __ CallCFunction(
ExternalReference::wasm_call_trap_callback_for_testing(isolate()), ExternalReference::wasm_call_trap_callback_for_testing(isolate()),
0); 0);
__ LeaveFrame(StackFrame::WASM_COMPILED);
__ Ret();
} else { } else {
__ Move(esi, Smi::kZero); __ Move(esi, Smi::kZero);
gen_->AssembleSourcePosition(instr_); gen_->AssembleSourcePosition(instr_);
__ CallRuntime(trap_id); __ CallRuntime(trap_id);
}
ReferenceMap* reference_map = ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone()); new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0, gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
Safepoint::kNoLazyDeopt); Safepoint::kNoLazyDeopt);
if (FLAG_debug_code) {
__ ud2();
}
}
} }
bool frame_elided_; bool frame_elided_;
......
...@@ -1759,9 +1759,6 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr, ...@@ -1759,9 +1759,6 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
if (frame_elided_) { if (frame_elided_) {
__ set_has_frame(old_has_frame); __ set_has_frame(old_has_frame);
} }
if (FLAG_debug_code) {
__ stop(GetBailoutReason(kUnexpectedReturnFromWasmTrap));
}
} }
private: private:
...@@ -1775,15 +1772,20 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr, ...@@ -1775,15 +1772,20 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
__ CallCFunction( __ CallCFunction(
ExternalReference::wasm_call_trap_callback_for_testing(isolate()), ExternalReference::wasm_call_trap_callback_for_testing(isolate()),
0); 0);
__ LeaveFrame(StackFrame::WASM_COMPILED);
__ Ret();
} else { } else {
__ Move(cp, Smi::kZero); __ Move(cp, Smi::kZero);
gen_->AssembleSourcePosition(instr_); gen_->AssembleSourcePosition(instr_);
__ CallRuntime(trap_id); __ CallRuntime(trap_id);
}
ReferenceMap* reference_map = ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone()); new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0, gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
Safepoint::kNoLazyDeopt); Safepoint::kNoLazyDeopt);
if (FLAG_debug_code) {
__ stop(GetBailoutReason(kUnexpectedReturnFromWasmTrap));
}
}
} }
bool frame_elided_; bool frame_elided_;
......
...@@ -2094,9 +2094,6 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr, ...@@ -2094,9 +2094,6 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
if (frame_elided_) { if (frame_elided_) {
__ set_has_frame(old_has_frame); __ set_has_frame(old_has_frame);
} }
if (FLAG_debug_code) {
__ stop(GetBailoutReason(kUnexpectedReturnFromWasmTrap));
}
} }
private: private:
...@@ -2110,15 +2107,20 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr, ...@@ -2110,15 +2107,20 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
__ CallCFunction( __ CallCFunction(
ExternalReference::wasm_call_trap_callback_for_testing(isolate()), ExternalReference::wasm_call_trap_callback_for_testing(isolate()),
0); 0);
__ LeaveFrame(StackFrame::WASM_COMPILED);
__ Ret();
} else { } else {
__ Move(cp, Smi::kZero); __ Move(cp, Smi::kZero);
gen_->AssembleSourcePosition(instr_); gen_->AssembleSourcePosition(instr_);
__ CallRuntime(trap_id); __ CallRuntime(trap_id);
}
ReferenceMap* reference_map = ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone()); new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0, gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
Safepoint::kNoLazyDeopt); Safepoint::kNoLazyDeopt);
if (FLAG_debug_code) {
__ stop(GetBailoutReason(kUnexpectedReturnFromWasmTrap));
}
}
} }
bool frame_elided_; bool frame_elided_;
Instruction* instr_; Instruction* instr_;
......
...@@ -2325,9 +2325,6 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr, ...@@ -2325,9 +2325,6 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
if (frame_elided_) { if (frame_elided_) {
__ set_has_frame(old_has_frame); __ set_has_frame(old_has_frame);
} }
if (FLAG_debug_code) {
__ ud2();
}
} }
private: private:
...@@ -2339,15 +2336,20 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr, ...@@ -2339,15 +2336,20 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
__ CallCFunction( __ CallCFunction(
ExternalReference::wasm_call_trap_callback_for_testing(isolate()), ExternalReference::wasm_call_trap_callback_for_testing(isolate()),
0); 0);
__ LeaveFrame(StackFrame::WASM_COMPILED);
__ Ret();
} else { } else {
__ Move(rsi, Smi::kZero); __ Move(rsi, Smi::kZero);
gen_->AssembleSourcePosition(instr_); gen_->AssembleSourcePosition(instr_);
__ CallRuntime(trap_id); __ CallRuntime(trap_id);
}
ReferenceMap* reference_map = ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone()); new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0, gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
Safepoint::kNoLazyDeopt); Safepoint::kNoLazyDeopt);
if (FLAG_debug_code) {
__ ud2();
}
}
} }
bool frame_elided_; bool frame_elided_;
......
...@@ -1319,6 +1319,9 @@ WASM_EXEC_TEST(I64ReinterpretF64) { ...@@ -1319,6 +1319,9 @@ WASM_EXEC_TEST(I64ReinterpretF64) {
} }
} }
// Do not run this test in a simulator because of signalling NaN issues on ia32.
#ifndef USE_SIMULATOR
WASM_EXEC_TEST(SignallingNanSurvivesI64ReinterpretF64) { WASM_EXEC_TEST(SignallingNanSurvivesI64ReinterpretF64) {
REQUIRE(I64ReinterpretF64); REQUIRE(I64ReinterpretF64);
WasmRunner<int64_t> r(execution_mode); WasmRunner<int64_t> r(execution_mode);
...@@ -1328,6 +1331,7 @@ WASM_EXEC_TEST(SignallingNanSurvivesI64ReinterpretF64) { ...@@ -1328,6 +1331,7 @@ WASM_EXEC_TEST(SignallingNanSurvivesI64ReinterpretF64) {
// This is a signalling nan. // This is a signalling nan.
CHECK_EQ(0x7ff4000000000000, r.Call()); CHECK_EQ(0x7ff4000000000000, r.Call());
} }
#endif
WASM_EXEC_TEST(F64ReinterpretI64) { WASM_EXEC_TEST(F64ReinterpretI64) {
REQUIRE(F64ReinterpretI64); REQUIRE(F64ReinterpretI64);
......
...@@ -1047,6 +1047,9 @@ WASM_EXEC_TEST(I32ReinterpretF32) { ...@@ -1047,6 +1047,9 @@ WASM_EXEC_TEST(I32ReinterpretF32) {
} }
} }
// Do not run this test in a simulator because of signalling NaN issues on ia32.
#ifndef USE_SIMULATOR
WASM_EXEC_TEST(SignallingNanSurvivesI32ReinterpretF32) { WASM_EXEC_TEST(SignallingNanSurvivesI32ReinterpretF32) {
WasmRunner<int32_t> r(execution_mode); WasmRunner<int32_t> r(execution_mode);
...@@ -1057,6 +1060,8 @@ WASM_EXEC_TEST(SignallingNanSurvivesI32ReinterpretF32) { ...@@ -1057,6 +1060,8 @@ WASM_EXEC_TEST(SignallingNanSurvivesI32ReinterpretF32) {
CHECK_EQ(0x7fa00000, r.Call()); CHECK_EQ(0x7fa00000, r.Call());
} }
#endif
WASM_EXEC_TEST_WITH_TRAP(LoadMaxUint32Offset) { WASM_EXEC_TEST_WITH_TRAP(LoadMaxUint32Offset) {
WasmRunner<int32_t> r(execution_mode); WasmRunner<int32_t> r(execution_mode);
r.module().AddMemoryElems<int32_t>(8); r.module().AddMemoryElems<int32_t>(8);
......
...@@ -741,9 +741,9 @@ class WasmRunnerBase : public HandleAndZoneScope { ...@@ -741,9 +741,9 @@ class WasmRunnerBase : public HandleAndZoneScope {
bool interpret() { return module_.execution_mode() == kExecuteInterpreted; } bool interpret() { return module_.execution_mode() == kExecuteInterpreted; }
public: public:
// This field has to be static. Otherwise, gcc complains about the using in // This field has to be static. Otherwise, gcc complains about the use in
// the lambda context below. // the lambda context below.
static jmp_buf jump_buffer; static bool trap_happened;
}; };
template <typename ReturnType, typename... ParamTypes> template <typename ReturnType, typename... ParamTypes>
...@@ -762,15 +762,24 @@ class WasmRunner : public WasmRunnerBase { ...@@ -762,15 +762,24 @@ class WasmRunner : public WasmRunnerBase {
DCHECK(compiled_); DCHECK(compiled_);
if (interpret()) return CallInterpreter(p...); if (interpret()) return CallInterpreter(p...);
// Use setjmp/longjmp to deal with traps in WebAssembly code.
ReturnType return_value = static_cast<ReturnType>(0xdeadbeefdeadbeef); ReturnType return_value = static_cast<ReturnType>(0xdeadbeefdeadbeef);
static int setjmp_ret; WasmRunnerBase::trap_happened = false;
setjmp_ret = setjmp(WasmRunnerBase::jump_buffer); auto trap_callback = []() -> void {
// setjmp returns 0 on the first return, 1 (passed to longjmp) after trap. WasmRunnerBase::trap_happened = true;
if (setjmp_ret == 0) { set_trap_callback_for_testing(nullptr);
DoCall(static_cast<void*>(&p)..., static_cast<void*>(&return_value)); };
} set_trap_callback_for_testing(trap_callback);
return return_value;
wrapper_.SetInnerCode(
module_.GetFunctionCode(functions_[0]->function_index()));
CodeRunner<int32_t> runner(CcTest::InitIsolateOnce(),
wrapper_.GetWrapperCode(), wrapper_.signature());
int32_t result = runner.Call(static_cast<void*>(&p)...,
static_cast<void*>(&return_value));
CHECK_EQ(WASM_WRAPPER_RETURN_VALUE, result);
return WasmRunnerBase::trap_happened
? static_cast<ReturnType>(0xdeadbeefdeadbeef)
: return_value;
} }
ReturnType CallInterpreter(ParamTypes... p) { ReturnType CallInterpreter(ParamTypes... p) {
...@@ -791,30 +800,10 @@ class WasmRunner : public WasmRunnerBase { ...@@ -791,30 +800,10 @@ class WasmRunner : public WasmRunnerBase {
return ReturnType{0}; return ReturnType{0};
} }
} }
private:
// Don't inline this function. The setjmp above should be followed immediately
// by a call.
template <typename... Ptrs>
V8_NOINLINE void DoCall(Ptrs... ptrs) {
auto trap_callback = []() -> void {
set_trap_callback_for_testing(nullptr);
longjmp(WasmRunnerBase::jump_buffer, 1);
};
set_trap_callback_for_testing(trap_callback);
wrapper_.SetInnerCode(
module_.GetFunctionCode(functions_[0]->function_index()));
CodeRunner<int32_t> runner(CcTest::InitIsolateOnce(),
wrapper_.GetWrapperCode(), wrapper_.signature());
int32_t result = runner.Call(ptrs...);
// If we arrive here, no trap happened.
CHECK_EQ(WASM_WRAPPER_RETURN_VALUE, result);
}
}; };
// Declare static variable. // Declare static variable.
jmp_buf WasmRunnerBase::jump_buffer; bool WasmRunnerBase::trap_happened;
// A macro to define tests that run in different engine configurations. // A macro to define tests that run in different engine configurations.
#define WASM_EXEC_TEST(name) \ #define WASM_EXEC_TEST(name) \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment