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
This commit is contained in:
parent
2336579a11
commit
a74fcf458c
23
src/debug.cc
23
src/debug.cc
@ -1160,7 +1160,28 @@ void Debug::HandleStepIn(Handle<JSFunction> function,
|
||||
if (fp == Debug::step_in_fp()) {
|
||||
// Don't allow step into functions in the native context.
|
||||
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) {
|
||||
}
|
||||
|
||||
|
||||
// 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
|
||||
// of debug event exception callbacks and message callbacks are collected. 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)
|
||||
|
||||
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 ]
|
||||
|
||||
# Slow tests which times out in debug mode.
|
||||
@ -64,7 +61,7 @@ debug-stepin-constructor: CRASH, FAIL
|
||||
debug-step: SKIP
|
||||
debug-breakpoints: PASS || FAIL
|
||||
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
|
||||
# Fails on real ARM hardware but not on the simulator.
|
||||
|
Loading…
Reference in New Issue
Block a user