[debug] fix break for builtin constructors with regular construct stub.

Regular construct stubs eventually call InvokeFunction, which does
performs debug hook checking. For builtins such as Object, Array, etc.
this approach does not work since they have specialized construct stubs
that do not check for the debug hook.

R=bmeurer@chromium.org

Bug: v8:178
Change-Id: I3e1f5d2dae1c7a6220b7236bd6ea71d83a65171f
Reviewed-on: https://chromium-review.googlesource.com/931702
Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
Commit-Queue: Yang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51503}
This commit is contained in:
Yang Guo 2018-02-22 16:19:22 +01:00 committed by Commit Bot
parent 3856d8d57d
commit 0b9b48b59d
2 changed files with 94 additions and 3 deletions

View File

@ -3468,6 +3468,9 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
if (m.Value()->IsJSFunction()) {
Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
// Do not reduce constructors with break points.
if (function->shared()->HasBreakInfo()) return NoChange();
// Don't inline cross native context.
if (function->native_context() != *native_context()) return NoChange();

View File

@ -1197,15 +1197,16 @@ TEST(BreakPointReturn) {
TEST(BreakPointBuiltin) {
i::FLAG_allow_natives_syntax = true;
i::FLAG_block_concurrent_recompilation = true;
break_point_hit_count = 0;
i::FLAG_experimental_inline_promise_constructor = true;
DebugLocalContext env;
v8::HandleScope scope(env->GetIsolate());
SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
v8::Local<v8::Function> builtin =
CompileRun("String.prototype.repeat").As<v8::Function>();
// === Test simple builtin ===
break_point_hit_count = 0;
v8::Local<v8::Function> builtin =
CompileRun("String.prototype.repeat").As<v8::Function>();
CompileRun("'a'.repeat(10)");
CHECK_EQ(0, break_point_hit_count);
@ -1219,6 +1220,41 @@ TEST(BreakPointBuiltin) {
CompileRun("'b'.repeat(10)");
CHECK_EQ(1, break_point_hit_count);
// === Test bound function from a builtin ===
break_point_hit_count = 0;
builtin = CompileRun(
"var boundrepeat = String.prototype.repeat.bind('a');"
"String.prototype.repeat")
.As<v8::Function>();
CompileRun("boundrepeat(10)");
CHECK_EQ(0, break_point_hit_count);
// Run with breakpoint.
bp = SetBreakPoint(builtin, 0);
CompileRun("boundrepeat(10)");
CHECK_EQ(1, break_point_hit_count);
// Run without breakpoints.
ClearBreakPoint(bp);
CompileRun("boundrepeat(10)");
CHECK_EQ(1, break_point_hit_count);
// === Test constructor builtin (for ones with normal construct stubs) ===
break_point_hit_count = 0;
builtin = CompileRun("Promise").As<v8::Function>();
CompileRun("new Promise(()=>{})");
CHECK_EQ(0, break_point_hit_count);
// Run with breakpoint.
bp = SetBreakPoint(builtin, 0);
CompileRun("new Promise(()=>{})");
CHECK_EQ(1, break_point_hit_count);
// Run without breakpoints.
ClearBreakPoint(bp);
CompileRun("new Promise(()=>{})");
CHECK_EQ(1, break_point_hit_count);
// === Test inlined builtin ===
break_point_hit_count = 0;
builtin = CompileRun("Math.sin").As<v8::Function>();
@ -1245,6 +1281,58 @@ TEST(BreakPointBuiltin) {
CompileRun("test(0.3);");
CHECK_EQ(3, break_point_hit_count);
// === Test inlined bound builtin ===
break_point_hit_count = 0;
builtin = CompileRun("String.prototype.repeat").As<v8::Function>();
CompileRun("function test(x) { return 'a' + boundrepeat(x) }");
CompileRun(
"test(4); test(5);"
"%OptimizeFunctionOnNextCall(test); test(6);");
CHECK_EQ(0, break_point_hit_count);
// Run with breakpoint.
bp = SetBreakPoint(builtin, 0);
CompileRun("'a'.repeat(2);");
CHECK_EQ(1, break_point_hit_count);
CompileRun("test(7);");
CHECK_EQ(2, break_point_hit_count);
// Re-optimize.
CompileRun("%OptimizeFunctionOnNextCall(test);");
CompileRun("test(8);");
CHECK_EQ(3, break_point_hit_count);
// Run without breakpoints.
ClearBreakPoint(bp);
CompileRun("test(9);");
CHECK_EQ(3, break_point_hit_count);
// === Test inlined constructor builtin (regular construct builtin) ===
break_point_hit_count = 0;
builtin = CompileRun("Promise").As<v8::Function>();
CompileRun("function test(x) { return new Promise(()=>x); }");
CompileRun(
"test(4); test(5);"
"%OptimizeFunctionOnNextCall(test); test(6);");
CHECK_EQ(0, break_point_hit_count);
// Run with breakpoint.
bp = SetBreakPoint(builtin, 0);
CompileRun("new Promise();");
CHECK_EQ(1, break_point_hit_count);
CompileRun("test(7);");
CHECK_EQ(2, break_point_hit_count);
// Re-optimize.
CompileRun("%OptimizeFunctionOnNextCall(test);");
CompileRun("test(8);");
CHECK_EQ(3, break_point_hit_count);
// Run without breakpoints.
ClearBreakPoint(bp);
CompileRun("test(9);");
CHECK_EQ(3, break_point_hit_count);
// === Test concurrent optimization ===
break_point_hit_count = 0;
builtin = CompileRun("Math.sin").As<v8::Function>();