a7776e30e2
Because of catch-less try blocks, we have to check the exception stack one more time so that we don't try to rethrow to an outer try scope if this is already the outermost one. R=clemensb@chromium.org Bug: chromium:1219746 Change-Id: I6ad7e4afec669f04bc10197998db5d6eb38a2205 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2983205 Reviewed-by: Clemens Backes <clemensb@chromium.org> Commit-Queue: Thibaud Michaud <thibaudm@chromium.org> Cr-Commit-Position: refs/heads/master@{#75355}
725 lines
26 KiB
C++
725 lines
26 KiB
C++
// Copyright 2019 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "src/api/api-inl.h"
|
|
#include "test/cctest/wasm/wasm-atomics-utils.h"
|
|
#include "test/common/wasm/test-signatures.h"
|
|
#include "test/common/wasm/wasm-macro-gen.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
namespace wasm {
|
|
namespace test_run_wasm_exceptions {
|
|
|
|
WASM_EXEC_TEST(TryCatchThrow) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
WasmRunner<uint32_t, uint32_t> r(execution_tier);
|
|
byte except = r.builder().AddException(sigs.v_v());
|
|
constexpr uint32_t kResult0 = 23;
|
|
constexpr uint32_t kResult1 = 42;
|
|
|
|
// Build the main test function.
|
|
BUILD(r, WASM_TRY_CATCH_T(kWasmI32,
|
|
WASM_STMTS(WASM_I32V(kResult1),
|
|
WASM_IF(WASM_I32_EQZ(WASM_LOCAL_GET(0)),
|
|
WASM_THROW(except))),
|
|
WASM_STMTS(WASM_I32V(kResult0)), except));
|
|
|
|
if (execution_tier != TestExecutionTier::kInterpreter) {
|
|
// Need to call through JS to allow for creation of stack traces.
|
|
r.CheckCallViaJS(kResult0, 0);
|
|
r.CheckCallViaJS(kResult1, 1);
|
|
} else {
|
|
CHECK_EQ(kResult0, r.CallInterpreter(0));
|
|
CHECK_EQ(kResult1, r.CallInterpreter(1));
|
|
}
|
|
}
|
|
|
|
WASM_EXEC_TEST(TryCatchThrowWithValue) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
WasmRunner<uint32_t, uint32_t> r(execution_tier);
|
|
byte except = r.builder().AddException(sigs.v_i());
|
|
constexpr uint32_t kResult0 = 23;
|
|
constexpr uint32_t kResult1 = 42;
|
|
|
|
// Build the main test function.
|
|
BUILD(r, WASM_TRY_CATCH_T(
|
|
kWasmI32,
|
|
WASM_STMTS(WASM_I32V(kResult1),
|
|
WASM_IF(WASM_I32_EQZ(WASM_LOCAL_GET(0)),
|
|
WASM_I32V(kResult0), WASM_THROW(except))),
|
|
WASM_STMTS(kExprNop), except));
|
|
|
|
if (execution_tier != TestExecutionTier::kInterpreter) {
|
|
// Need to call through JS to allow for creation of stack traces.
|
|
r.CheckCallViaJS(kResult0, 0);
|
|
r.CheckCallViaJS(kResult1, 1);
|
|
} else {
|
|
CHECK_EQ(kResult0, r.CallInterpreter(0));
|
|
CHECK_EQ(kResult1, r.CallInterpreter(1));
|
|
}
|
|
}
|
|
|
|
WASM_EXEC_TEST(TryMultiCatchThrow) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
WasmRunner<uint32_t, uint32_t> r(execution_tier);
|
|
byte except1 = r.builder().AddException(sigs.v_v());
|
|
byte except2 = r.builder().AddException(sigs.v_v());
|
|
constexpr uint32_t kResult0 = 23;
|
|
constexpr uint32_t kResult1 = 42;
|
|
constexpr uint32_t kResult2 = 51;
|
|
|
|
// Build the main test function.
|
|
BUILD(
|
|
r, kExprTry, static_cast<byte>((kWasmI32).value_type_code()),
|
|
WASM_STMTS(WASM_I32V(kResult2),
|
|
WASM_IF(WASM_I32_EQZ(WASM_LOCAL_GET(0)), WASM_THROW(except1)),
|
|
WASM_IF(WASM_I32_EQ(WASM_LOCAL_GET(0), WASM_I32V(1)),
|
|
WASM_THROW(except2))),
|
|
kExprCatch, except1, WASM_STMTS(WASM_I32V(kResult0)), kExprCatch, except2,
|
|
WASM_STMTS(WASM_I32V(kResult1)), kExprEnd);
|
|
|
|
if (execution_tier != TestExecutionTier::kInterpreter) {
|
|
// Need to call through JS to allow for creation of stack traces.
|
|
r.CheckCallViaJS(kResult0, 0);
|
|
r.CheckCallViaJS(kResult1, 1);
|
|
r.CheckCallViaJS(kResult2, 2);
|
|
} else {
|
|
CHECK_EQ(kResult0, r.CallInterpreter(0));
|
|
CHECK_EQ(kResult1, r.CallInterpreter(1));
|
|
CHECK_EQ(kResult2, r.CallInterpreter(2));
|
|
}
|
|
}
|
|
|
|
WASM_EXEC_TEST(TryCatchAllThrow) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
WasmRunner<uint32_t, uint32_t> r(execution_tier);
|
|
byte except = r.builder().AddException(sigs.v_v());
|
|
constexpr uint32_t kResult0 = 23;
|
|
constexpr uint32_t kResult1 = 42;
|
|
|
|
// Build the main test function.
|
|
BUILD(r, kExprTry, static_cast<byte>((kWasmI32).value_type_code()),
|
|
WASM_STMTS(WASM_I32V(kResult1), WASM_IF(WASM_I32_EQZ(WASM_LOCAL_GET(0)),
|
|
WASM_THROW(except))),
|
|
kExprCatchAll, WASM_I32V(kResult0), kExprEnd);
|
|
|
|
if (execution_tier != TestExecutionTier::kInterpreter) {
|
|
// Need to call through JS to allow for creation of stack traces.
|
|
r.CheckCallViaJS(kResult0, 0);
|
|
r.CheckCallViaJS(kResult1, 1);
|
|
} else {
|
|
CHECK_EQ(kResult0, r.CallInterpreter(0));
|
|
CHECK_EQ(kResult1, r.CallInterpreter(1));
|
|
}
|
|
}
|
|
|
|
WASM_EXEC_TEST(TryCatchCatchAllThrow) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
WasmRunner<uint32_t, uint32_t> r(execution_tier);
|
|
byte except1 = r.builder().AddException(sigs.v_v());
|
|
byte except2 = r.builder().AddException(sigs.v_v());
|
|
constexpr uint32_t kResult0 = 23;
|
|
constexpr uint32_t kResult1 = 42;
|
|
constexpr uint32_t kResult2 = 51;
|
|
|
|
// Build the main test function.
|
|
BUILD(
|
|
r, kExprTry, static_cast<byte>((kWasmI32).value_type_code()),
|
|
WASM_STMTS(WASM_I32V(kResult2),
|
|
WASM_IF(WASM_I32_EQZ(WASM_LOCAL_GET(0)), WASM_THROW(except1)),
|
|
WASM_IF(WASM_I32_EQ(WASM_LOCAL_GET(0), WASM_I32V(1)),
|
|
WASM_THROW(except2))),
|
|
kExprCatch, except1, WASM_I32V(kResult0), kExprCatchAll,
|
|
WASM_I32V(kResult1), kExprEnd);
|
|
|
|
if (execution_tier != TestExecutionTier::kInterpreter) {
|
|
// Need to call through JS to allow for creation of stack traces.
|
|
r.CheckCallViaJS(kResult0, 0);
|
|
r.CheckCallViaJS(kResult1, 1);
|
|
r.CheckCallViaJS(kResult2, 2);
|
|
} else {
|
|
CHECK_EQ(kResult0, r.CallInterpreter(0));
|
|
CHECK_EQ(kResult1, r.CallInterpreter(1));
|
|
CHECK_EQ(kResult2, r.CallInterpreter(2));
|
|
}
|
|
}
|
|
|
|
WASM_EXEC_TEST(TryImplicitRethrow) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
WasmRunner<uint32_t, uint32_t> r(execution_tier);
|
|
byte except1 = r.builder().AddException(sigs.v_v());
|
|
byte except2 = r.builder().AddException(sigs.v_v());
|
|
constexpr uint32_t kResult0 = 23;
|
|
constexpr uint32_t kResult1 = 42;
|
|
constexpr uint32_t kResult2 = 51;
|
|
|
|
// Build the main test function.
|
|
BUILD(r,
|
|
WASM_TRY_CATCH_T(
|
|
kWasmI32,
|
|
WASM_TRY_CATCH_T(kWasmI32,
|
|
WASM_STMTS(WASM_I32V(kResult1),
|
|
WASM_IF(WASM_I32_EQZ(WASM_LOCAL_GET(0)),
|
|
WASM_THROW(except2))),
|
|
WASM_STMTS(WASM_I32V(kResult2)), except1),
|
|
WASM_I32V(kResult0), except2));
|
|
|
|
if (execution_tier != TestExecutionTier::kInterpreter) {
|
|
// Need to call through JS to allow for creation of stack traces.
|
|
r.CheckCallViaJS(kResult0, 0);
|
|
r.CheckCallViaJS(kResult1, 1);
|
|
} else {
|
|
CHECK_EQ(kResult0, r.CallInterpreter(0));
|
|
CHECK_EQ(kResult1, r.CallInterpreter(1));
|
|
}
|
|
}
|
|
|
|
WASM_EXEC_TEST(TryDelegate) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
WasmRunner<uint32_t, uint32_t> r(execution_tier);
|
|
byte except = r.builder().AddException(sigs.v_v());
|
|
constexpr uint32_t kResult0 = 23;
|
|
constexpr uint32_t kResult1 = 42;
|
|
|
|
// Build the main test function.
|
|
BUILD(r,
|
|
WASM_TRY_CATCH_T(kWasmI32,
|
|
WASM_TRY_DELEGATE_T(
|
|
kWasmI32,
|
|
WASM_STMTS(WASM_I32V(kResult1),
|
|
WASM_IF(WASM_I32_EQZ(WASM_LOCAL_GET(0)),
|
|
WASM_THROW(except))),
|
|
0),
|
|
WASM_I32V(kResult0), except));
|
|
|
|
if (execution_tier != TestExecutionTier::kInterpreter) {
|
|
// Need to call through JS to allow for creation of stack traces.
|
|
r.CheckCallViaJS(kResult0, 0);
|
|
r.CheckCallViaJS(kResult1, 1);
|
|
} else {
|
|
CHECK_EQ(kResult0, r.CallInterpreter(0));
|
|
CHECK_EQ(kResult1, r.CallInterpreter(1));
|
|
}
|
|
}
|
|
|
|
WASM_EXEC_TEST(TestCatchlessTry) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
WasmRunner<uint32_t> r(execution_tier);
|
|
byte except = r.builder().AddException(sigs.v_i());
|
|
BUILD(r,
|
|
WASM_TRY_CATCH_T(
|
|
kWasmI32,
|
|
WASM_TRY_T(kWasmI32, WASM_STMTS(WASM_I32V(0), WASM_THROW(except))),
|
|
WASM_NOP, except));
|
|
if (execution_tier != TestExecutionTier::kInterpreter) {
|
|
r.CheckCallViaJS(0);
|
|
} else {
|
|
CHECK_EQ(0, r.CallInterpreter());
|
|
}
|
|
}
|
|
|
|
WASM_EXEC_TEST(TryCatchRethrow) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
WasmRunner<uint32_t, uint32_t> r(execution_tier);
|
|
byte except1 = r.builder().AddException(sigs.v_v());
|
|
byte except2 = r.builder().AddException(sigs.v_v());
|
|
constexpr uint32_t kResult0 = 23;
|
|
constexpr uint32_t kResult1 = 42;
|
|
constexpr uint32_t kUnreachable = 51;
|
|
|
|
// Build the main test function.
|
|
BUILD(r,
|
|
WASM_TRY_CATCH_CATCH_T(
|
|
kWasmI32,
|
|
WASM_TRY_CATCH_T(
|
|
kWasmI32, WASM_THROW(except2),
|
|
WASM_TRY_CATCH_T(
|
|
kWasmI32, WASM_THROW(except1),
|
|
WASM_STMTS(WASM_I32V(kUnreachable),
|
|
WASM_IF_ELSE(WASM_I32_EQZ(WASM_LOCAL_GET(0)),
|
|
WASM_RETHROW(1), WASM_RETHROW(2))),
|
|
except1),
|
|
except2),
|
|
except1, WASM_I32V(kResult0), except2, WASM_I32V(kResult1)));
|
|
|
|
if (execution_tier != TestExecutionTier::kInterpreter) {
|
|
// Need to call through JS to allow for creation of stack traces.
|
|
r.CheckCallViaJS(kResult0, 0);
|
|
r.CheckCallViaJS(kResult1, 1);
|
|
} else {
|
|
CHECK_EQ(kResult0, r.CallInterpreter(0));
|
|
CHECK_EQ(kResult1, r.CallInterpreter(1));
|
|
}
|
|
}
|
|
|
|
WASM_EXEC_TEST(TryDelegateToCaller) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
WasmRunner<uint32_t, uint32_t> r(execution_tier);
|
|
byte except = r.builder().AddException(sigs.v_v());
|
|
constexpr uint32_t kResult0 = 23;
|
|
constexpr uint32_t kResult1 = 42;
|
|
|
|
// Build the main test function.
|
|
BUILD(r,
|
|
WASM_TRY_CATCH_T(kWasmI32,
|
|
WASM_TRY_DELEGATE_T(
|
|
kWasmI32,
|
|
WASM_STMTS(WASM_I32V(kResult1),
|
|
WASM_IF(WASM_I32_EQZ(WASM_LOCAL_GET(0)),
|
|
WASM_THROW(except))),
|
|
1),
|
|
WASM_I32V(kResult0), except));
|
|
|
|
if (execution_tier != TestExecutionTier::kInterpreter) {
|
|
// Need to call through JS to allow for creation of stack traces.
|
|
constexpr int64_t trap = 0xDEADBEEF;
|
|
r.CheckCallViaJS(trap, 0);
|
|
r.CheckCallViaJS(kResult1, 1);
|
|
} else {
|
|
constexpr int stopped = 0;
|
|
CHECK_EQ(stopped, r.CallInterpreter(0));
|
|
CHECK_EQ(kResult1, r.CallInterpreter(1));
|
|
}
|
|
}
|
|
|
|
WASM_EXEC_TEST(TryCatchCallDirect) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
WasmRunner<uint32_t, uint32_t> r(execution_tier);
|
|
byte except = r.builder().AddException(sigs.v_v());
|
|
constexpr uint32_t kResult0 = 23;
|
|
constexpr uint32_t kResult1 = 42;
|
|
|
|
// Build a throwing helper function.
|
|
WasmFunctionCompiler& throw_func = r.NewFunction(sigs.i_ii());
|
|
BUILD(throw_func, WASM_THROW(except));
|
|
|
|
// Build the main test function.
|
|
BUILD(r, WASM_TRY_CATCH_T(
|
|
kWasmI32,
|
|
WASM_STMTS(WASM_I32V(kResult1),
|
|
WASM_IF(WASM_I32_EQZ(WASM_LOCAL_GET(0)),
|
|
WASM_STMTS(WASM_CALL_FUNCTION(
|
|
throw_func.function_index(),
|
|
WASM_I32V(7), WASM_I32V(9)),
|
|
WASM_DROP))),
|
|
WASM_STMTS(WASM_I32V(kResult0)), except));
|
|
|
|
if (execution_tier != TestExecutionTier::kInterpreter) {
|
|
// Need to call through JS to allow for creation of stack traces.
|
|
r.CheckCallViaJS(kResult0, 0);
|
|
r.CheckCallViaJS(kResult1, 1);
|
|
} else {
|
|
CHECK_EQ(kResult0, r.CallInterpreter(0));
|
|
CHECK_EQ(kResult1, r.CallInterpreter(1));
|
|
}
|
|
}
|
|
|
|
WASM_EXEC_TEST(TryCatchAllCallDirect) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
WasmRunner<uint32_t, uint32_t> r(execution_tier);
|
|
byte except = r.builder().AddException(sigs.v_v());
|
|
constexpr uint32_t kResult0 = 23;
|
|
constexpr uint32_t kResult1 = 42;
|
|
|
|
// Build a throwing helper function.
|
|
WasmFunctionCompiler& throw_func = r.NewFunction(sigs.i_ii());
|
|
BUILD(throw_func, WASM_THROW(except));
|
|
|
|
// Build the main test function.
|
|
BUILD(r, WASM_TRY_CATCH_ALL_T(
|
|
kWasmI32,
|
|
WASM_STMTS(WASM_I32V(kResult1),
|
|
WASM_IF(WASM_I32_EQZ(WASM_LOCAL_GET(0)),
|
|
WASM_STMTS(WASM_CALL_FUNCTION(
|
|
throw_func.function_index(),
|
|
WASM_I32V(7), WASM_I32V(9)),
|
|
WASM_DROP))),
|
|
WASM_STMTS(WASM_I32V(kResult0))));
|
|
|
|
if (execution_tier != TestExecutionTier::kInterpreter) {
|
|
// Need to call through JS to allow for creation of stack traces.
|
|
r.CheckCallViaJS(kResult0, 0);
|
|
r.CheckCallViaJS(kResult1, 1);
|
|
} else {
|
|
CHECK_EQ(kResult0, r.CallInterpreter(0));
|
|
CHECK_EQ(kResult1, r.CallInterpreter(1));
|
|
}
|
|
}
|
|
|
|
WASM_EXEC_TEST(TryCatchCallIndirect) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
WasmRunner<uint32_t, uint32_t> r(execution_tier);
|
|
byte except = r.builder().AddException(sigs.v_v());
|
|
constexpr uint32_t kResult0 = 23;
|
|
constexpr uint32_t kResult1 = 42;
|
|
|
|
// Build a throwing helper function.
|
|
WasmFunctionCompiler& throw_func = r.NewFunction(sigs.i_ii());
|
|
BUILD(throw_func, WASM_THROW(except));
|
|
byte sig_index = r.builder().AddSignature(sigs.i_ii());
|
|
throw_func.SetSigIndex(0);
|
|
|
|
// Add an indirect function table.
|
|
uint16_t indirect_function_table[] = {
|
|
static_cast<uint16_t>(throw_func.function_index())};
|
|
r.builder().AddIndirectFunctionTable(indirect_function_table,
|
|
arraysize(indirect_function_table));
|
|
|
|
// Build the main test function.
|
|
BUILD(r,
|
|
WASM_TRY_CATCH_T(
|
|
kWasmI32,
|
|
WASM_STMTS(WASM_I32V(kResult1),
|
|
WASM_IF(WASM_I32_EQZ(WASM_LOCAL_GET(0)),
|
|
WASM_STMTS(WASM_CALL_INDIRECT(
|
|
sig_index, WASM_I32V(7),
|
|
WASM_I32V(9), WASM_LOCAL_GET(0)),
|
|
WASM_DROP))),
|
|
WASM_I32V(kResult0), except));
|
|
|
|
if (execution_tier != TestExecutionTier::kInterpreter) {
|
|
// Need to call through JS to allow for creation of stack traces.
|
|
r.CheckCallViaJS(kResult0, 0);
|
|
r.CheckCallViaJS(kResult1, 1);
|
|
} else {
|
|
CHECK_EQ(kResult0, r.CallInterpreter(0));
|
|
CHECK_EQ(kResult1, r.CallInterpreter(1));
|
|
}
|
|
}
|
|
|
|
WASM_EXEC_TEST(TryCatchAllCallIndirect) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
WasmRunner<uint32_t, uint32_t> r(execution_tier);
|
|
byte except = r.builder().AddException(sigs.v_v());
|
|
constexpr uint32_t kResult0 = 23;
|
|
constexpr uint32_t kResult1 = 42;
|
|
|
|
// Build a throwing helper function.
|
|
WasmFunctionCompiler& throw_func = r.NewFunction(sigs.i_ii());
|
|
BUILD(throw_func, WASM_THROW(except));
|
|
byte sig_index = r.builder().AddSignature(sigs.i_ii());
|
|
throw_func.SetSigIndex(0);
|
|
|
|
// Add an indirect function table.
|
|
uint16_t indirect_function_table[] = {
|
|
static_cast<uint16_t>(throw_func.function_index())};
|
|
r.builder().AddIndirectFunctionTable(indirect_function_table,
|
|
arraysize(indirect_function_table));
|
|
|
|
// Build the main test function.
|
|
BUILD(r,
|
|
WASM_TRY_CATCH_ALL_T(
|
|
kWasmI32,
|
|
WASM_STMTS(WASM_I32V(kResult1),
|
|
WASM_IF(WASM_I32_EQZ(WASM_LOCAL_GET(0)),
|
|
WASM_STMTS(WASM_CALL_INDIRECT(
|
|
sig_index, WASM_I32V(7),
|
|
WASM_I32V(9), WASM_LOCAL_GET(0)),
|
|
WASM_DROP))),
|
|
WASM_I32V(kResult0)));
|
|
|
|
if (execution_tier != TestExecutionTier::kInterpreter) {
|
|
// Need to call through JS to allow for creation of stack traces.
|
|
r.CheckCallViaJS(kResult0, 0);
|
|
r.CheckCallViaJS(kResult1, 1);
|
|
} else {
|
|
CHECK_EQ(kResult0, r.CallInterpreter(0));
|
|
CHECK_EQ(kResult1, r.CallInterpreter(1));
|
|
}
|
|
}
|
|
|
|
WASM_COMPILED_EXEC_TEST(TryCatchCallExternal) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
HandleScope scope(CcTest::InitIsolateOnce());
|
|
const char* source = "(function() { throw 'ball'; })";
|
|
Handle<JSFunction> js_function =
|
|
Handle<JSFunction>::cast(v8::Utils::OpenHandle(
|
|
*v8::Local<v8::Function>::Cast(CompileRun(source))));
|
|
ManuallyImportedJSFunction import = {sigs.i_ii(), js_function};
|
|
WasmRunner<uint32_t, uint32_t> r(execution_tier, &import);
|
|
constexpr uint32_t kResult0 = 23;
|
|
constexpr uint32_t kResult1 = 42;
|
|
constexpr uint32_t kJSFunc = 0;
|
|
|
|
// Build the main test function.
|
|
BUILD(r, WASM_TRY_CATCH_ALL_T(
|
|
kWasmI32,
|
|
WASM_STMTS(
|
|
WASM_I32V(kResult1),
|
|
WASM_IF(WASM_I32_EQZ(WASM_LOCAL_GET(0)),
|
|
WASM_STMTS(WASM_CALL_FUNCTION(kJSFunc, WASM_I32V(7),
|
|
WASM_I32V(9)),
|
|
WASM_DROP))),
|
|
WASM_I32V(kResult0)));
|
|
|
|
// Need to call through JS to allow for creation of stack traces.
|
|
r.CheckCallViaJS(kResult0, 0);
|
|
r.CheckCallViaJS(kResult1, 1);
|
|
}
|
|
|
|
WASM_COMPILED_EXEC_TEST(TryCatchAllCallExternal) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
HandleScope scope(CcTest::InitIsolateOnce());
|
|
const char* source = "(function() { throw 'ball'; })";
|
|
Handle<JSFunction> js_function =
|
|
Handle<JSFunction>::cast(v8::Utils::OpenHandle(
|
|
*v8::Local<v8::Function>::Cast(CompileRun(source))));
|
|
ManuallyImportedJSFunction import = {sigs.i_ii(), js_function};
|
|
WasmRunner<uint32_t, uint32_t> r(execution_tier, &import);
|
|
constexpr uint32_t kResult0 = 23;
|
|
constexpr uint32_t kResult1 = 42;
|
|
constexpr uint32_t kJSFunc = 0;
|
|
|
|
// Build the main test function.
|
|
BUILD(r, WASM_TRY_CATCH_ALL_T(
|
|
kWasmI32,
|
|
WASM_STMTS(
|
|
WASM_I32V(kResult1),
|
|
WASM_IF(WASM_I32_EQZ(WASM_LOCAL_GET(0)),
|
|
WASM_STMTS(WASM_CALL_FUNCTION(kJSFunc, WASM_I32V(7),
|
|
WASM_I32V(9)),
|
|
WASM_DROP))),
|
|
WASM_I32V(kResult0)));
|
|
|
|
// Need to call through JS to allow for creation of stack traces.
|
|
r.CheckCallViaJS(kResult0, 0);
|
|
r.CheckCallViaJS(kResult1, 1);
|
|
}
|
|
|
|
namespace {
|
|
|
|
void TestTrapNotCaught(byte* code, size_t code_size,
|
|
TestExecutionTier execution_tier) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
WasmRunner<uint32_t> r(execution_tier, nullptr, "main",
|
|
kRuntimeExceptionSupport);
|
|
r.builder().AddMemory(kWasmPageSize);
|
|
constexpr uint32_t kResultSuccess = 23;
|
|
constexpr uint32_t kResultCaught = 47;
|
|
|
|
// Add an indirect function table.
|
|
const int kTableSize = 2;
|
|
r.builder().AddIndirectFunctionTable(nullptr, kTableSize);
|
|
|
|
// Build a trapping helper function.
|
|
WasmFunctionCompiler& trap_func = r.NewFunction(sigs.i_ii());
|
|
trap_func.Build(code, code + code_size);
|
|
|
|
// Build the main test function.
|
|
BUILD(r, WASM_TRY_CATCH_ALL_T(
|
|
kWasmI32,
|
|
WASM_STMTS(WASM_I32V(kResultSuccess),
|
|
WASM_CALL_FUNCTION(trap_func.function_index(),
|
|
WASM_I32V(7), WASM_I32V(9)),
|
|
WASM_DROP),
|
|
WASM_STMTS(WASM_I32V(kResultCaught))));
|
|
|
|
if (execution_tier != TestExecutionTier::kInterpreter) {
|
|
// Need to call through JS to allow for creation of stack traces.
|
|
r.CheckCallViaJSTraps();
|
|
} else {
|
|
r.CallInterpreter();
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
WASM_EXEC_TEST(TryCatchTrapUnreachable) {
|
|
byte code[] = {WASM_UNREACHABLE};
|
|
TestTrapNotCaught(code, arraysize(code), execution_tier);
|
|
}
|
|
|
|
WASM_EXEC_TEST(TryCatchTrapMemOutOfBounds) {
|
|
byte code[] = {WASM_LOAD_MEM(MachineType::Int32(), WASM_I32V_1(-1))};
|
|
TestTrapNotCaught(code, arraysize(code), execution_tier);
|
|
}
|
|
|
|
WASM_EXEC_TEST(TryCatchTrapDivByZero) {
|
|
byte code[] = {WASM_I32_DIVS(WASM_LOCAL_GET(0), WASM_I32V_1(0))};
|
|
TestTrapNotCaught(code, arraysize(code), execution_tier);
|
|
}
|
|
|
|
WASM_EXEC_TEST(TryCatchTrapRemByZero) {
|
|
byte code[] = {WASM_I32_REMS(WASM_LOCAL_GET(0), WASM_I32V_1(0))};
|
|
TestTrapNotCaught(code, arraysize(code), execution_tier);
|
|
}
|
|
|
|
WASM_EXEC_TEST(TryCatchTrapTableFill) {
|
|
EXPERIMENTAL_FLAG_SCOPE(reftypes);
|
|
int table_index = 0;
|
|
int length = 10; // OOB.
|
|
int start = 10; // OOB.
|
|
byte code[] = {WASM_TABLE_FILL(table_index, WASM_I32V(length),
|
|
WASM_REF_NULL(kFuncRefCode), WASM_I32V(start)),
|
|
WASM_I32V_1(42)};
|
|
TestTrapNotCaught(code, arraysize(code), execution_tier);
|
|
}
|
|
|
|
namespace {
|
|
// TODO(cleanup): Define in cctest.h and re-use where appropriate.
|
|
class IsolateScope {
|
|
public:
|
|
IsolateScope() {
|
|
v8::Isolate::CreateParams create_params;
|
|
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
|
isolate_ = v8::Isolate::New(create_params);
|
|
isolate_->Enter();
|
|
}
|
|
|
|
~IsolateScope() {
|
|
isolate_->Exit();
|
|
isolate_->Dispose();
|
|
}
|
|
|
|
v8::Isolate* isolate() { return isolate_; }
|
|
Isolate* i_isolate() { return reinterpret_cast<Isolate*>(isolate_); }
|
|
|
|
private:
|
|
v8::Isolate* isolate_;
|
|
};
|
|
} // namespace
|
|
|
|
UNINITIALIZED_WASM_EXEC_TEST(TestStackOverflowNotCaught) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
// FLAG_stack_size must be set before isolate initialization.
|
|
FlagScope<int32_t> stack_size(&v8::internal::FLAG_stack_size, 8);
|
|
|
|
IsolateScope isolate_scope;
|
|
LocalContext context(isolate_scope.isolate());
|
|
|
|
WasmRunner<uint32_t> r(execution_tier, nullptr, "main",
|
|
kRuntimeExceptionSupport, isolate_scope.i_isolate());
|
|
|
|
// Build a function that calls itself until stack overflow.
|
|
WasmFunctionCompiler& stack_overflow = r.NewFunction(sigs.v_v());
|
|
byte stack_overflow_code[] = {
|
|
kExprCallFunction, static_cast<byte>(stack_overflow.function_index())};
|
|
stack_overflow.Build(stack_overflow_code,
|
|
stack_overflow_code + arraysize(stack_overflow_code));
|
|
|
|
// Build the main test function.
|
|
BUILD(r, WASM_TRY_CATCH_ALL_T(
|
|
kWasmI32,
|
|
WASM_STMTS(WASM_I32V(1), kExprCallFunction,
|
|
static_cast<byte>(stack_overflow.function_index())),
|
|
WASM_STMTS(WASM_I32V(1))));
|
|
|
|
if (execution_tier != TestExecutionTier::kInterpreter) {
|
|
// Need to call through JS to allow for creation of stack traces.
|
|
r.CheckCallViaJSTraps();
|
|
} else {
|
|
constexpr int stopped = 0;
|
|
CHECK_EQ(stopped, r.CallInterpreter());
|
|
}
|
|
}
|
|
|
|
TEST(Regress1180457) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
WasmRunner<uint32_t> r(TestExecutionTier::kInterpreter);
|
|
constexpr uint32_t kResult0 = 23;
|
|
constexpr uint32_t kUnreachable = 42;
|
|
BUILD(r, WASM_TRY_CATCH_ALL_T(
|
|
kWasmI32,
|
|
WASM_TRY_DELEGATE_T(
|
|
kWasmI32, WASM_STMTS(WASM_I32V(kResult0), WASM_BR(0)), 0),
|
|
WASM_I32V(kUnreachable)));
|
|
|
|
CHECK_EQ(kResult0, r.CallInterpreter());
|
|
}
|
|
|
|
TEST(Regress1187896) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
WasmRunner<uint32_t> r(TestExecutionTier::kInterpreter);
|
|
byte try_sig = r.builder().AddSignature(sigs.v_i());
|
|
constexpr uint32_t kResult = 23;
|
|
BUILD(r, kExprI32Const, 0, kExprTry, try_sig, kExprDrop, kExprCatchAll,
|
|
kExprNop, kExprEnd, kExprI32Const, kResult);
|
|
CHECK_EQ(kResult, r.CallInterpreter());
|
|
}
|
|
|
|
TEST(Regress1190291) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
WasmRunner<uint32_t> r(TestExecutionTier::kInterpreter);
|
|
byte try_sig = r.builder().AddSignature(sigs.v_i());
|
|
BUILD(r, kExprUnreachable, kExprTry, try_sig, kExprCatchAll, kExprEnd,
|
|
kExprI32Const, 0);
|
|
r.CallInterpreter();
|
|
}
|
|
|
|
TEST(Regress1186795) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
WasmRunner<uint32_t> r(TestExecutionTier::kInterpreter);
|
|
byte except = r.builder().AddException(sigs.v_i());
|
|
BUILD(r,
|
|
WASM_TRY_CATCH_T(
|
|
kWasmI32,
|
|
WASM_STMTS(WASM_I32V(0), WASM_I32V(0), WASM_I32V(0), WASM_I32V(0),
|
|
WASM_I32V(0), WASM_I32V(0), WASM_I32V(0),
|
|
WASM_TRY_T(kWasmI32,
|
|
WASM_STMTS(WASM_I32V(0), WASM_THROW(except))),
|
|
WASM_DROP, WASM_DROP, WASM_DROP, WASM_DROP, WASM_DROP,
|
|
WASM_DROP, WASM_DROP),
|
|
WASM_NOP, except));
|
|
CHECK_EQ(0, r.CallInterpreter());
|
|
}
|
|
|
|
TEST(Regress1197408) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
WasmRunner<int32_t, int32_t, int32_t, int32_t> r(
|
|
TestExecutionTier::kInterpreter);
|
|
byte sig_id = r.builder().AddSignature(sigs.i_iii());
|
|
BUILD(r, WASM_STMTS(WASM_I32V(0), WASM_I32V(0), WASM_I32V(0), kExprTry,
|
|
sig_id, kExprTry, sig_id, kExprCallFunction, 0,
|
|
kExprDelegate, 0, kExprDelegate, 0));
|
|
CHECK_EQ(0, r.CallInterpreter(0, 0, 0));
|
|
}
|
|
|
|
TEST(Regress1212396) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
WasmRunner<int32_t> r(TestExecutionTier::kInterpreter);
|
|
byte except = r.builder().AddException(sigs.v_v());
|
|
BUILD(r, kExprTry, kVoidCode, kExprTry, kVoidCode, kExprI32Const, 0,
|
|
kExprThrow, except, kExprDelegate, 0, kExprCatch, except, kExprEnd,
|
|
kExprI32Const, 42);
|
|
CHECK_EQ(42, r.CallInterpreter());
|
|
}
|
|
|
|
TEST(Regress1219746) {
|
|
TestSignatures sigs;
|
|
EXPERIMENTAL_FLAG_SCOPE(eh);
|
|
WasmRunner<int32_t> r(TestExecutionTier::kInterpreter);
|
|
BUILD(r, kExprTry, kVoidCode, kExprI32Const, 0, kExprEnd);
|
|
CHECK_EQ(0, r.CallInterpreter());
|
|
}
|
|
|
|
} // namespace test_run_wasm_exceptions
|
|
} // namespace wasm
|
|
} // namespace internal
|
|
} // namespace v8
|