[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}
This commit is contained in:
parent
b1434ac460
commit
ec8e14e697
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user