From 29bb553b1d3096a6281fa98dd5c7e65f05318a22 Mon Sep 17 00:00:00 2001 From: "prybin@chromium.org" Date: Wed, 7 Aug 2013 12:27:22 +0000 Subject: [PATCH] Fix step in positions (include various calls and exclude current pc point), add a test R=yangguo@chromium.org Review URL: https://codereview.chromium.org/22198002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16100 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/debug.cc | 3 + src/execution.cc | 4 +- src/runtime.cc | 23 ++++-- test/mjsunit/debug-stepin-positions.js | 142 +++++++++++++++++++++++++++++++++ 4 files changed, 164 insertions(+), 8 deletions(-) create mode 100644 test/mjsunit/debug-stepin-positions.js diff --git a/src/debug.cc b/src/debug.cc index 03fa3a2..4966713 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -409,6 +409,9 @@ bool BreakLocationIterator::IsStepInLocation(Isolate* isolate) { HandleScope scope(debug_info_->GetIsolate()); Address target = rinfo()->target_address(); Handle target_code(Code::GetCodeFromTargetAddress(target)); + if (target_code->kind() == Code::STUB) { + return target_code->major_key() == CodeStub::CallFunction; + } return target_code->is_call_stub() || target_code->is_keyed_call_stub(); } else { return false; diff --git a/src/execution.cc b/src/execution.cc index d7b9cf5..ecfa1db 100644 --- a/src/execution.cc +++ b/src/execution.cc @@ -206,10 +206,12 @@ Handle Execution::TryCall(Handle func, catcher.SetCaptureMessage(false); *caught_exception = false; + // Get isolate now, because handle might be persistent + // and get destroyed in the next call. + Isolate* isolate = func->GetIsolate(); Handle result = Invoke(false, func, receiver, argc, args, caught_exception); - Isolate* isolate = func->GetIsolate(); if (*caught_exception) { ASSERT(catcher.HasCaught()); ASSERT(isolate->has_pending_exception()); diff --git a/src/runtime.cc b/src/runtime.cc index a1c0d75..a9121ce 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -12014,8 +12014,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetStepInPositions) { JavaScriptFrameIterator frame_it(isolate, id); JavaScriptFrame* frame = frame_it.frame(); + Handle fun = + Handle(frame->function()); Handle shared = - Handle(frame->function()->shared()); + Handle(fun->shared()); + + if (!isolate->debug()->EnsureDebugInfo(shared, fun)) { + return isolate->heap()->undefined_value(); + } + Handle debug_info = Debug::GetDebugInfo(shared); int len = 0; @@ -12028,12 +12035,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetStepInPositions) { int current_statement_pos = break_location_iterator.statement_position(); while (!break_location_iterator.Done()) { - if (break_location_iterator.IsStepInLocation(isolate)) { - Smi* position_value = Smi::FromInt(break_location_iterator.position()); - JSObject::SetElement(array, len, - Handle(position_value, isolate), - NONE, kNonStrictMode); - len++; + if (break_location_iterator.pc() > frame->pc()) { + if (break_location_iterator.IsStepInLocation(isolate)) { + Smi* position_value = Smi::FromInt(break_location_iterator.position()); + JSObject::SetElement(array, len, + Handle(position_value, isolate), + NONE, kNonStrictMode); + len++; + } } // Advance iterator. break_location_iterator.Next(); diff --git a/test/mjsunit/debug-stepin-positions.js b/test/mjsunit/debug-stepin-positions.js new file mode 100644 index 0000000..482e21b --- /dev/null +++ b/test/mjsunit/debug-stepin-positions.js @@ -0,0 +1,142 @@ +// Copyright 2008 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Flags: --expose-debug-as debug --nocrankshaft +// Get the Debug object exposed from the debug context global object. +Debug = debug.Debug + +function DebuggerStatement() { + debugger; +} + +function TestCase(fun) { + var exception = false; + var codeSnippet = undefined; + var resultPositions = undefined; + + function listener(event, exec_state, event_data, data) { + try { + if (event == Debug.DebugEvent.Break) { + Debug.setListener(null); + + var secondFrame = exec_state.frame(1); + codeSnippet = secondFrame.sourceLineText(); + resultPositions = secondFrame.stepInPositions(); + } + } catch (e) { + exception = e + } + } + + Debug.setListener(listener); + + fun(); + + Debug.setListener(null); + + assertTrue(!exception, exception); + + var expectedPositions = {}; + var markPattern = new RegExp("/\\*#\\*/", "g"); + + var matchResult; + while ( (matchResult = markPattern.exec(codeSnippet)) ) { + expectedPositions[matchResult.index] = true; + } + + print(codeSnippet); + + var decoratedResult = codeSnippet; + + function replaceStringRange(s, pos, substitute) { + return s.substring(0, pos) + substitute + + s.substring(pos + substitute.length); + } + + var markLength = 5; + var unexpectedPositionFound = false; + + for (var i = 0; i < resultPositions.length; i++) { + var col = resultPositions[i].position.column - markLength; + if (expectedPositions[col]) { + delete expectedPositions[col]; + decoratedResult = replaceStringRange(decoratedResult, col, "*YES*"); + } else { + decoratedResult = replaceStringRange(decoratedResult, col, "!BAD!"); + unexpectedPositionFound = true; + } + } + + print(decoratedResult); + + for (var n in expectedPositions) { + assertTrue(false, "Some positions are not reported: " + decoratedResult); + break; + } + assertFalse(unexpectedPositionFound, "Found unexpected position: " + + decoratedResult); +} + + +// Test cases. + +// Method calls. +var fun = function() { + var data = { + a: function() {} + }; + var res = [ DebuggerStatement(), data./*#*/a(), data[/*#*/String("a")]/*#*/(), data["a"]/*#*/(), data.a, data["a"] ]; +}; +TestCase(fun); + +// Function call on a value. +var fun = function() { + function g(p) { + return g; + } + var res = [ DebuggerStatement(), /*#*/g(2), /*#*/g(2)/*#*/(3), /*#*/g(0)/*#*/(0)/*#*/(g) ]; +}; +TestCase(fun); + +// Local function call, closure function call, +// local function construction call. +var fun = (function(p) { + return function() { + function f(a, b) { + } + var res = /*#*/f(DebuggerStatement(), /*#*/p(/*#*/new f())); + }; +})(Object); +TestCase(fun); + +// Global function, global object construction, calls before pause point. +var fun = (function(p) { + return function() { + var res = [ Math.abs(new Object()), DebuggerStatement(), Math./*#*/abs(4), /*#*/new Object()./*#*/toString() ]; + }; +})(Object); +TestCase(fun); -- 2.7.4