Commit 47fce35e authored by yangguo's avatar yangguo Committed by Commit bot

Debugger: correctly redirect code with no stack check.

This fix makes the redirect mechanism a bit more stable.

R=mvstanton@chromium.org

Review URL: https://codereview.chromium.org/1269733002

Cr-Commit-Position: refs/heads/master@{#29936}
parent 0dc4c959
...@@ -1311,13 +1311,10 @@ void Debug::ClearStepNext() { ...@@ -1311,13 +1311,10 @@ void Debug::ClearStepNext() {
} }
// We start counting call sites from the stack check because the declaration bool MatchingCodeTargets(Code* target1, Code* target2) {
// code at the start of the function may have changed on recompile. if (target1 == target2) return true;
static void SkipToStackCheck(Isolate* isolate, RelocIterator* it) { if (target1->kind() != target2->kind()) return false;
while (Code::GetCodeFromTargetAddress(it->rinfo()->target_address()) != return target1->is_handler() || target1->is_inline_cache_stub();
*isolate->builtins()->StackCheck()) {
it->next();
}
} }
...@@ -1328,24 +1325,42 @@ static Address ComputeNewPcForRedirect(Code* new_code, Code* old_code, ...@@ -1328,24 +1325,42 @@ static Address ComputeNewPcForRedirect(Code* new_code, Code* old_code,
DCHECK_EQ(old_code->kind(), Code::FUNCTION); DCHECK_EQ(old_code->kind(), Code::FUNCTION);
DCHECK_EQ(new_code->kind(), Code::FUNCTION); DCHECK_EQ(new_code->kind(), Code::FUNCTION);
DCHECK(new_code->has_debug_break_slots()); DCHECK(new_code->has_debug_break_slots());
int mask = RelocInfo::kCodeTargetMask; static const int mask = RelocInfo::kCodeTargetMask;
int index = 0;
// Find the target of the current call.
Code* target = NULL;
intptr_t delta = 0; intptr_t delta = 0;
Isolate* isolate = new_code->GetIsolate(); for (RelocIterator it(old_code, mask); !it.done(); it.next()) {
RelocIterator old_it(old_code, mask); RelocInfo* rinfo = it.rinfo();
for (SkipToStackCheck(isolate, &old_it); !old_it.done(); old_it.next()) {
RelocInfo* rinfo = old_it.rinfo();
Address current_pc = rinfo->pc(); Address current_pc = rinfo->pc();
// The frame PC is behind the call instruction by the call instruction size. // The frame PC is behind the call instruction by the call instruction size.
if (current_pc > old_pc) break; if (current_pc > old_pc) break;
index++;
delta = old_pc - current_pc; delta = old_pc - current_pc;
target = Code::GetCodeFromTargetAddress(rinfo->target_address());
}
// Count the number of calls to the same target before the current call.
int index = 0;
for (RelocIterator it(old_code, mask); !it.done(); it.next()) {
RelocInfo* rinfo = it.rinfo();
Address current_pc = rinfo->pc();
if (current_pc > old_pc) break;
Code* current = Code::GetCodeFromTargetAddress(rinfo->target_address());
if (MatchingCodeTargets(target, current)) index++;
}
DCHECK(index > 0);
// Repeat the count on the new code to find corresponding call.
for (RelocIterator it(new_code, mask); !it.done(); it.next()) {
RelocInfo* rinfo = it.rinfo();
Code* current = Code::GetCodeFromTargetAddress(rinfo->target_address());
if (MatchingCodeTargets(target, current)) index--;
if (index == 0) return rinfo->pc() + delta;
} }
RelocIterator new_it(new_code, mask); UNREACHABLE();
SkipToStackCheck(isolate, &new_it); return NULL;
for (int i = 1; i < index; i++) new_it.next();
return new_it.rinfo()->pc() + delta;
} }
......
...@@ -348,6 +348,11 @@ void FullCodeGenerator::Generate() { ...@@ -348,6 +348,11 @@ void FullCodeGenerator::Generate() {
VisitDeclarations(scope()->declarations()); VisitDeclarations(scope()->declarations());
} }
// Assert that the declarations do not use ICs. Otherwise the debugger
// won't be able to redirect a PC at an IC to the correct IC in newly
// recompiled code.
DCHECK_EQ(0, ic_total_count_);
{ Comment cmnt(masm_, "[ Stack check"); { Comment cmnt(masm_, "[ Stack check");
PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS); PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
Label ok; Label ok;
......
...@@ -353,6 +353,11 @@ void FullCodeGenerator::Generate() { ...@@ -353,6 +353,11 @@ void FullCodeGenerator::Generate() {
VisitDeclarations(scope()->declarations()); VisitDeclarations(scope()->declarations());
} }
// Assert that the declarations do not use ICs. Otherwise the debugger
// won't be able to redirect a PC at an IC to the correct IC in newly
// recompiled code.
DCHECK_EQ(0, ic_total_count_);
{ {
Comment cmnt(masm_, "[ Stack check"); Comment cmnt(masm_, "[ Stack check");
PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS); PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
......
...@@ -350,6 +350,11 @@ void FullCodeGenerator::Generate() { ...@@ -350,6 +350,11 @@ void FullCodeGenerator::Generate() {
VisitDeclarations(scope()->declarations()); VisitDeclarations(scope()->declarations());
} }
// Assert that the declarations do not use ICs. Otherwise the debugger
// won't be able to redirect a PC at an IC to the correct IC in newly
// recompiled code.
DCHECK_EQ(0, ic_total_count_);
{ Comment cmnt(masm_, "[ Stack check"); { Comment cmnt(masm_, "[ Stack check");
PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS); PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
Label ok; Label ok;
......
...@@ -366,6 +366,11 @@ void FullCodeGenerator::Generate() { ...@@ -366,6 +366,11 @@ void FullCodeGenerator::Generate() {
VisitDeclarations(scope()->declarations()); VisitDeclarations(scope()->declarations());
} }
// Assert that the declarations do not use ICs. Otherwise the debugger
// won't be able to redirect a PC at an IC to the correct IC in newly
// recompiled code.
DCHECK_EQ(0, ic_total_count_);
{ Comment cmnt(masm_, "[ Stack check"); { Comment cmnt(masm_, "[ Stack check");
PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS); PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
Label ok; Label ok;
......
...@@ -360,6 +360,12 @@ void FullCodeGenerator::Generate() { ...@@ -360,6 +360,12 @@ void FullCodeGenerator::Generate() {
{ Comment cmnt(masm_, "[ Declarations"); { Comment cmnt(masm_, "[ Declarations");
VisitDeclarations(scope()->declarations()); VisitDeclarations(scope()->declarations());
} }
// Assert that the declarations do not use ICs. Otherwise the debugger
// won't be able to redirect a PC at an IC to the correct IC in newly
// recompiled code.
DCHECK_EQ(0, ic_total_count_);
{ Comment cmnt(masm_, "[ Stack check"); { Comment cmnt(masm_, "[ Stack check");
PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS); PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
Label ok; Label ok;
......
...@@ -360,6 +360,11 @@ void FullCodeGenerator::Generate() { ...@@ -360,6 +360,11 @@ void FullCodeGenerator::Generate() {
VisitDeclarations(scope()->declarations()); VisitDeclarations(scope()->declarations());
} }
// Assert that the declarations do not use ICs. Otherwise the debugger
// won't be able to redirect a PC at an IC to the correct IC in newly
// recompiled code.
DCHECK_EQ(0, ic_total_count_);
{ {
Comment cmnt(masm_, "[ Stack check"); Comment cmnt(masm_, "[ Stack check");
PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS); PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
......
...@@ -348,6 +348,11 @@ void FullCodeGenerator::Generate() { ...@@ -348,6 +348,11 @@ void FullCodeGenerator::Generate() {
VisitDeclarations(scope()->declarations()); VisitDeclarations(scope()->declarations());
} }
// Assert that the declarations do not use ICs. Otherwise the debugger
// won't be able to redirect a PC at an IC to the correct IC in newly
// recompiled code.
DCHECK_EQ(0, ic_total_count_);
{ Comment cmnt(masm_, "[ Stack check"); { Comment cmnt(masm_, "[ Stack check");
PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS); PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
Label ok; Label ok;
......
...@@ -347,6 +347,11 @@ void FullCodeGenerator::Generate() { ...@@ -347,6 +347,11 @@ void FullCodeGenerator::Generate() {
VisitDeclarations(scope()->declarations()); VisitDeclarations(scope()->declarations());
} }
// Assert that the declarations do not use ICs. Otherwise the debugger
// won't be able to redirect a PC at an IC to the correct IC in newly
// recompiled code.
DCHECK_EQ(0, ic_total_count_);
{ Comment cmnt(masm_, "[ Stack check"); { Comment cmnt(masm_, "[ Stack check");
PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS); PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
Label ok; Label ok;
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --expose-debug-as debug
function f(x) {
// This function compiles into code that only throws a redeclaration
// error. It contains no stack check and has no function body.
const x = 0;
return x;
}
function g() {
f(0);
}
var exception = null;
var called = false;
var Debug = debug.Debug;
Debug.setBreakOnException();
function listener(event, exec_state, event_data, data) {
if (event != Debug.DebugEvent.Exception) return;
try {
called = true;
Debug.setBreakPoint(f, 1);
} catch (e) {
exception = e;
}
}
Debug.setListener(listener);
assertThrows(g);
assertNull(exception);
assertTrue(called);
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