Commit 9d61228b authored by Michael Starzinger's avatar Michael Starzinger Committed by Commit Bot

[wasm] Handle external exception in the interpreter.

This implements preliminary handling of exceptions thrown by external
functions that have been imported into the module. Note that handling
internal function is still missing, but tests have been added.

R=clemensh@chromium.org
TEST=cctest/test-run-wasm-exceptions
BUG=v8:8091

Change-Id: I9d07739d8b4715a5643114fd7a868cdd8d72efd0
Reviewed-on: https://chromium-review.googlesource.com/c/1445751
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59199}
parent 3ef9af84
......@@ -882,10 +882,13 @@ class SideTable : public ZoneObject {
break;
}
case kExprThrow:
case kExprRethrow: {
case kExprRethrow:
case kExprCallFunction: {
if (exception_stack.empty()) break; // Nothing to do here.
// TODO(mstarzinger): The same needs to be done for calls, not only
// for "throw" and "rethrow". Factor this logic out accordingly.
// TODO(mstarzinger): For calls the stack height here is off when the
// callee either consumes or produces stack values. Test and fix!
DCHECK_GE(control_stack.size() - 1, exception_stack.back());
Control* c = &control_stack[exception_stack.back()];
if (!unreachable) c->else_label->Ref(i.pc(), stack_height);
......@@ -1082,7 +1085,9 @@ struct ExternalCallResult {
// The function was executed and returned normally.
EXTERNAL_RETURNED,
// The function was executed, threw an exception, and the stack was unwound.
EXTERNAL_UNWOUND
EXTERNAL_UNWOUND,
// The function was executed and threw an exception that was locally caught.
EXTERNAL_CAUGHT
};
Type type;
// If type is INTERNAL, this field holds the function to call internally.
......@@ -2529,6 +2534,9 @@ class ThreadImpl {
break;
case ExternalCallResult::EXTERNAL_UNWOUND:
return;
case ExternalCallResult::EXTERNAL_CAUGHT:
len = JumpToHandlerDelta(code, pc);
break;
}
if (result.type != ExternalCallResult::INTERNAL) break;
}
......@@ -2565,6 +2573,9 @@ class ThreadImpl {
break;
case ExternalCallResult::EXTERNAL_UNWOUND:
return;
case ExternalCallResult::EXTERNAL_CAUGHT:
len = JumpToHandlerDelta(code, pc);
break;
}
} break;
case kExprGetGlobal: {
......@@ -2928,10 +2939,11 @@ class ThreadImpl {
}
ExternalCallResult TryHandleException(Isolate* isolate) {
DCHECK(isolate->has_pending_exception()); // Assume exceptional return.
if (HandleException(isolate) == WasmInterpreter::Thread::UNWOUND) {
return {ExternalCallResult::EXTERNAL_UNWOUND};
}
return {ExternalCallResult::EXTERNAL_RETURNED};
return {ExternalCallResult::EXTERNAL_CAUGHT};
}
ExternalCallResult CallExternalWasmFunction(Isolate* isolate,
......
......@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/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"
......@@ -19,6 +20,7 @@ WASM_EXEC_TEST(TryCatchThrow) {
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_GET_LOCAL(0)),
......@@ -30,6 +32,94 @@ WASM_EXEC_TEST(TryCatchThrow) {
r.CheckCallViaJS(kResult1, 1);
}
WASM_EXEC_TEST(TryCatchCallDirect) {
TestSignatures sigs;
EXPERIMENTAL_FLAG_SCOPE(eh);
WasmRunner<uint32_t, uint32_t> r(execution_tier);
uint32_t 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<void>();
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_GET_LOCAL(0)),
WASM_CALL_FUNCTION0(throw_func.function_index()))),
WASM_STMTS(WASM_DROP, WASM_I32V(kResult0))));
// Need to call through JS to allow for creation of stack traces.
// TODO(mstarzinger): Enable the below tests once implemented.
// r.CheckCallViaJS(kResult0, 0);
r.CheckCallViaJS(kResult1, 1);
}
WASM_EXEC_TEST(TryCatchCallIndirect) {
TestSignatures sigs;
EXPERIMENTAL_FLAG_SCOPE(eh);
WasmRunner<uint32_t, uint32_t> r(execution_tier);
uint32_t 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.v_v());
BUILD(throw_func, WASM_THROW(except));
r.builder().AddSignature(sigs.v_v());
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));
r.builder().PopulateIndirectFunctionTable();
// Build the main test function.
BUILD(r, WASM_TRY_CATCH_T(
kWasmI32,
WASM_STMTS(WASM_I32V(kResult1),
WASM_IF(WASM_I32_EQZ(WASM_GET_LOCAL(0)),
WASM_CALL_INDIRECT0(0, WASM_GET_LOCAL(0)))),
WASM_STMTS(WASM_DROP, WASM_I32V(kResult0))));
// Need to call through JS to allow for creation of stack traces.
// TODO(mstarzinger): Enable the below tests once implemented.
// r.CheckCallViaJS(kResult0, 0);
r.CheckCallViaJS(kResult1, 1);
}
WASM_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.v_v(), 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_T(kWasmI32,
WASM_STMTS(WASM_I32V(kResult1),
WASM_IF(WASM_I32_EQZ(WASM_GET_LOCAL(0)),
WASM_CALL_FUNCTION0(kJSFunc))),
WASM_STMTS(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 test_run_wasm_exceptions
} // namespace wasm
} // namespace internal
......
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