From 8965b683ce39bc3c24ed2466d189323d81a70852 Mon Sep 17 00:00:00 2001 From: yangguo Date: Fri, 10 Jul 2015 01:49:14 -0700 Subject: [PATCH] Debugger: use debug break slot to break on call. Break point at calls are currently set via IC. To change this, we need to set debug break slots instead. We also need to distinguish those debug break slots as calls to support step-in. To implement this, we add a data field to debug break reloc info to indicate non-call debug breaks or in case of call debug breaks, the number of arguments. We can later use this to find the callee on the evaluation stack in Debug::PrepareStep. BUG=v8:4269 R=ulan@chromium.org LOG=N Review URL: https://codereview.chromium.org/1222093007 Cr-Commit-Position: refs/heads/master@{#29561} --- src/arm/assembler-arm.h | 2 + src/arm/debug-arm.cc | 88 ++------- src/arm/full-codegen-arm.cc | 11 +- src/arm64/assembler-arm64.h | 2 + src/arm64/debug-arm64.cc | 89 +-------- src/arm64/full-codegen-arm64.cc | 44 ++--- src/assembler.cc | 94 ++++++++-- src/assembler.h | 10 + src/builtins.cc | 21 --- src/builtins.h | 8 - src/code-stubs.h | 9 - src/debug.cc | 198 +++----------------- src/debug.h | 46 ++--- src/disassembler.cc | 10 +- src/full-codegen.cc | 29 ++- src/full-codegen.h | 4 + src/ia32/assembler-ia32.h | 2 + src/ia32/debug-ia32.cc | 82 +------- src/ia32/full-codegen-ia32.cc | 11 +- src/mips/assembler-mips.h | 2 + src/mips/debug-mips.cc | 88 ++------- src/mips/full-codegen-mips.cc | 37 ++-- src/mips64/assembler-mips64.h | 2 + src/mips64/debug-mips64.cc | 63 +------ src/mips64/full-codegen-mips64.cc | 37 ++-- src/x64/assembler-x64.h | 2 + src/x64/debug-x64.cc | 73 +------- src/x64/full-codegen-x64.cc | 38 ++-- test/cctest/test-debug.cc | 55 ------ test/mjsunit/debug-stepin-construct-call.js | 42 +++++ 30 files changed, 347 insertions(+), 852 deletions(-) create mode 100644 test/mjsunit/debug-stepin-construct-call.js diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h index 36f3fda6f..73c109972 100644 --- a/src/arm/assembler-arm.h +++ b/src/arm/assembler-arm.h @@ -1359,6 +1359,8 @@ class Assembler : public AssemblerBase { // Mark address of a debug break slot. void RecordDebugBreakSlot(); + void RecordDebugBreakSlotForCall(int argc); + void RecordDebugBreakSlotForConstructCall(); // Record the AST id of the CallIC being compiled, so that it can be placed // in the relocation information. diff --git a/src/arm/debug-arm.cc b/src/arm/debug-arm.cc index 7d9313200..57681b147 100644 --- a/src/arm/debug-arm.cc +++ b/src/arm/debug-arm.cc @@ -54,8 +54,7 @@ void BreakLocation::SetDebugBreakAtSlot() { static void Generate_DebugBreakCallHelper(MacroAssembler* masm, - RegList object_regs, - RegList non_object_regs) { + RegList object_regs) { { FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); @@ -71,21 +70,8 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, // make sure that these are correctly updated during GC. Non object values // are stored as a smi causing it to be untouched by GC. DCHECK((object_regs & ~kJSCallerSaved) == 0); - DCHECK((non_object_regs & ~kJSCallerSaved) == 0); - DCHECK((object_regs & non_object_regs) == 0); - if ((object_regs | non_object_regs) != 0) { - for (int i = 0; i < kNumJSCallerSaved; i++) { - int r = JSCallerSavedCode(i); - Register reg = { r }; - if ((non_object_regs & (1 << r)) != 0) { - if (FLAG_debug_code) { - __ tst(reg, Operand(0xc0000000)); - __ Assert(eq, kUnableToEncodeValueAsSmi); - } - __ SmiTag(reg); - } - } - __ stm(db_w, sp, object_regs | non_object_regs); + if (object_regs != 0) { + __ stm(db_w, sp, object_regs); } #ifdef DEBUG @@ -98,18 +84,15 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, __ CallStub(&ceb); // Restore the register values from the expression stack. - if ((object_regs | non_object_regs) != 0) { - __ ldm(ia_w, sp, object_regs | non_object_regs); - for (int i = 0; i < kNumJSCallerSaved; i++) { - int r = JSCallerSavedCode(i); - Register reg = { r }; - if ((non_object_regs & (1 << r)) != 0) { - __ SmiUntag(reg); - } - if (FLAG_debug_code && - (((object_regs |non_object_regs) & (1 << r)) == 0)) { - __ mov(reg, Operand(kDebugZapValue)); - } + if (object_regs != 0) { + __ ldm(ia_w, sp, object_regs); + } + + for (int i = 0; i < kNumJSCallerSaved; i++) { + int r = JSCallerSavedCode(i); + Register reg = {r}; + if (FLAG_debug_code && ((object_regs & (1 << r)) == 0)) { + __ mov(reg, Operand(kDebugZapValue)); } } @@ -130,53 +113,11 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, } -void DebugCodegen::GenerateCallICStubDebugBreak(MacroAssembler* masm) { - // Register state for CallICStub - // ----------- S t a t e ------------- - // -- r1 : function - // -- r3 : slot in feedback array (smi) - // ----------------------------------- - Generate_DebugBreakCallHelper(masm, r1.bit() | r3.bit(), 0); -} - - void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) { // In places other than IC call sites it is expected that r0 is TOS which // is an object - this is not generally the case so this should be used with // care. - Generate_DebugBreakCallHelper(masm, r0.bit(), 0); -} - - -void DebugCodegen::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) { - // Register state for CallFunctionStub (from code-stubs-arm.cc). - // ----------- S t a t e ------------- - // -- r1 : function - // ----------------------------------- - Generate_DebugBreakCallHelper(masm, r1.bit(), 0); -} - - -void DebugCodegen::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) { - // Calling convention for CallConstructStub (from code-stubs-arm.cc) - // ----------- S t a t e ------------- - // -- r0 : number of arguments (not smi) - // -- r1 : constructor function - // ----------------------------------- - Generate_DebugBreakCallHelper(masm, r1.bit(), r0.bit()); -} - - -void DebugCodegen::GenerateCallConstructStubRecordDebugBreak( - MacroAssembler* masm) { - // Calling convention for CallConstructStub (from code-stubs-arm.cc) - // ----------- S t a t e ------------- - // -- r0 : number of arguments (not smi) - // -- r1 : constructor function - // -- r2 : feedback array - // -- r3 : feedback slot (smi) - // ----------------------------------- - Generate_DebugBreakCallHelper(masm, r1.bit() | r2.bit() | r3.bit(), r0.bit()); + Generate_DebugBreakCallHelper(masm, r0.bit()); } @@ -186,7 +127,6 @@ void DebugCodegen::GenerateSlot(MacroAssembler* masm) { Assembler::BlockConstPoolScope block_const_pool(masm); Label check_codesize; __ bind(&check_codesize); - __ RecordDebugBreakSlot(); for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) { __ nop(MacroAssembler::DEBUG_BREAK_NOP); } @@ -198,7 +138,7 @@ void DebugCodegen::GenerateSlot(MacroAssembler* masm) { void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) { // In the places where a debug break slot is inserted no registers can contain // object pointers. - Generate_DebugBreakCallHelper(masm, 0, 0); + Generate_DebugBreakCallHelper(masm, 0); } diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index e4b7cf34e..3dea3bc18 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -2269,6 +2269,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) { CallIC(ic, TypeFeedbackId::None()); __ mov(r1, r0); __ str(r1, MemOperand(sp, 2 * kPointerSize)); + SetCallPosition(expr, 1); CallFunctionStub stub(isolate(), 1, CALL_AS_METHOD); __ CallStub(&stub); @@ -3103,7 +3104,7 @@ void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) { VisitForStackValue(args->at(i)); } - SetExpressionPosition(expr); + SetCallPosition(expr, arg_count); Handle ic = CodeFactory::CallIC(isolate(), arg_count, call_type).code(); __ mov(r3, Operand(SmiFromSlot(expr->CallFeedbackICSlot()))); __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); @@ -3238,7 +3239,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { PrepareForBailoutForId(expr->EvalId(), NO_REGISTERS); // Record source position for debugger. - SetExpressionPosition(expr); + SetCallPosition(expr, arg_count); CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS); __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); __ CallStub(&stub); @@ -3310,7 +3311,7 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) { // Call the construct call builtin that handles allocation and // constructor invocation. - SetExpressionPosition(expr); + SetConstructCallPosition(expr); // Load function and argument count into r1 and r0. __ mov(r0, Operand(arg_count)); @@ -3353,7 +3354,7 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) { // Call the construct call builtin that handles allocation and // constructor invocation. - SetExpressionPosition(expr); + SetConstructCallPosition(expr); // Load function and argument count into r1 and r0. __ mov(r0, Operand(arg_count)); @@ -4732,7 +4733,7 @@ void FullCodeGenerator::EmitCallJSRuntimeFunction(CallRuntime* expr) { ZoneList* args = expr->arguments(); int arg_count = args->length(); - SetExpressionPosition(expr); + SetCallPosition(expr, arg_count); CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS); __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); __ CallStub(&stub); diff --git a/src/arm64/assembler-arm64.h b/src/arm64/assembler-arm64.h index 5fab081d4..b13d2199a 100644 --- a/src/arm64/assembler-arm64.h +++ b/src/arm64/assembler-arm64.h @@ -1027,6 +1027,8 @@ class Assembler : public AssemblerBase { // Mark address of a debug break slot. void RecordDebugBreakSlot(); + void RecordDebugBreakSlotForCall(int argc); + void RecordDebugBreakSlotForConstructCall(); // Record the emission of a constant pool. // diff --git a/src/arm64/debug-arm64.cc b/src/arm64/debug-arm64.cc index 2eec4466e..7b24526dc 100644 --- a/src/arm64/debug-arm64.cc +++ b/src/arm64/debug-arm64.cc @@ -94,9 +94,8 @@ void BreakLocation::SetDebugBreakAtSlot() { static void Generate_DebugBreakCallHelper(MacroAssembler* masm, - RegList object_regs, - RegList non_object_regs, - Register scratch) { + RegList object_regs) { + Register scratch = x10; { FrameScope scope(masm, StackFrame::INTERNAL); @@ -120,30 +119,10 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, // // TODO(jbramley): Why can't this handle callee-saved registers? DCHECK((~kCallerSaved.list() & object_regs) == 0); - DCHECK((~kCallerSaved.list() & non_object_regs) == 0); - DCHECK((object_regs & non_object_regs) == 0); DCHECK((scratch.Bit() & object_regs) == 0); - DCHECK((scratch.Bit() & non_object_regs) == 0); - DCHECK((masm->TmpList()->list() & (object_regs | non_object_regs)) == 0); + DCHECK((masm->TmpList()->list() & object_regs) == 0); STATIC_ASSERT(kSmiValueSize == 32); - CPURegList non_object_list = - CPURegList(CPURegister::kRegister, kXRegSizeInBits, non_object_regs); - while (!non_object_list.IsEmpty()) { - // Store each non-object register as two SMIs. - Register reg = Register(non_object_list.PopLowestIndex()); - __ Lsr(scratch, reg, 32); - __ SmiTagAndPush(scratch, reg); - - // Stack: - // jssp[12]: reg[63:32] - // jssp[8]: 0x00000000 (SMI tag & padding) - // jssp[4]: reg[31:0] - // jssp[0]: 0x00000000 (SMI tag & padding) - STATIC_ASSERT(kSmiTag == 0); - STATIC_ASSERT(static_cast(kSmiShift) == kWRegSizeInBits); - } - if (object_regs != 0) { __ PushXRegList(object_regs); } @@ -162,20 +141,6 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, __ PopXRegList(object_regs); } - non_object_list = - CPURegList(CPURegister::kRegister, kXRegSizeInBits, non_object_regs); - while (!non_object_list.IsEmpty()) { - // Load each non-object register from two SMIs. - // Stack: - // jssp[12]: reg[63:32] - // jssp[8]: 0x00000000 (SMI tag & padding) - // jssp[4]: reg[31:0] - // jssp[0]: 0x00000000 (SMI tag & padding) - Register reg = Register(non_object_list.PopHighestIndex()); - __ Pop(scratch, reg); - __ Bfxil(reg, scratch, 32, 32); - } - // Don't bother removing padding bytes pushed on the stack // as the frame is going to be restored right away. @@ -193,54 +158,11 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, } -void DebugCodegen::GenerateCallICStubDebugBreak(MacroAssembler* masm) { - // Register state for CallICStub - // ----------- S t a t e ------------- - // -- x1 : function - // -- x3 : slot in feedback array - // ----------------------------------- - Generate_DebugBreakCallHelper(masm, x1.Bit() | x3.Bit(), 0, x10); -} - - void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) { // In places other than IC call sites it is expected that r0 is TOS which // is an object - this is not generally the case so this should be used with // care. - Generate_DebugBreakCallHelper(masm, x0.Bit(), 0, x10); -} - - -void DebugCodegen::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) { - // Register state for CallFunctionStub (from code-stubs-arm64.cc). - // ----------- S t a t e ------------- - // -- x1 : function - // ----------------------------------- - Generate_DebugBreakCallHelper(masm, x1.Bit(), 0, x10); -} - - -void DebugCodegen::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) { - // Calling convention for CallConstructStub (from code-stubs-arm64.cc). - // ----------- S t a t e ------------- - // -- x0 : number of arguments (not smi) - // -- x1 : constructor function - // ----------------------------------- - Generate_DebugBreakCallHelper(masm, x1.Bit(), x0.Bit(), x10); -} - - -void DebugCodegen::GenerateCallConstructStubRecordDebugBreak( - MacroAssembler* masm) { - // Calling convention for CallConstructStub (from code-stubs-arm64.cc). - // ----------- S t a t e ------------- - // -- x0 : number of arguments (not smi) - // -- x1 : constructor function - // -- x2 : feedback array - // -- x3 : feedback slot (smi) - // ----------------------------------- - Generate_DebugBreakCallHelper( - masm, x1.Bit() | x2.Bit() | x3.Bit(), x0.Bit(), x10); + Generate_DebugBreakCallHelper(masm, x0.Bit()); } @@ -249,7 +171,6 @@ void DebugCodegen::GenerateSlot(MacroAssembler* masm) { // the constant pool in the debug break slot code. InstructionAccurateScope scope(masm, Assembler::kDebugBreakSlotInstructions); - __ RecordDebugBreakSlot(); for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) { __ nop(Assembler::DEBUG_BREAK_NOP); } @@ -259,7 +180,7 @@ void DebugCodegen::GenerateSlot(MacroAssembler* masm) { void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) { // In the places where a debug break slot is inserted no registers can contain // object pointers. - Generate_DebugBreakCallHelper(masm, 0, 0, x10); + Generate_DebugBreakCallHelper(masm, 0); } diff --git a/src/arm64/full-codegen-arm64.cc b/src/arm64/full-codegen-arm64.cc index 324bfb816..9896771b5 100644 --- a/src/arm64/full-codegen-arm64.cc +++ b/src/arm64/full-codegen-arm64.cc @@ -2788,10 +2788,11 @@ void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) { // Load the arguments. ZoneList* args = expr->arguments(); int arg_count = args->length(); - for (int i = 0; i < arg_count; i++) { - VisitForStackValue(args->at(i)); - } - SetExpressionPosition(expr); + for (int i = 0; i < arg_count; i++) { + VisitForStackValue(args->at(i)); + } + + SetCallPosition(expr, arg_count); Handle ic = CodeFactory::CallIC(isolate(), arg_count, call_type).code(); __ Mov(x3, SmiFromSlot(expr->CallFeedbackICSlot())); @@ -2907,26 +2908,26 @@ void FullCodeGenerator::VisitCall(Call* expr) { ZoneList* args = expr->arguments(); int arg_count = args->length(); - PushCalleeAndWithBaseObject(expr); + PushCalleeAndWithBaseObject(expr); - // Push the arguments. - for (int i = 0; i < arg_count; i++) { - VisitForStackValue(args->at(i)); - } + // Push the arguments. + for (int i = 0; i < arg_count; i++) { + VisitForStackValue(args->at(i)); + } - // Push a copy of the function (found below the arguments) and - // resolve eval. - __ Peek(x10, (arg_count + 1) * kPointerSize); - __ Push(x10); - EmitResolvePossiblyDirectEval(arg_count); + // Push a copy of the function (found below the arguments) and + // resolve eval. + __ Peek(x10, (arg_count + 1) * kPointerSize); + __ Push(x10); + EmitResolvePossiblyDirectEval(arg_count); - // Touch up the stack with the resolved function. - __ Poke(x0, (arg_count + 1) * kPointerSize); + // Touch up the stack with the resolved function. + __ Poke(x0, (arg_count + 1) * kPointerSize); - PrepareForBailoutForId(expr->EvalId(), NO_REGISTERS); + PrepareForBailoutForId(expr->EvalId(), NO_REGISTERS); // Record source position for debugger. - SetExpressionPosition(expr); + SetCallPosition(expr, arg_count); // Call the evaluated function. CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS); @@ -3001,7 +3002,7 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) { // Call the construct call builtin that handles allocation and // constructor invocation. - SetExpressionPosition(expr); + SetConstructCallPosition(expr); // Load function and argument count into x1 and x0. __ Mov(x0, arg_count); @@ -3044,7 +3045,7 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) { // Call the construct call builtin that handles allocation and // constructor invocation. - SetExpressionPosition(expr); + SetConstructCallPosition(expr); // Load function and argument count into x1 and x0. __ Mov(x0, arg_count); @@ -4424,7 +4425,7 @@ void FullCodeGenerator::EmitCallJSRuntimeFunction(CallRuntime* expr) { ZoneList* args = expr->arguments(); int arg_count = args->length(); - SetExpressionPosition(expr); + SetCallPosition(expr, arg_count); CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS); __ Peek(x1, (arg_count + 1) * kPointerSize); __ CallStub(&stub); @@ -5186,6 +5187,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) { CallIC(ic, TypeFeedbackId::None()); __ Mov(x1, x0); __ Poke(x1, 2 * kPointerSize); + SetCallPosition(expr, 1); CallFunctionStub stub(isolate(), 1, CALL_AS_METHOD); __ CallStub(&stub); diff --git a/src/assembler.cc b/src/assembler.cc index e6aaa914b..d03593f36 100644 --- a/src/assembler.cc +++ b/src/assembler.cc @@ -380,23 +380,27 @@ void RelocInfoWriter::WriteExtraTaggedPC(uint32_t pc_delta, int extra_tag) { } -void RelocInfoWriter::WriteExtraTaggedIntData(int data_delta, int top_tag) { - WriteExtraTag(kDataJumpExtraTag, top_tag); +void RelocInfoWriter::WriteInt(int number) { for (int i = 0; i < kIntSize; i++) { - *--pos_ = static_cast(data_delta); + *--pos_ = static_cast(number); // Signed right shift is arithmetic shift. Tested in test-utils.cc. - data_delta = data_delta >> kBitsPerByte; + number = number >> kBitsPerByte; } } +void RelocInfoWriter::WriteDebugBreakSlotData(int data) { WriteInt(data); } + + +void RelocInfoWriter::WriteExtraTaggedIntData(int data_delta, int top_tag) { + WriteExtraTag(kDataJumpExtraTag, top_tag); + WriteInt(data_delta); +} + + void RelocInfoWriter::WriteExtraTaggedPoolData(int data, int pool_type) { WriteExtraTag(kPoolExtraTag, pool_type); - for (int i = 0; i < kIntSize; i++) { - *--pos_ = static_cast(data); - // Signed right shift is arithmetic shift. Tested in test-utils.cc. - data = data >> kBitsPerByte; - } + WriteInt(data); } @@ -498,10 +502,10 @@ void RelocInfoWriter::Write(const RelocInfo* rinfo) { WriteExtraTaggedData(rinfo->data(), kCommentTag); DCHECK(begin_pos - pos_ >= RelocInfo::kMinRelocCommentSize); } else if (RelocInfo::IsConstPool(rmode) || RelocInfo::IsVeneerPool(rmode)) { - WriteExtraTaggedPC(pc_delta, kPCJumpExtraTag); - WriteExtraTaggedPoolData(static_cast(rinfo->data()), - RelocInfo::IsConstPool(rmode) ? kConstPoolTag - : kVeneerPoolTag); + WriteExtraTaggedPC(pc_delta, kPCJumpExtraTag); + WriteExtraTaggedPoolData( + static_cast(rinfo->data()), + RelocInfo::IsConstPool(rmode) ? kConstPoolTag : kVeneerPoolTag); } else { DCHECK(rmode > RelocInfo::LAST_COMPACT_ENUM); DCHECK(rmode <= RelocInfo::LAST_STANDARD_NONCOMPACT_ENUM); @@ -513,6 +517,9 @@ void RelocInfoWriter::Write(const RelocInfo* rinfo) { // None of these modes need a data component. DCHECK(0 <= saved_mode && saved_mode < kPoolExtraTag); WriteExtraTaggedPC(pc_delta, saved_mode); + if (RelocInfo::IsDebugBreakSlot(rmode)) { + WriteDebugBreakSlotData(static_cast(rinfo->data())); + } } last_pc_ = rinfo->pc(); last_mode_ = rmode; @@ -557,7 +564,7 @@ void RelocIterator::AdvanceReadId() { } -void RelocIterator::AdvanceReadPoolData() { +void RelocIterator::AdvanceReadInt() { int x = 0; for (int i = 0; i < kIntSize; i++) { x |= static_cast(*--pos_) << i * kBitsPerByte; @@ -566,6 +573,12 @@ void RelocIterator::AdvanceReadPoolData() { } +void RelocIterator::AdvanceReadPoolData() { AdvanceReadInt(); } + + +void RelocIterator::AdvanceReadDebugBreakSlotData() { AdvanceReadInt(); } + + void RelocIterator::AdvanceReadPosition() { int x = 0; for (int i = 0; i < kIntSize; i++) { @@ -718,8 +731,17 @@ void RelocIterator::next() { Advance(kIntSize); } else { AdvanceReadPC(); - int rmode = extra_tag + RelocInfo::LAST_COMPACT_ENUM + 1; - if (SetMode(static_cast(rmode))) return; + RelocInfo::Mode rmode = static_cast( + extra_tag + RelocInfo::LAST_COMPACT_ENUM + 1); + if (RelocInfo::IsDebugBreakSlot(rmode)) { + if (SetMode(rmode)) { + AdvanceReadDebugBreakSlotData(); + return; + } + Advance(kIntSize); + } else if (SetMode(rmode)) { + return; + } } } } @@ -883,6 +905,14 @@ void RelocInfo::Print(Isolate* isolate, std::ostream& os) { // NOLINT } } else if (IsConstPool(rmode_)) { os << " (size " << static_cast(data_) << ")"; + } else if (IsDebugBreakSlot(rmode_)) { + if (DebugBreakIsCall(data_)) { + os << " (call with " << DebugBreakCallArgumentsCount(data_) << " args)"; + } else if (DebugBreakIsConstructCall(data_)) { + os << " (construct call)"; + } else { + os << " (slot)"; + } } os << "\n"; @@ -946,6 +976,20 @@ void RelocInfo::Verify(Isolate* isolate) { #endif // VERIFY_HEAP +bool RelocInfo::DebugBreakIsConstructCall(intptr_t data) { + return data == static_cast(kDebugBreakConstructCallSentinel); +} + + +bool RelocInfo::DebugBreakIsCall(intptr_t data) { return data >= 0; } + + +int RelocInfo::DebugBreakCallArgumentsCount(intptr_t data) { + DCHECK(DebugBreakIsCall(data)); + return static_cast(data); +} + + // ----------------------------------------------------------------------------- // Implementation of ExternalReference @@ -1869,7 +1913,23 @@ void Assembler::RecordJSReturn() { void Assembler::RecordDebugBreakSlot() { EnsureSpace ensure_space(this); - RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT); + intptr_t data = static_cast(RelocInfo::kDebugBreakNonCallSentinel); + RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT, data); +} + + +void Assembler::RecordDebugBreakSlotForCall(int argc) { + EnsureSpace ensure_space(this); + intptr_t data = static_cast(argc); + RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT, data); +} + + +void Assembler::RecordDebugBreakSlotForConstructCall() { + EnsureSpace ensure_space(this); + intptr_t data = + static_cast(RelocInfo::kDebugBreakConstructCallSentinel); + RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT, data); } diff --git a/src/assembler.h b/src/assembler.h index fb59ceb7b..9433692ed 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -506,6 +506,10 @@ class RelocInfo { // constant pool, otherwise the pointer is embedded in the instruction stream. bool IsInConstantPool(); + static bool DebugBreakIsConstructCall(intptr_t data); + static bool DebugBreakIsCall(intptr_t data); + static int DebugBreakCallArgumentsCount(intptr_t data); + // Read/modify the code target in the branch/call instruction // this relocation applies to; // can only be called if IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) @@ -623,6 +627,8 @@ class RelocInfo { static const int kDataMask = (1 << CODE_TARGET_WITH_ID) | kPositionMask | (1 << COMMENT); static const int kApplyMask; // Modes affected by apply. Depends on arch. + static const int kDebugBreakNonCallSentinel = -2; + static const int kDebugBreakConstructCallSentinel = -1; private: // On ARM, note that pc_ is the address of the constant pool entry @@ -690,6 +696,8 @@ class RelocInfoWriter BASE_EMBEDDED { inline uint32_t WriteVariableLengthPCJump(uint32_t pc_delta); inline void WriteTaggedPC(uint32_t pc_delta, int tag); inline void WriteExtraTaggedPC(uint32_t pc_delta, int extra_tag); + inline void WriteInt(int number); + inline void WriteDebugBreakSlotData(int data); inline void WriteExtraTaggedIntData(int data_delta, int top_tag); inline void WriteExtraTaggedPoolData(int data, int pool_type); inline void WriteExtraTaggedData(intptr_t data_delta, int top_tag); @@ -750,7 +758,9 @@ class RelocIterator: public Malloced { void ReadTaggedPC(); void AdvanceReadPC(); void AdvanceReadId(); + void AdvanceReadInt(); void AdvanceReadPoolData(); + void AdvanceReadDebugBreakSlotData(); void AdvanceReadPosition(); void AdvanceReadData(); void AdvanceReadVariableLengthPCJump(); diff --git a/src/builtins.cc b/src/builtins.cc index 869ad2cc0..69c287165 100644 --- a/src/builtins.cc +++ b/src/builtins.cc @@ -1369,32 +1369,11 @@ static void Generate_KeyedStoreIC_PreMonomorphic_Strict(MacroAssembler* masm) { } -static void Generate_CallICStub_DebugBreak(MacroAssembler* masm) { - DebugCodegen::GenerateCallICStubDebugBreak(masm); -} - - static void Generate_Return_DebugBreak(MacroAssembler* masm) { DebugCodegen::GenerateReturnDebugBreak(masm); } -static void Generate_CallFunctionStub_DebugBreak(MacroAssembler* masm) { - DebugCodegen::GenerateCallFunctionStubDebugBreak(masm); -} - - -static void Generate_CallConstructStub_DebugBreak(MacroAssembler* masm) { - DebugCodegen::GenerateCallConstructStubDebugBreak(masm); -} - - -static void Generate_CallConstructStub_Recording_DebugBreak( - MacroAssembler* masm) { - DebugCodegen::GenerateCallConstructStubRecordDebugBreak(masm); -} - - static void Generate_Slot_DebugBreak(MacroAssembler* masm) { DebugCodegen::GenerateSlotDebugBreak(masm); } diff --git a/src/builtins.h b/src/builtins.h index e1e202b3f..d831b0bfb 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -143,14 +143,6 @@ enum BuiltinExtraArguments { #define BUILTIN_LIST_DEBUG_A(V) \ V(Return_DebugBreak, BUILTIN, DEBUG_STUB, \ DEBUG_BREAK) \ - V(CallFunctionStub_DebugBreak, BUILTIN, DEBUG_STUB, \ - DEBUG_BREAK) \ - V(CallConstructStub_DebugBreak, BUILTIN, DEBUG_STUB, \ - DEBUG_BREAK) \ - V(CallConstructStub_Recording_DebugBreak, BUILTIN, DEBUG_STUB, \ - DEBUG_BREAK) \ - V(CallICStub_DebugBreak, CALL_IC, DEBUG_STUB, \ - DEBUG_BREAK) \ V(Slot_DebugBreak, BUILTIN, DEBUG_STUB, \ DEBUG_BREAK) \ V(PlainReturn_LiveEdit, BUILTIN, DEBUG_STUB, \ diff --git a/src/code-stubs.h b/src/code-stubs.h index a798d5e35..30624ea4a 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -1013,11 +1013,6 @@ class CallICStub: public PlatformCodeStub { minor_key_ = state.GetExtraICState(); } - static int ExtractArgcFromMinorKey(int minor_key) { - CallICState state(static_cast(minor_key)); - return state.arg_count(); - } - Code::Kind GetCodeKind() const override { return Code::CALL_IC; } InlineCacheState GetICState() const override { return DEFAULT; } @@ -1913,10 +1908,6 @@ class CallFunctionStub: public PlatformCodeStub { minor_key_ = ArgcBits::encode(argc) | FlagBits::encode(flags); } - static int ExtractArgcFromMinorKey(int minor_key) { - return ArgcBits::decode(minor_key); - } - private: int argc() const { return ArgcBits::decode(minor_key_); } int flags() const { return FlagBits::decode(minor_key_); } diff --git a/src/debug.cc b/src/debug.cc index b7bf3e39a..c3c0dcb66 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -117,7 +117,6 @@ void BreakLocation::Iterator::Next() { continue; } - // Check for break at return. if (RelocInfo::IsJSReturn(rmode())) { // Set the positions to the end of the function. if (debug_info_->shared()->HasSourceCode()) { @@ -127,43 +126,21 @@ void BreakLocation::Iterator::Next() { position_ = 0; } statement_position_ = position_; - break_index_++; break; } - if (RelocInfo::IsCodeTarget(rmode())) { - // Check for breakable code target. Look in the original code as setting - // break points can cause the code targets in the running (debugged) code - // to be of a different kind than in the original code. - Address target = original_rinfo()->target_address(); - Code* code = Code::GetCodeFromTargetAddress(target); - - if (RelocInfo::IsConstructCall(rmode()) || code->is_call_stub()) { - break_index_++; - break; - } - - if (code->kind() == Code::STUB && - CodeStub::GetMajorKey(code) == CodeStub::CallFunction) { - break_index_++; - break; - } - } - - // Skip below if we only want locations for calls and returns. - if (type_ == CALLS_AND_RETURNS) continue; - - if (RelocInfo::IsDebuggerStatement(rmode())) { - break_index_++; + if (RelocInfo::IsDebugBreakSlot(rmode()) && + (type_ == ALL_BREAK_LOCATIONS || + RelocInfo::DebugBreakIsCall(rinfo()->data()))) { break; } - if (RelocInfo::IsDebugBreakSlot(rmode()) && type_ != CALLS_AND_RETURNS) { - // There is always a possible break point at a debug break slot. - break_index_++; + if (RelocInfo::IsDebuggerStatement(rmode()) && + type_ == ALL_BREAK_LOCATIONS) { break; } } + break_index_++; } @@ -311,9 +288,6 @@ void BreakLocation::SetDebugBreak() { } else if (IsDebugBreakSlot()) { // Patch the code in the break slot. SetDebugBreakAtSlot(); - } else { - // Patch the IC call. - SetDebugBreakAtIC(); } DCHECK(IsDebugBreak()); } @@ -329,13 +303,6 @@ void BreakLocation::ClearDebugBreak() { } else if (IsDebugBreakSlot()) { // Restore the code in the break slot. RestoreFromOriginal(Assembler::kDebugBreakSlotLength); - } else { - // Restore the IC call. - rinfo().set_target_address(original_rinfo().target_address()); - // Some ICs store data in the feedback vector. Clear this to ensure we - // won't miss future stepping requirements. - SharedFunctionInfo* shared = debug_info_->shared(); - shared->feedback_vector()->ClearICSlots(shared); } DCHECK(!IsDebugBreak()); } @@ -348,13 +315,7 @@ void BreakLocation::RestoreFromOriginal(int length_in_bytes) { bool BreakLocation::IsStepInLocation() const { - if (IsConstructCall()) return true; - if (RelocInfo::IsCodeTarget(rmode())) { - HandleScope scope(debug_info_->GetIsolate()); - Handle target_code = CodeTarget(); - return target_code->is_call_stub(); - } - return false; + return IsConstructCall() || IsCall(); } @@ -363,52 +324,8 @@ bool BreakLocation::IsDebugBreak() const { return rinfo().IsPatchedReturnSequence(); } else if (IsDebugBreakSlot()) { return rinfo().IsPatchedDebugBreakSlotSequence(); - } else { - return Debug::IsDebugBreak(rinfo().target_address()); - } -} - - -// Find the builtin to use for invoking the debug break -static Handle DebugBreakForIC(Handle code, RelocInfo::Mode mode) { - Isolate* isolate = code->GetIsolate(); - - // Find the builtin debug break function matching the calling convention - // used by the call site. - if (code->is_inline_cache_stub()) { - DCHECK(code->kind() == Code::CALL_IC); - return isolate->builtins()->CallICStub_DebugBreak(); - } - if (RelocInfo::IsConstructCall(mode)) { - if (code->has_function_cache()) { - return isolate->builtins()->CallConstructStub_Recording_DebugBreak(); - } else { - return isolate->builtins()->CallConstructStub_DebugBreak(); - } - } - if (code->kind() == Code::STUB) { - DCHECK(CodeStub::GetMajorKey(*code) == CodeStub::CallFunction); - return isolate->builtins()->CallFunctionStub_DebugBreak(); - } - - UNREACHABLE(); - return Handle::null(); -} - - -void BreakLocation::SetDebugBreakAtIC() { - // Patch the original code with the current address as the current address - // might have changed by the inline caching since the code was copied. - original_rinfo().set_target_address(rinfo().target_address()); - - if (RelocInfo::IsCodeTarget(rmode_)) { - Handle target_code = CodeTarget(); - - // Patch the code to invoke the builtin debug break function matching the - // calling convention used by the call site. - Handle debug_break_code = DebugBreakForIC(target_code, rmode_); - rinfo().set_target_address(debug_break_code->entry()); } + return false; } @@ -417,20 +334,6 @@ Handle BreakLocation::BreakPointObjects() const { } -Handle BreakLocation::CodeTarget() const { - DCHECK(IsCodeTarget()); - Address target = rinfo().target_address(); - return Handle(Code::GetCodeFromTargetAddress(target)); -} - - -Handle BreakLocation::OriginalCodeTarget() const { - DCHECK(IsCodeTarget()); - Address target = original_rinfo().target_address(); - return Handle(Code::GetCodeFromTargetAddress(target)); -} - - bool BreakLocation::Iterator::RinfoDone() const { DCHECK(reloc_iterator_.done() == reloc_iterator_original_.done()); return reloc_iterator_.done(); @@ -442,7 +345,7 @@ void BreakLocation::Iterator::RinfoNext() { reloc_iterator_original_.next(); #ifdef DEBUG DCHECK(reloc_iterator_.done() == reloc_iterator_original_.done()); - DCHECK(reloc_iterator_.done() || rmode() == original_rmode()); + DCHECK(reloc_iterator_.done() || rmode() == original_rinfo()->rmode()); #endif } @@ -941,7 +844,7 @@ bool Debug::SetBreakPoint(Handle function, // Find the break point and change it. BreakLocation location = BreakLocation::FromPosition( - debug_info, SOURCE_BREAK_LOCATIONS, *source_position, STATEMENT_ALIGNED); + debug_info, ALL_BREAK_LOCATIONS, *source_position, STATEMENT_ALIGNED); *source_position = location.statement_position(); location.SetBreakPoint(break_point_object); @@ -985,7 +888,7 @@ bool Debug::SetBreakPointForScript(Handle