From 42a10a9dfe04583206350d1db03814d65db434b6 Mon Sep 17 00:00:00 2001 From: "peter.rybin@gmail.com" Date: Tue, 25 Jun 2013 13:48:43 +0000 Subject: [PATCH] Allow debugger evaluate expressions to mute local variables R=yangguo@chromium.org Review URL: https://codereview.chromium.org/17636007 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15323 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/mirror-debugger.js | 31 ++++++++++++++++++++++++------- src/runtime.cc | 25 ++++++++++++++++++++++++- test/mjsunit/debug-evaluate-locals.js | 13 ++++++++++--- 3 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/mirror-debugger.js b/src/mirror-debugger.js index a997fce..91097ea 100644 --- a/src/mirror-debugger.js +++ b/src/mirror-debugger.js @@ -1699,13 +1699,30 @@ FrameMirror.prototype.stepInPositions = function() { FrameMirror.prototype.evaluate = function(source, disable_break, opt_context_object) { - var result = %DebugEvaluate(this.break_id_, - this.details_.frameId(), - this.details_.inlinedFrameIndex(), - source, - Boolean(disable_break), - opt_context_object); - return MakeMirror(result); + var result_array = %DebugEvaluate(this.break_id_, + this.details_.frameId(), + this.details_.inlinedFrameIndex(), + source, + Boolean(disable_break), + opt_context_object); + // Silently ignore local variables changes if the frame is optimized. + if (!this.isOptimizedFrame()) { + var local_scope_before = result_array[1]; + var local_scope_after = result_array[2]; + for (var n in local_scope_after) { + var value_before = local_scope_before[n]; + var value_after = local_scope_after[n]; + if (value_before !== value_after) { + %SetScopeVariableValue(this.break_id_, + this.details_.frameId(), + this.details_.inlinedFrameIndex(), + 0, + n, + value_after); + } + } + } + return MakeMirror(result_array[0]); }; diff --git a/src/runtime.cc b/src/runtime.cc index e42a9db..8917c58 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -12424,6 +12424,13 @@ static MaybeObject* DebugEvaluate(Isolate* isolate, // the same view of the values of parameters and local variables as if the // piece of JavaScript was evaluated at the point where the function on the // stack frame is currently stopped when we compile and run the (direct) eval. +// Returns array of +// #0: evaluate result +// #1: local variables scope materizalized as object before evaluation +// #2: local variables scope materizalized as object after evaluation +// Since user expression only reaches (and modifies) copies of local variables, +// those copies are returned to the caller to allow tracking the changes and +// manually updating the actual variables. RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { HandleScope scope(isolate); @@ -12523,7 +12530,23 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { } Handle receiver(frame->receiver(), isolate); - return DebugEvaluate(isolate, context, context_extension, receiver, source); + Object* evaluate_result_object; + { MaybeObject* maybe_result = + DebugEvaluate(isolate, context, context_extension, receiver, source); + if (!maybe_result->ToObject(&evaluate_result_object)) return maybe_result; + } + Handle evaluate_result(evaluate_result_object, isolate); + + Handle local_scope_after = MaterializeLocalScopeWithFrameInspector( + isolate, frame, &frame_inspector); + + Handle resultArray = + isolate->factory()->NewFixedArray(3); + resultArray->set(0, *evaluate_result); + resultArray->set(2, *local_scope); + resultArray->set(1, *local_scope_after); + + return *(isolate->factory()->NewJSArrayWithElements(resultArray)); } diff --git a/test/mjsunit/debug-evaluate-locals.js b/test/mjsunit/debug-evaluate-locals.js index a68162d..e6326e1 100644 --- a/test/mjsunit/debug-evaluate-locals.js +++ b/test/mjsunit/debug-evaluate-locals.js @@ -38,6 +38,7 @@ function h() { var b = 2; var eval = 5; // Overriding eval should not break anything. debugger; // Breakpoint. + return a; } function checkFrame0(frame) { @@ -60,7 +61,7 @@ function checkFrame0(frame) { function g() { var a = 3; eval("var b = 4;"); - h(); + return h() + a; } function checkFrame1(frame) { @@ -83,7 +84,7 @@ function f() { var a = 5; var b = 0; with ({b:6}) { - g(); + return g(); } } @@ -125,6 +126,10 @@ function listener(event, exec_state, event_data, data) { assertEquals(6, exec_state.frame(2).evaluate('b').value()); assertEquals("function", typeof exec_state.frame(2).evaluate('eval').value()); + assertEquals("foo", + exec_state.frame(0).evaluate('a = "foo"').value()); + assertEquals("bar", + exec_state.frame(1).evaluate('a = "bar"').value()); // Indicate that all was processed. listenerComplete = true; } @@ -137,7 +142,9 @@ function listener(event, exec_state, event_data, data) { // Add the debug event listener. Debug.setListener(listener); -f(); +var f_result = f(); + +assertEquals('foobar', f_result); // Make sure that the debug event listener was invoked. assertFalse(exception, "exception in listener") -- 2.7.4