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) {
} else if (type == StackFrame::WASM_COMPILED) {
DCHECK(csp.Is(StackPointer()));
Mov(type_reg, Smi::FromInt(type));
Push(xzr, lr);
Push(fp, type_reg);
Add(fp, csp, TypedFrameConstants::kFixedFrameSizeFromFp);
// csp[3] for alignment
// csp[2] : lr
// csp[1] : fp
// csp[0] : type
Push(lr, fp);
Mov(fp, csp);
Push(type_reg, xzr);
// csp[3] : lr
// csp[2] : fp
// csp[1] : type
// csp[0] : for alignment
} else {
DCHECK(jssp.Is(StackPointer()));
Mov(type_reg, Smi::FromInt(type));
......@@ -2672,12 +2672,19 @@ void MacroAssembler::EnterFrame(StackFrame::Type type) {
void MacroAssembler::LeaveFrame(StackFrame::Type type) {
DCHECK(jssp.Is(StackPointer()));
// Drop the execution stack down to the frame pointer and restore
// the caller frame pointer and return address.
Mov(jssp, fp);
AssertStackConsistency();
Pop(fp, lr);
if (type == StackFrame::WASM_COMPILED) {
DCHECK(csp.Is(StackPointer()));
Mov(csp, fp);
AssertStackConsistency();
Pop(fp, lr);
} else {
DCHECK(jssp.Is(StackPointer()));
// Drop the execution stack down to the frame pointer and restore
// the caller frame pointer and return address.
Mov(jssp, fp);
AssertStackConsistency();
Pop(fp, lr);
}
}
......
......@@ -2026,9 +2026,6 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
if (frame_elided_) {
__ set_has_frame(old_has_frame);
}
if (FLAG_debug_code) {
__ stop(GetBailoutReason(kUnexpectedReturnFromWasmTrap));
}
}
private:
......@@ -2042,15 +2039,20 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
__ CallCFunction(
ExternalReference::wasm_call_trap_callback_for_testing(isolate()),
0);
__ LeaveFrame(StackFrame::WASM_COMPILED);
__ Ret();
} else {
__ Move(cp, Smi::kZero);
gen_->AssembleSourcePosition(instr_);
__ CallRuntime(trap_id);
ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
Safepoint::kNoLazyDeopt);
if (FLAG_debug_code) {
__ stop(GetBailoutReason(kUnexpectedReturnFromWasmTrap));
}
}
ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
Safepoint::kNoLazyDeopt);
}
bool frame_elided_;
......
......@@ -1721,10 +1721,6 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
if (frame_elided_) {
__ set_has_frame(old_has_frame);
}
if (FLAG_debug_code) {
// The trap code should never return.
__ Brk(0);
}
}
private:
......@@ -1735,6 +1731,8 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
__ CallCFunction(
ExternalReference::wasm_call_trap_callback_for_testing(isolate()),
0);
__ LeaveFrame(StackFrame::WASM_COMPILED);
__ Ret();
} else {
DCHECK(csp.Is(__ StackPointer()));
__ Move(cp, Smi::kZero);
......@@ -1742,11 +1740,15 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
__ Mov(jssp, csp);
gen_->AssembleSourcePosition(instr_);
__ CallRuntime(trap_id);
ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
Safepoint::kNoLazyDeopt);
if (FLAG_debug_code) {
// The trap code should never return.
__ Brk(0);
}
}
ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
Safepoint::kNoLazyDeopt);
}
bool frame_elided_;
Instruction* instr_;
......@@ -1887,7 +1889,6 @@ void CodeGenerator::AssembleConstructFrame() {
osr_pc_offset_ = __ pc_offset();
shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
}
// Build remainder of frame, including accounting for and filling-in
// frame-specific header information, e.g. claiming the extra slot that
// other platforms explicitly push for STUB frames and frames recording
......
......@@ -1697,9 +1697,6 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
if (frame_elided_) {
__ set_has_frame(old_has_frame);
}
if (FLAG_debug_code) {
__ ud2();
}
}
private:
......@@ -1711,15 +1708,20 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
__ CallCFunction(
ExternalReference::wasm_call_trap_callback_for_testing(isolate()),
0);
__ LeaveFrame(StackFrame::WASM_COMPILED);
__ Ret();
} else {
__ Move(esi, Smi::kZero);
gen_->AssembleSourcePosition(instr_);
__ CallRuntime(trap_id);
ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
Safepoint::kNoLazyDeopt);
if (FLAG_debug_code) {
__ ud2();
}
}
ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
Safepoint::kNoLazyDeopt);
}
bool frame_elided_;
......
......@@ -1759,9 +1759,6 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
if (frame_elided_) {
__ set_has_frame(old_has_frame);
}
if (FLAG_debug_code) {
__ stop(GetBailoutReason(kUnexpectedReturnFromWasmTrap));
}
}
private:
......@@ -1775,15 +1772,20 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
__ CallCFunction(
ExternalReference::wasm_call_trap_callback_for_testing(isolate()),
0);
__ LeaveFrame(StackFrame::WASM_COMPILED);
__ Ret();
} else {
__ Move(cp, Smi::kZero);
gen_->AssembleSourcePosition(instr_);
__ CallRuntime(trap_id);
ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
Safepoint::kNoLazyDeopt);
if (FLAG_debug_code) {
__ stop(GetBailoutReason(kUnexpectedReturnFromWasmTrap));
}
}
ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
Safepoint::kNoLazyDeopt);
}
bool frame_elided_;
......
......@@ -2094,9 +2094,6 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
if (frame_elided_) {
__ set_has_frame(old_has_frame);
}
if (FLAG_debug_code) {
__ stop(GetBailoutReason(kUnexpectedReturnFromWasmTrap));
}
}
private:
......@@ -2110,15 +2107,20 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
__ CallCFunction(
ExternalReference::wasm_call_trap_callback_for_testing(isolate()),
0);
__ LeaveFrame(StackFrame::WASM_COMPILED);
__ Ret();
} else {
__ Move(cp, Smi::kZero);
gen_->AssembleSourcePosition(instr_);
__ CallRuntime(trap_id);
ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
Safepoint::kNoLazyDeopt);
if (FLAG_debug_code) {
__ stop(GetBailoutReason(kUnexpectedReturnFromWasmTrap));
}
}
ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
Safepoint::kNoLazyDeopt);
}
bool frame_elided_;
Instruction* instr_;
......
......@@ -2325,9 +2325,6 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
if (frame_elided_) {
__ set_has_frame(old_has_frame);
}
if (FLAG_debug_code) {
__ ud2();
}
}
private:
......@@ -2339,15 +2336,20 @@ void CodeGenerator::AssembleArchTrap(Instruction* instr,
__ CallCFunction(
ExternalReference::wasm_call_trap_callback_for_testing(isolate()),
0);
__ LeaveFrame(StackFrame::WASM_COMPILED);
__ Ret();
} else {
__ Move(rsi, Smi::kZero);
gen_->AssembleSourcePosition(instr_);
__ CallRuntime(trap_id);
ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
Safepoint::kNoLazyDeopt);
if (FLAG_debug_code) {
__ ud2();
}
}
ReferenceMap* reference_map =
new (gen_->zone()) ReferenceMap(gen_->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
Safepoint::kNoLazyDeopt);
}
bool frame_elided_;
......
......@@ -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) {
REQUIRE(I64ReinterpretF64);
WasmRunner<int64_t> r(execution_mode);
......@@ -1328,6 +1331,7 @@ WASM_EXEC_TEST(SignallingNanSurvivesI64ReinterpretF64) {
// This is a signalling nan.
CHECK_EQ(0x7ff4000000000000, r.Call());
}
#endif
WASM_EXEC_TEST(F64ReinterpretI64) {
REQUIRE(F64ReinterpretI64);
......
......@@ -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) {
WasmRunner<int32_t> r(execution_mode);
......@@ -1057,6 +1060,8 @@ WASM_EXEC_TEST(SignallingNanSurvivesI32ReinterpretF32) {
CHECK_EQ(0x7fa00000, r.Call());
}
#endif
WASM_EXEC_TEST_WITH_TRAP(LoadMaxUint32Offset) {
WasmRunner<int32_t> r(execution_mode);
r.module().AddMemoryElems<int32_t>(8);
......
......@@ -741,9 +741,9 @@ class WasmRunnerBase : public HandleAndZoneScope {
bool interpret() { return module_.execution_mode() == kExecuteInterpreted; }
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.
static jmp_buf jump_buffer;
static bool trap_happened;
};
template <typename ReturnType, typename... ParamTypes>
......@@ -762,15 +762,24 @@ class WasmRunner : public WasmRunnerBase {
DCHECK(compiled_);
if (interpret()) return CallInterpreter(p...);
// Use setjmp/longjmp to deal with traps in WebAssembly code.
ReturnType return_value = static_cast<ReturnType>(0xdeadbeefdeadbeef);
static int setjmp_ret;
setjmp_ret = setjmp(WasmRunnerBase::jump_buffer);
// setjmp returns 0 on the first return, 1 (passed to longjmp) after trap.
if (setjmp_ret == 0) {
DoCall(static_cast<void*>(&p)..., static_cast<void*>(&return_value));
}
return return_value;
WasmRunnerBase::trap_happened = false;
auto trap_callback = []() -> void {
WasmRunnerBase::trap_happened = true;
set_trap_callback_for_testing(nullptr);
};
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(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) {
......@@ -791,30 +800,10 @@ class WasmRunner : public WasmRunnerBase {
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.
jmp_buf WasmRunnerBase::jump_buffer;
bool WasmRunnerBase::trap_happened;
// A macro to define tests that run in different engine configurations.
#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