Commit ec8e14e6 authored by clemensh's avatar clemensh Committed by Commit bot

[wasm] Add a cctest for the stack on a wasm trap

In contrast to the existing cctest, this time the error is not thrown
from javascript, but by a trap in wasm. And in contrast to the mjsunit
tests, this checks the detailed stack trace, not the simple one.

R=jfb@chromium.org, mstarzinger@chromium.org, titzer@chromium.org
BUG=

Review URL: https://codereview.chromium.org/1884593002

Cr-Commit-Position: refs/heads/master@{#35665}
parent b1434ac4
......@@ -51,10 +51,10 @@ struct ExceptionInfo {
template <int N>
void CheckExceptionInfos(Isolate* isolate, Handle<Object> exc,
const ExceptionInfo (&excInfos)[N]) {
// check that it's indeed an Error object
// Check that it's indeed an Error object.
CHECK(Object::IsErrorObject(isolate, exc));
// extract stack frame from exception
// Extract stack frame from the exception.
Local<v8::Value> localExc = Utils::ToLocal(exc);
v8::Local<v8::StackTrace> stack = v8::Exception::GetStackTrace(localExc);
PrintStackTrace(stack);
......@@ -76,41 +76,83 @@ TEST(CollectDetailedWasmStack_ExplicitThrowFromJs) {
TestSignatures sigs;
TestingModule module;
// Initialize WasmFunctionCompiler first, since it sets up the HandleScope.
WasmFunctionCompiler comp1(sigs.v_v(), &module);
uint32_t jsThrowingIndex = module.AddJsFunction(
uint32_t js_throwing_index = module.AddJsFunction(
sigs.v_v(),
"(function js() {\n function a() {\n throw new Error(); };\n a(); })");
BUILD(comp1, WASM_CALL_FUNCTION0(jsThrowingIndex));
uint32_t wasmIndex = comp1.CompileAndAdd();
BUILD(comp1, WASM_CALL_FUNCTION0(js_throwing_index));
uint32_t wasm_index = comp1.CompileAndAdd();
WasmFunctionCompiler comp2(sigs.v_v(), &module);
BUILD(comp2, WASM_CALL_FUNCTION0(wasmIndex));
uint32_t wasmIndex2 = comp2.CompileAndAdd();
BUILD(comp2, WASM_CALL_FUNCTION0(wasm_index));
uint32_t wasm_index_2 = comp2.CompileAndAdd();
Handle<JSFunction> jsWasmWrapper = module.WrapCode(wasmIndex2);
Handle<JSFunction> js_wasm_wrapper = module.WrapCode(wasm_index_2);
Handle<JSFunction> jsTrampoline = Handle<JSFunction>::cast(
Handle<JSFunction> js_trampoline = Handle<JSFunction>::cast(
v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
CompileRun("(function callFn(fn) { fn(); })"))));
Isolate* isolate = jsWasmWrapper->GetIsolate();
Isolate* isolate = js_wasm_wrapper->GetIsolate();
isolate->SetCaptureStackTraceForUncaughtExceptions(true, 10,
v8::StackTrace::kOverview);
Handle<Object> global(isolate->context()->global_object(), isolate);
MaybeHandle<Object> excMaybe;
Handle<Object> args[] = {jsWasmWrapper};
MaybeHandle<Object> maybe_exc;
Handle<Object> args[] = {js_wasm_wrapper};
MaybeHandle<Object> returnObjMaybe =
Execution::TryCall(isolate, jsTrampoline, global, 1, args, &excMaybe);
Execution::TryCall(isolate, js_trampoline, global, 1, args, &maybe_exc);
CHECK(returnObjMaybe.is_null());
// line number is 1-based, with 0 == kNoLineNumberInfo
ExceptionInfo expectedExceptions[] = {
{"a", 3}, // comment to prevent clang-format complaints
// Line number is 1-based, with 0 == kNoLineNumberInfo.
ExceptionInfo expected_exceptions[] = {
{"a", 3}, // Comment to prevent clang-format complaints
{"js", 4}, // -
{"<WASM>", 0}, // -
{"<WASM>", 0}, // -
{"callFn", 1}};
CheckExceptionInfos(isolate, excMaybe.ToHandleChecked(), expectedExceptions);
CheckExceptionInfos(isolate, maybe_exc.ToHandleChecked(),
expected_exceptions);
}
// Trigger a trap in WASM, stack should be JS -> WASM -> WASM.
TEST(CollectDetailedWasmStack_WasmError) {
TestSignatures sigs;
TestingModule module;
WasmFunctionCompiler comp1(sigs.i_v(), &module, "exec_unreachable");
// Set the execution context, such that a runtime error can be thrown.
comp1.SetModuleContext();
BUILD(comp1, WASM_UNREACHABLE);
uint32_t wasm_index = comp1.CompileAndAdd();
WasmFunctionCompiler comp2(sigs.i_v(), &module, "call_exec_unreachable");
BUILD(comp2, WASM_CALL_FUNCTION0(wasm_index));
uint32_t wasm_index_2 = comp2.CompileAndAdd();
Handle<JSFunction> js_wasm_wrapper = module.WrapCode(wasm_index_2);
Handle<JSFunction> js_trampoline = Handle<JSFunction>::cast(
v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
CompileRun("(function callFn(fn) { fn(); })"))));
Isolate* isolate = js_wasm_wrapper->GetIsolate();
isolate->SetCaptureStackTraceForUncaughtExceptions(true, 10,
v8::StackTrace::kOverview);
Handle<Object> global(isolate->context()->global_object(), isolate);
MaybeHandle<Object> maybe_exc;
Handle<Object> args[] = {js_wasm_wrapper};
MaybeHandle<Object> maybe_return_obj =
Execution::TryCall(isolate, js_trampoline, global, 1, args, &maybe_exc);
CHECK(maybe_return_obj.is_null());
// Line number is 1-based, with 0 == kNoLineNumberInfo.
ExceptionInfo expected_exceptions[] = {
{"<WASM>", 0}, // Comment to prevent clang-format complaints.
{"<WASM>", 0},
{"callFn", 1}};
CheckExceptionInfos(isolate, maybe_exc.ToHandleChecked(),
expected_exceptions);
}
......@@ -410,13 +410,15 @@ class WasmFunctionWrapper : public HandleAndZoneScope,
class WasmFunctionCompiler : public HandleAndZoneScope,
private GraphAndBuilders {
public:
explicit WasmFunctionCompiler(FunctionSig* sig, TestingModule* module)
explicit WasmFunctionCompiler(FunctionSig* sig, TestingModule* module,
const char* debug_name = "<WASM UNNAMED>")
: GraphAndBuilders(main_zone()),
jsgraph(this->isolate(), this->graph(), this->common(), nullptr,
nullptr, this->machine()),
sig(sig),
descriptor_(nullptr),
testing_module_(module) {
testing_module_(module),
debug_name_(debug_name) {
if (module) {
// Get a new function from the testing module.
function_ = nullptr;
......@@ -438,6 +440,7 @@ class WasmFunctionCompiler : public HandleAndZoneScope,
// The call descriptor is initialized when the function is compiled.
CallDescriptor* descriptor_;
TestingModule* testing_module_;
const char* debug_name_;
WasmFunction* function_;
int function_index_;
LocalDeclEncoder local_decls;
......@@ -474,7 +477,7 @@ class WasmFunctionCompiler : public HandleAndZoneScope,
if (kPointerSize == 4) {
desc = testing_module_->GetI32WasmCallDescriptor(this->zone(), desc);
}
CompilationInfo info("wasm compile", this->isolate(), this->zone(),
CompilationInfo info(debug_name_, this->isolate(), this->zone(),
Code::ComputeFlags(Code::WASM_FUNCTION));
Handle<Code> result =
Pipeline::GenerateCodeForTesting(&info, desc, this->graph());
......@@ -500,6 +503,16 @@ class WasmFunctionCompiler : public HandleAndZoneScope,
if (function_) return function_;
return &testing_module_->module->functions[function_index_];
}
// Set the context, such that e.g. runtime functions can be called.
void SetModuleContext() {
if (!testing_module_->instance->context.is_null()) {
CHECK(testing_module_->instance->context.is_identical_to(
main_isolate()->native_context()));
return;
}
testing_module_->instance->context = main_isolate()->native_context();
}
};
// A helper class to build graphs from Wasm bytecode, generate machine
......
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