Commit a74fcf45 authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

Fixed the step in handling for function.apply.

The generic step-in mechanism floods the function called with break points to ensure a break is hit when entering the function. This generic mechanism was also used for function.apply. The code for function.apply contains a keyed load IC which was patched when stepping into function.apply. However function.apply enteres an internal frame not a JavaScript frame. This caused the logic for returning from the break in function.apply to fail as it forced a jump to the IC on the top JavaScript frame. The top JavaScript frame was the frame for the function calling function.apply not the frame for the apply function. Now returning from the break point in the keyed load IC in the apply code caused a jump to the code for the call IC for the function calling function.apply in the first place. Not a pretty sight.

Step-in now handles function.apply as a separate case where the actual JavaScript function called through apply is flodded with breakpoints instead of the function.apply function.

BUG=269
BUG=8210@chromium.org
Review URL: http://codereview.chromium.org/63055

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1683 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 2336579a
...@@ -1160,7 +1160,28 @@ void Debug::HandleStepIn(Handle<JSFunction> function, ...@@ -1160,7 +1160,28 @@ void Debug::HandleStepIn(Handle<JSFunction> function,
if (fp == Debug::step_in_fp()) { if (fp == Debug::step_in_fp()) {
// Don't allow step into functions in the native context. // Don't allow step into functions in the native context.
if (function->context()->global() != Top::context()->builtins()) { if (function->context()->global() != Top::context()->builtins()) {
Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared())); if (function->shared()->code() ==
Builtins::builtin(Builtins::FunctionApply)) {
// Handle function.apply separately to flood the function to be called
// and not the code for Builtins::FunctionApply. At the point of the
// call IC to call Builtins::FunctionApply the expression stack has the
// following content:
// symbol "apply"
// function apply was called on
// receiver for apply (first parameter to apply)
// arguments array for apply (second parameter to apply)
JavaScriptFrameIterator it;
ASSERT(it.frame()->fp() == fp);
ASSERT(it.frame()->GetExpression(1)->IsJSFunction());
if (it.frame()->GetExpression(1)->IsJSFunction()) {
Handle<JSFunction>
actual_function(JSFunction::cast(it.frame()->GetExpression(1)));
Handle<SharedFunctionInfo> actual_shared(actual_function->shared());
Debug::FloodWithOneShot(actual_shared);
}
} else {
Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
}
} }
} }
} }
......
...@@ -2406,6 +2406,45 @@ TEST(DebugStepNatives) { ...@@ -2406,6 +2406,45 @@ TEST(DebugStepNatives) {
} }
// Test that step in works with function.apply.
TEST(DebugStepFunctionApply) {
v8::HandleScope scope;
DebugLocalContext env;
// Create a function for testing stepping.
v8::Local<v8::Function> foo = CompileFunction(
&env,
"function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
"function foo(){ debugger; bar.apply(this, [1,2,3]); }",
"foo");
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
step_action = StepIn;
break_point_hit_count = 0;
foo->Call(env->Global(), 0, NULL);
// With stepping all break locations are hit.
CHECK_EQ(6, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
// Register a debug event listener which just counts.
v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
break_point_hit_count = 0;
foo->Call(env->Global(), 0, NULL);
// Without stepping only the debugger statement is hit.
CHECK_EQ(1, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
}
// Test break on exceptions. For each exception break combination the number // Test break on exceptions. For each exception break combination the number
// of debug event exception callbacks and message callbacks are collected. The // of debug event exception callbacks and message callbacks are collected. The
// number of debug event exception callbacks are used to check that the // number of debug event exception callbacks are used to check that the
......
...@@ -36,9 +36,6 @@ fuzz-natives: PASS, SKIP if ($mode == release || $arch == arm) ...@@ -36,9 +36,6 @@ fuzz-natives: PASS, SKIP if ($mode == release || $arch == arm)
big-object-literal: PASS, SKIP if ($arch == arm) big-object-literal: PASS, SKIP if ($arch == arm)
# Bug realiably triggers a debug assertion and crashed in release mode.
bugs/bug-269: CRASH, FAIL if $mode == debug
[ $arch == arm ] [ $arch == arm ]
# Slow tests which times out in debug mode. # Slow tests which times out in debug mode.
...@@ -64,7 +61,7 @@ debug-stepin-constructor: CRASH, FAIL ...@@ -64,7 +61,7 @@ debug-stepin-constructor: CRASH, FAIL
debug-step: SKIP debug-step: SKIP
debug-breakpoints: PASS || FAIL debug-breakpoints: PASS || FAIL
debug-handle: CRASH, FAIL if $mode == debug debug-handle: CRASH, FAIL if $mode == debug
bugs/bug-269: SKIP regress/regress-269: SKIP
# Bug number 130 http://code.google.com/p/v8/issues/detail?id=130 # Bug number 130 http://code.google.com/p/v8/issues/detail?id=130
# Fails on real ARM hardware but not on the simulator. # Fails on real ARM hardware but not on the simulator.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment