diff --git a/src/debug/debug-frames.cc b/src/debug/debug-frames.cc index c98f911f75..5da1656fad 100644 --- a/src/debug/debug-frames.cc +++ b/src/debug/debug-frames.cc @@ -77,23 +77,11 @@ Handle FrameInspector::GetExpression(int index) { : handle(frame_->GetExpression(index), isolate_); } - int FrameInspector::GetSourcePosition() { - if (is_optimized_) return deoptimized_frame_->GetSourcePosition(); - AbstractCode* code; - int code_offset; - if (is_interpreted_) { - InterpretedFrame* frame = reinterpret_cast(frame_); - code = AbstractCode::cast(frame->GetBytecodeArray()); - code_offset = frame->GetBytecodeOffset(); - } else { - code = AbstractCode::cast(frame_->LookupCode()); - code_offset = static_cast(frame_->pc() - code->instruction_start()); - } - return code->SourcePosition(code_offset); + return is_optimized_ ? deoptimized_frame_->GetSourcePosition() + : frame_->position(); } - bool FrameInspector::IsConstructor() { return is_optimized_ && !is_bottommost_ ? deoptimized_frame_->HasConstructStub() diff --git a/src/debug/mirrors.js b/src/debug/mirrors.js index 165e172449..e5801a46be 100644 --- a/src/debug/mirrors.js +++ b/src/debug/mirrors.js @@ -1878,6 +1878,15 @@ FrameMirror.prototype.func = function() { }; +FrameMirror.prototype.script = function() { + if (!this.script_) { + this.script_ = MakeMirror(this.details_.script()); + } + + return this.script_; +} + + FrameMirror.prototype.receiver = function() { return MakeMirror(this.details_.receiver()); }; @@ -1954,12 +1963,9 @@ FrameMirror.prototype.sourcePosition = function() { FrameMirror.prototype.sourceLocation = function() { - var func = this.func(); - if (func.resolved()) { - var script = func.script(); - if (script) { - return script.locationFromPosition(this.sourcePosition(), true); - } + var script = this.script(); + if (script) { + return script.locationFromPosition(this.sourcePosition(), true); } }; diff --git a/src/frames.cc b/src/frames.cc index c67fdc2d94..92a98e8c98 100644 --- a/src/frames.cc +++ b/src/frames.cc @@ -720,6 +720,12 @@ Object* StandardFrame::context() const { return isolate()->heap()->undefined_value(); } +int StandardFrame::position() const { + AbstractCode* code = AbstractCode::cast(LookupCode()); + int code_offset = static_cast(pc() - code->instruction_start()); + return code->SourcePosition(code_offset); +} + int StandardFrame::ComputeExpressionsCount() const { Address base = GetExpressionAddress(0); Address limit = sp() - kPointerSize; @@ -1335,6 +1341,12 @@ Object* OptimizedFrame::StackSlotAt(int index) const { return Memory::Object_at(fp() + StackSlotOffsetRelativeToFp(index)); } +int InterpretedFrame::position() const { + AbstractCode* code = AbstractCode::cast(GetBytecodeArray()); + int code_offset = GetBytecodeOffset(); + return code->SourcePosition(code_offset); +} + int InterpretedFrame::LookupExceptionHandlerInTable( int* context_register, HandlerTable::CatchPrediction* prediction) { BytecodeArray* bytecode = function()->shared()->bytecode_array(); @@ -1474,10 +1486,22 @@ uint32_t WasmFrame::function_index() const { Script* WasmFrame::script() const { Handle wasm(JSObject::cast(wasm_obj()), isolate()); + if (wasm::WasmIsAsmJs(*wasm, isolate())) { + return *wasm::GetAsmWasmScript(wasm); + } Handle debug_info = wasm::GetDebugInfo(wasm); return wasm::WasmDebugInfo::GetFunctionScript(debug_info, function_index()); } +int WasmFrame::position() const { + int position = StandardFrame::position(); + if (wasm::WasmIsAsmJs(wasm_obj(), isolate())) { + Handle wasm(JSObject::cast(wasm_obj()), isolate()); + position = wasm::GetAsmWasmSourcePosition(wasm, function_index(), position); + } + return position; +} + int WasmFrame::LookupExceptionHandlerInTable(int* stack_slots) { DCHECK_NOT_NULL(stack_slots); Code* code = LookupCode(); diff --git a/src/frames.h b/src/frames.h index 373f4de92c..b363b90dc2 100644 --- a/src/frames.h +++ b/src/frames.h @@ -734,6 +734,7 @@ class StandardFrame : public StackFrame { virtual Object* receiver() const; virtual Script* script() const; virtual Object* context() const; + virtual int position() const; // Access the expressions in the stack frame including locals. inline Object* GetExpression(int index) const; @@ -957,6 +958,9 @@ class InterpretedFrame : public JavaScriptFrame { public: Type type() const override { return INTERPRETED; } + // Accessors. + int position() const override; + // Lookup exception handler for current {pc}, returns -1 if none found. int LookupExceptionHandlerInTable( int* data, HandlerTable::CatchPrediction* prediction) override; @@ -1067,6 +1071,7 @@ class WasmFrame : public StandardFrame { Object* wasm_obj() const; uint32_t function_index() const; Script* script() const override; + int position() const override; static WasmFrame* cast(StackFrame* frame) { DCHECK(frame->is_wasm()); diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc index 8f99797fde..f133832a89 100644 --- a/src/wasm/wasm-module.cc +++ b/src/wasm/wasm-module.cc @@ -1388,33 +1388,8 @@ class WasmInstanceBuilder { FlushICache(isolate_, code_table); //-------------------------------------------------------------------------- - // Run the start function if one was specified. + // Set up and link the new instance. //-------------------------------------------------------------------------- - if (compiled_module_->has_startup_function()) { - Handle startup_data = compiled_module_->startup_function(); - HandleScope scope(isolate_); - int32_t start_index = - startup_data->GetValueChecked(isolate_, kExportIndex)->value(); - Handle startup_code = - code_table->GetValueChecked(isolate_, start_index); - int arity = Smi::cast(startup_data->get(kExportArity))->value(); - MaybeHandle startup_signature = - startup_data->GetValue(isolate_, kExportedSignature); - Handle startup_fct = WrapExportCodeAsJSFunction( - isolate_, startup_code, factory->InternalizeUtf8String("start"), - arity, startup_signature, instance); - RecordStats(isolate_, *startup_code); - // Call the JS function. - Handle undefined = factory->undefined_value(); - MaybeHandle retval = - Execution::Call(isolate_, startup_fct, undefined, 0, nullptr); - - if (retval.is_null()) { - thrower_->Error("WASM.instantiateModule(): start function failed"); - return nothing; - } - } - { Handle global_handle = isolate_->global_handles()->Create(*instance); @@ -1450,6 +1425,38 @@ class WasmInstanceBuilder { } } + //-------------------------------------------------------------------------- + // Run the start function if one was specified. + //-------------------------------------------------------------------------- + if (compiled_module_->has_startup_function()) { + Handle startup_data = compiled_module_->startup_function(); + HandleScope scope(isolate_); + int32_t start_index = + startup_data->GetValueChecked(isolate_, kExportIndex)->value(); + Handle startup_code = + code_table->GetValueChecked(isolate_, start_index); + int arity = Smi::cast(startup_data->get(kExportArity))->value(); + MaybeHandle startup_signature = + startup_data->GetValue(isolate_, kExportedSignature); + Handle startup_fct = WrapExportCodeAsJSFunction( + isolate_, startup_code, factory->InternalizeUtf8String("start"), + arity, startup_signature, instance); + RecordStats(isolate_, *startup_code); + // Call the JS function. + Handle undefined = factory->undefined_value(); + MaybeHandle retval = + Execution::Call(isolate_, startup_fct, undefined, 0, nullptr); + + if (retval.is_null()) { + thrower_->Error("WASM.instantiateModule(): start function failed"); + // It's unfortunate that the new instance is already linked in the + // chain. However, we need to set up everything before executing the + // start function, such that stack trace information can be generated + // correctly already in the start function. + return nothing; + } + } + DCHECK(wasm::IsWasmObject(*instance)); TRACE("Finishing instance %d\n", compiled_module_->instance_id()); diff --git a/test/mjsunit/wasm/asm-debug.js b/test/mjsunit/wasm/asm-debug.js new file mode 100644 index 0000000000..5a1891a597 --- /dev/null +++ b/test/mjsunit/wasm/asm-debug.js @@ -0,0 +1,89 @@ +// Copyright 2016 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. + +// Flags: --expose-wasm --expose-debug-as debug --validate-asm + +Debug = debug.Debug + +// Initialized in setup(). +var exception; +var break_count; +var num_wasm_scripts; +var module; + +var filename = '(?:[^ ]+/)?test/mjsunit/wasm/asm-debug.js'; +filename = filename.replace(/\//g, '[/\\\\]'); + +var expected_stack_entries = []; + +function listener(event, exec_state, event_data, data) { + try { + if (event == Debug.DebugEvent.Break) { + ++break_count; + // Request frame details. + var num_frames = exec_state.frameCount(); + assertEquals( + expected_stack_entries.length, num_frames, 'number of frames'); + print('Stack Trace (length ' + num_frames + '):'); + for (var i = 0; i < num_frames; ++i) { + var frame = exec_state.frame(i); + var script = frame.script(); + assertNotNull(script); + var line = frame.sourceLine() + 1; + var column = frame.sourceColumn() + 1; + var funcName = frame.func().name(); + var name = script.name(); + print( + ' [' + i + '] ' + funcName + ' (' + name + ':' + line + ':' + + column + ')'); + assertMatches(filename, name, 'name'); + assertEquals( + expected_stack_entries[i][0], funcName, 'function name at ' + i); + assertEquals(expected_stack_entries[i][1], line, 'line at ' + i); + assertEquals(expected_stack_entries[i][2], column, 'column at ' + i); + } + } + } catch (e) { + print('exception: ' + e); + exception = e; + } +}; + +function generateWasmFromAsmJs(stdlib, foreign, heap) { + 'use asm'; + var debugger_fun = foreign.call_debugger; + function callDebugger() { + debugger_fun(); + } + function redirectFun() { + callDebugger(); + } + return redirectFun; +} + +function call_debugger() { + debugger; +} + +function setup() { + exception = null; + break_count = 0; +} + +(function FrameInspection() { + setup(); + var fun = + generateWasmFromAsmJs(this, {'call_debugger': call_debugger}, undefined); + expected_stack_entries = [ + ['call_debugger', 66, 3], // -- + ['callDebugger', 57, 5], // -- + ['redirectFun', 60, 5], // -- + ['FrameInspection', 86, 3], // -- + ['', 89, 3] + ]; + Debug.setListener(listener); + fun(); + Debug.setListener(null); + assertEquals(1, break_count); +})();