Author: yu...@chromium.org
Date: Tue Jul 14 09:55:32 2009
New Revision: 2458

Added:
    branches/bleeding_edge/test/mjsunit/debug-stepin-accessor.js
Modified:
    branches/bleeding_edge/src/debug.cc
    branches/bleeding_edge/src/objects.cc
    branches/bleeding_edge/test/mjsunit/mjsunit.status

Log:
Support stepping into getters and setters.

Related Chromium bug:
http://code.google.com/p/chromium/issues/detail?id=16427

Review URL: http://codereview.chromium.org/149542

Modified: branches/bleeding_edge/src/debug.cc
==============================================================================
--- branches/bleeding_edge/src/debug.cc (original)
+++ branches/bleeding_edge/src/debug.cc Tue Jul 14 09:55:32 2009
@@ -334,8 +334,11 @@
        rinfo()->set_target_address(stub->entry());
      }
    } else {
-    // Step in through constructs call requires no changes to the running  
code.
-    ASSERT(RelocInfo::IsConstructCall(rmode()));
+    // Step in through construct call requires no changes to the running  
code.
+    // Step in through getters/setters should already be prepared as well
+    // because caller of this function (Debug::PrepareStep) is expected to
+    // flood the top frame's function with one shot breakpoints.
+    ASSERT(RelocInfo::IsConstructCall(rmode()) ||  
code->is_inline_cache_stub());
    }
  }

@@ -1087,10 +1090,18 @@

    // Compute whether or not the target is a call target.
    bool is_call_target = false;
+  bool is_load_or_store = false;
+  bool is_inline_cache_stub = false;
    if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) {
      Address target = it.rinfo()->target_address();
      Code* code = Code::GetCodeFromTargetAddress(target);
-    if (code->is_call_stub()) is_call_target = true;
+    if (code->is_call_stub()) {
+      is_call_target = true;
+    }
+    if (code->is_inline_cache_stub()) {
+      is_inline_cache_stub = true;
+      is_load_or_store = !is_call_target;
+    }
    }

    // If this is the last break code target step out is the only  
possibility.
@@ -1103,8 +1114,8 @@
        JSFunction* function =  
JSFunction::cast(frames_it.frame()->function());
        FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
      }
-  } else if (!(is_call_target || RelocInfo::IsConstructCall(it.rmode())) ||
-             step_action == StepNext || step_action == StepMin) {
+  } else if (!(is_inline_cache_stub ||  
RelocInfo::IsConstructCall(it.rmode()))
+             || step_action == StepNext || step_action == StepMin) {
      // Step next or step min.

      // Fill the current function with one-shot break points.
@@ -1117,8 +1128,19 @@
    } else {
      // Fill the current function with one-shot break points even for step  
in on
      // a call target as the function called might be a native function for
-    // which step in will not stop.
+    // which step in will not stop. It also prepares for stepping in
+    // getters/setters.
      FloodWithOneShot(shared);
+
+    if (is_load_or_store) {
+      // Remember source position and frame to handle step in  
getter/setter. If
+      // there is a custom getter/setter it will be handled in
+      // Object::Get/SetPropertyWithCallback, otherwise the step action  
will be
+      // propagated on the next Debug::Break.
+      thread_local_.last_statement_position_ =
+          debug_info->code()->SourceStatementPosition(frame->pc());
+      thread_local_.last_fp_ = frame->fp();
+    }

      // Step in or Step in min
      it.PrepareStepIn();

Modified: branches/bleeding_edge/src/objects.cc
==============================================================================
--- branches/bleeding_edge/src/objects.cc       (original)
+++ branches/bleeding_edge/src/objects.cc       Tue Jul 14 09:55:32 2009
@@ -216,6 +216,12 @@
    HandleScope scope;
    Handle<JSFunction> fun(JSFunction::cast(getter));
    Handle<Object> self(receiver);
+#ifdef ENABLE_DEBUGGER_SUPPORT
+  // Handle stepping into a getter if step into is active.
+  if (Debug::StepInActive()) {
+    Debug::HandleStepIn(fun, Handle<Object>::null(), 0, false);
+  }
+#endif
    bool has_pending_exception;
    Handle<Object> result =
        Execution::Call(fun, self, 0, NULL, &has_pending_exception);
@@ -1624,6 +1630,12 @@
    Handle<Object> value_handle(value);
    Handle<JSFunction> fun(JSFunction::cast(setter));
    Handle<JSObject> self(this);
+#ifdef ENABLE_DEBUGGER_SUPPORT
+  // Handle stepping into a setter if step into is active.
+  if (Debug::StepInActive()) {
+    Debug::HandleStepIn(fun, Handle<Object>::null(), 0, false);
+  }
+#endif
    bool has_pending_exception;
    Object** argv[] = { value_handle.location() };
    Execution::Call(fun, self, 1, argv, &has_pending_exception);

Added: branches/bleeding_edge/test/mjsunit/debug-stepin-accessor.js
==============================================================================
--- (empty file)
+++ branches/bleeding_edge/test/mjsunit/debug-stepin-accessor.js        Tue Jul 
14  
09:55:32 2009
@@ -0,0 +1,248 @@
+// 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
+
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+var exception = null;
+var state = 1;
+var expected_source_line_text = null;
+var expected_function_name = null;
+
+// Simple debug event handler which first time will cause 'step in' action
+// to get into g.call and than check that execution is pauesed inside
+// function 'g'.
+function listener(event, exec_state, event_data, data) {
+  try {
+    if (event == Debug.DebugEvent.Break) {
+      if (state == 1) {
+        exec_state.prepareStep(Debug.StepAction.StepIn, 2);
+        state = 2;
+      } else if (state == 2) {
+        assertEquals(expected_source_line_text,
+                     event_data.sourceLineText());
+        assertEquals(expected_function_name, event_data.func().name());
+        state = 3;
+      }
+    }
+  } catch(e) {
+    exception = e;
+  }
+};
+
+// Add the debug event listener.
+Debug.setListener(listener);
+
+
+var c = {
+  name: 'name ',
+  get getter1() {
+    return this.name;  // getter 1
+  },
+  get getter2() {
+    return {  // getter 2
+     'a': c.name
+    };
+  },
+  set setter1(n) {
+    this.name = n;  // setter 1
+  }
+};
+
+c.__defineGetter__('y', function getterY() {
+  return this.name;  // getter y
+});
+
+c.__defineGetter__(3, function getter3() {
+  return this.name;  // getter 3
+});
+
+c.__defineSetter__('y', function setterY(n) {
+  this.name = n;  // setter y
+});
+
+c.__defineSetter__(3, function setter3(n) {
+  this.name = n;  // setter 3
+});
+
+var d = {
+  'c': c,
+};
+
+function testGetter1_1() {
+  expected_function_name = 'getter1';
+  expected_source_line_text = '    return this.name;  // getter 1';
+  debugger;
+  var x = c.getter1;
+}
+
+function testGetter1_2() {
+  expected_function_name = 'getter1';
+  expected_source_line_text = '    return this.name;  // getter 1';
+  debugger;
+  var x = c['getter1'];
+}
+
+function testGetter1_3() {
+  expected_function_name = 'getter1';
+  expected_source_line_text = '    return this.name;  // getter 1';
+  debugger;
+  for (var i = 1; i < 2; i++) {
+    var x = c['getter' + i];
+  }
+}
+
+function testGetter1_4() {
+  expected_function_name = 'getter1';
+  expected_source_line_text = '    return this.name;  // getter 1';
+  debugger;
+  var x = d.c.getter1;
+}
+
+function testGetter1_5() {
+  expected_function_name = 'getter1';
+  expected_source_line_text = '    return this.name;  // getter 1';
+  for (var i = 2; i != 1; i--);
+  debugger;
+  var x = d.c['getter' + i];
+}
+
+function testGetter2_1() {
+  expected_function_name = 'getter2';
+  expected_source_line_text = '    return {  // getter 2';
+  for (var i = 2; i != 1; i--);
+  debugger;
+  var t = d.c.getter2.name;
+}
+
+
+function testGetterY_1() {
+  expected_function_name = 'getterY';
+  expected_source_line_text = '  return this.name;  // getter y';
+  debugger;
+  var t = d.c.y;
+}
+
+function testIndexedGetter3_1() {
+  expected_function_name = 'getter3';
+  expected_source_line_text = '  return this.name;  // getter 3';
+  debugger;
+  var r = d.c[3];
+}
+
+function testSetterY_1() {
+  expected_function_name = 'setterY';
+  expected_source_line_text = '  this.name = n;  // setter y';
+  debugger;
+  d.c.y = 'www';
+}
+
+function testIndexedSetter3_1() {
+  expected_function_name = 'setter3';
+  expected_source_line_text = '  this.name = n;  // setter 3';
+  var i = 3
+  debugger;
+  d.c[3] = 'www';
+}
+
+function testSetter1_1() {
+  expected_function_name = 'setter1';
+  expected_source_line_text = '    this.name = n;  // setter 1';
+  debugger;
+  d.c.setter1 = 'aa';
+}
+
+function testSetter1_2() {
+  expected_function_name = 'setter1';
+  expected_source_line_text = '    this.name = n;  // setter 1';
+  debugger;
+  d.c['setter1'] = 'bb';
+}
+
+function testSetter1_3() {
+  expected_function_name = 'setter1';
+  expected_source_line_text = '    this.name = n;  // setter 1';
+  for (var i = 2; i != 1; i--);
+  debugger;
+  d.c['setter' + i] = i;
+}
+
+var e = {
+  name: 'e'
+};
+e.__proto__ = c;
+
+function testProtoGetter1_1() {
+  expected_function_name = 'getter1';
+  expected_source_line_text = '    return this.name;  // getter 1';
+  debugger;
+  var x = e.getter1;
+}
+
+function testProtoSetter1_1() {
+  expected_function_name = 'setter1';
+  expected_source_line_text = '    this.name = n;  // setter 1';
+  debugger;
+  e.setter1 = 'aa';
+}
+
+function testProtoIndexedGetter3_1() {
+  expected_function_name = 'getter3';
+  expected_source_line_text = '  return this.name;  // getter 3';
+  debugger;
+  var x = e[3];
+}
+
+function testProtoIndexedSetter3_1() {
+  expected_function_name = 'setter3';
+  expected_source_line_text = '  this.name = n;  // setter 3';
+  debugger;
+  e[3] = 'new val';
+}
+
+function testProtoSetter1_2() {
+  expected_function_name = 'setter1';
+  expected_source_line_text = '    this.name = n;  // setter 1';
+  for (var i = 2; i != 1; i--);
+  debugger;
+  e['setter' + i] = 'aa';
+}
+
+for (var n in this) {
+  if (n.substr(0, 4) != 'test') {
+    continue;
+  }
+  state = 1;
+  this[n]();
+  assertNull(exception);
+  assertEquals(3, state);
+}
+
+// Get rid of the debug event listener.
+Debug.setListener(null);
\ No newline at end of file

Modified: branches/bleeding_edge/test/mjsunit/mjsunit.status
==============================================================================
--- branches/bleeding_edge/test/mjsunit/mjsunit.status  (original)
+++ branches/bleeding_edge/test/mjsunit/mjsunit.status  Tue Jul 14 09:55:32  
2009
@@ -58,6 +58,7 @@
  debug-multiple-breakpoints: CRASH || FAIL
  debug-setbreakpoint: CRASH || FAIL || PASS
  debug-step-stub-callfunction: SKIP
+debug-stepin-accessor: CRASH || FAIL
  debug-stepin-constructor: CRASH, FAIL
  debug-stepin-function-call: CRASH || FAIL
  debug-step: SKIP

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
v8-dev@googlegroups.com
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to