// 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.
static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
- RegList object_regs,
- RegList non_object_regs) {
+ RegList object_regs) {
{
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
// 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
__ 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));
}
}
}
-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());
}
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);
}
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);
}
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);
VisitForStackValue(args->at(i));
}
- SetExpressionPosition(expr);
+ SetCallPosition(expr, arg_count);
Handle<Code> ic = CodeFactory::CallIC(isolate(), arg_count, call_type).code();
__ mov(r3, Operand(SmiFromSlot(expr->CallFeedbackICSlot())));
__ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
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);
// 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));
// 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));
ZoneList<Expression*>* 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);
// Mark address of a debug break slot.
void RecordDebugBreakSlot();
+ void RecordDebugBreakSlotForCall(int argc);
+ void RecordDebugBreakSlotForConstructCall();
// Record the emission of a constant pool.
//
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);
//
// 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<unsigned>(kSmiShift) == kWRegSizeInBits);
- }
-
if (object_regs != 0) {
__ PushXRegList(object_regs);
}
__ 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.
}
-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());
}
// 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);
}
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);
}
// Load the arguments.
ZoneList<Expression*>* 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<Code> ic = CodeFactory::CallIC(isolate(), arg_count, call_type).code();
__ Mov(x3, SmiFromSlot(expr->CallFeedbackICSlot()));
ZoneList<Expression*>* 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);
// 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);
// 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);
ZoneList<Expression*>* 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);
CallIC(ic, TypeFeedbackId::None());
__ Mov(x1, x0);
__ Poke(x1, 2 * kPointerSize);
+ SetCallPosition(expr, 1);
CallFunctionStub stub(isolate(), 1, CALL_AS_METHOD);
__ CallStub(&stub);
}
-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<byte>(data_delta);
+ *--pos_ = static_cast<byte>(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<byte>(data);
- // Signed right shift is arithmetic shift. Tested in test-utils.cc.
- data = data >> kBitsPerByte;
- }
+ WriteInt(data);
}
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<int>(rinfo->data()),
- RelocInfo::IsConstPool(rmode) ? kConstPoolTag
- : kVeneerPoolTag);
+ WriteExtraTaggedPC(pc_delta, kPCJumpExtraTag);
+ WriteExtraTaggedPoolData(
+ static_cast<int>(rinfo->data()),
+ RelocInfo::IsConstPool(rmode) ? kConstPoolTag : kVeneerPoolTag);
} else {
DCHECK(rmode > RelocInfo::LAST_COMPACT_ENUM);
DCHECK(rmode <= RelocInfo::LAST_STANDARD_NONCOMPACT_ENUM);
// 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<int>(rinfo->data()));
+ }
}
last_pc_ = rinfo->pc();
last_mode_ = rmode;
}
-void RelocIterator::AdvanceReadPoolData() {
+void RelocIterator::AdvanceReadInt() {
int x = 0;
for (int i = 0; i < kIntSize; i++) {
x |= static_cast<int>(*--pos_) << i * kBitsPerByte;
}
+void RelocIterator::AdvanceReadPoolData() { AdvanceReadInt(); }
+
+
+void RelocIterator::AdvanceReadDebugBreakSlotData() { AdvanceReadInt(); }
+
+
void RelocIterator::AdvanceReadPosition() {
int x = 0;
for (int i = 0; i < kIntSize; i++) {
Advance(kIntSize);
} else {
AdvanceReadPC();
- int rmode = extra_tag + RelocInfo::LAST_COMPACT_ENUM + 1;
- if (SetMode(static_cast<RelocInfo::Mode>(rmode))) return;
+ RelocInfo::Mode rmode = static_cast<RelocInfo::Mode>(
+ extra_tag + RelocInfo::LAST_COMPACT_ENUM + 1);
+ if (RelocInfo::IsDebugBreakSlot(rmode)) {
+ if (SetMode(rmode)) {
+ AdvanceReadDebugBreakSlotData();
+ return;
+ }
+ Advance(kIntSize);
+ } else if (SetMode(rmode)) {
+ return;
+ }
}
}
}
}
} else if (IsConstPool(rmode_)) {
os << " (size " << static_cast<int>(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";
#endif // VERIFY_HEAP
+bool RelocInfo::DebugBreakIsConstructCall(intptr_t data) {
+ return data == static_cast<intptr_t>(kDebugBreakConstructCallSentinel);
+}
+
+
+bool RelocInfo::DebugBreakIsCall(intptr_t data) { return data >= 0; }
+
+
+int RelocInfo::DebugBreakCallArgumentsCount(intptr_t data) {
+ DCHECK(DebugBreakIsCall(data));
+ return static_cast<int>(data);
+}
+
+
// -----------------------------------------------------------------------------
// Implementation of ExternalReference
void Assembler::RecordDebugBreakSlot() {
EnsureSpace ensure_space(this);
- RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
+ intptr_t data = static_cast<intptr_t>(RelocInfo::kDebugBreakNonCallSentinel);
+ RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT, data);
+}
+
+
+void Assembler::RecordDebugBreakSlotForCall(int argc) {
+ EnsureSpace ensure_space(this);
+ intptr_t data = static_cast<intptr_t>(argc);
+ RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT, data);
+}
+
+
+void Assembler::RecordDebugBreakSlotForConstructCall() {
+ EnsureSpace ensure_space(this);
+ intptr_t data =
+ static_cast<intptr_t>(RelocInfo::kDebugBreakConstructCallSentinel);
+ RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT, data);
}
// 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_)
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
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);
void ReadTaggedPC();
void AdvanceReadPC();
void AdvanceReadId();
+ void AdvanceReadInt();
void AdvanceReadPoolData();
+ void AdvanceReadDebugBreakSlotData();
void AdvanceReadPosition();
void AdvanceReadData();
void AdvanceReadVariableLengthPCJump();
}
-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);
}
#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, \
minor_key_ = state.GetExtraICState();
}
- static int ExtractArgcFromMinorKey(int minor_key) {
- CallICState state(static_cast<ExtraICState>(minor_key));
- return state.arg_count();
- }
-
Code::Kind GetCodeKind() const override { return Code::CALL_IC; }
InlineCacheState GetICState() const override { return DEFAULT; }
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_); }
continue;
}
- // Check for break at return.
if (RelocInfo::IsJSReturn(rmode())) {
// Set the positions to the end of the function.
if (debug_info_->shared()->HasSourceCode()) {
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_++;
}
} else if (IsDebugBreakSlot()) {
// Patch the code in the break slot.
SetDebugBreakAtSlot();
- } else {
- // Patch the IC call.
- SetDebugBreakAtIC();
}
DCHECK(IsDebugBreak());
}
} 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());
}
bool BreakLocation::IsStepInLocation() const {
- if (IsConstructCall()) return true;
- if (RelocInfo::IsCodeTarget(rmode())) {
- HandleScope scope(debug_info_->GetIsolate());
- Handle<Code> target_code = CodeTarget();
- return target_code->is_call_stub();
- }
- return false;
+ return IsConstructCall() || IsCall();
}
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<Code> DebugBreakForIC(Handle<Code> 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<Code>::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<Code> target_code = CodeTarget();
-
- // Patch the code to invoke the builtin debug break function matching the
- // calling convention used by the call site.
- Handle<Code> debug_break_code = DebugBreakForIC(target_code, rmode_);
- rinfo().set_target_address(debug_break_code->entry());
}
+ return false;
}
}
-Handle<Code> BreakLocation::CodeTarget() const {
- DCHECK(IsCodeTarget());
- Address target = rinfo().target_address();
- return Handle<Code>(Code::GetCodeFromTargetAddress(target));
-}
-
-
-Handle<Code> BreakLocation::OriginalCodeTarget() const {
- DCHECK(IsCodeTarget());
- Address target = original_rinfo().target_address();
- return Handle<Code>(Code::GetCodeFromTargetAddress(target));
-}
-
-
bool BreakLocation::Iterator::RinfoDone() const {
DCHECK(reloc_iterator_.done() == reloc_iterator_original_.done());
return reloc_iterator_.done();
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
}
// 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);
// Find the break point and change it.
BreakLocation location = BreakLocation::FromPosition(
- debug_info, SOURCE_BREAK_LOCATIONS, position, alignment);
+ debug_info, ALL_BREAK_LOCATIONS, position, alignment);
location.SetBreakPoint(break_point_object);
position = (alignment == STATEMENT_ALIGNED) ? location.statement_position()
break_point_info->code_position()->value();
BreakLocation location =
- BreakLocation::FromAddress(debug_info, SOURCE_BREAK_LOCATIONS, pc);
+ BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, pc);
location.ClearBreakPoint(break_point_object);
// If there are no more break points left remove the debug info for this
BreakLocation location =
BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc);
- if (thread_local_.restarter_frame_function_pointer_ == NULL) {
- if (location.IsCodeTarget()) {
- Handle<Code> target_code = location.CodeTarget();
-
- // Check if target code is CallFunction stub.
- Handle<Code> maybe_call_function_stub = target_code;
- // If there is a breakpoint at this line look at the original code to
- // check if it is a CallFunction stub.
- if (location.IsDebugBreak()) {
- maybe_call_function_stub = location.OriginalCodeTarget();
- }
- if ((maybe_call_function_stub->kind() == Code::STUB &&
- CodeStub::GetMajorKey(*maybe_call_function_stub) ==
- CodeStub::CallFunction) ||
- maybe_call_function_stub->is_call_stub()) {
- // Save reference to the code as we may need it to find out arguments
- // count for 'step in' later.
- call_function_stub = maybe_call_function_stub;
- }
- }
- } else {
+ if (thread_local_.restarter_frame_function_pointer_ != NULL) {
is_at_restarted_function = true;
}
Handle<JSFunction> restarted_function(
JSFunction::cast(*thread_local_.restarter_frame_function_pointer_));
FloodWithOneShot(restarted_function);
- } else if (!call_function_stub.is_null()) {
- // If it's CallFunction stub ensure target function is compiled and flood
- // it with one shot breakpoints.
- bool is_call_ic = call_function_stub->kind() == Code::CALL_IC;
-
- // Find out number of arguments from the stub minor key.
- uint32_t key = call_function_stub->stub_key();
- // Argc in the stub is the number of arguments passed - not the
- // expected arguments of the called function.
- int call_function_arg_count = is_call_ic
- ? CallICStub::ExtractArgcFromMinorKey(CodeStub::MinorKeyFromKey(key))
- : CallFunctionStub::ExtractArgcFromMinorKey(
- CodeStub::MinorKeyFromKey(key));
-
- DCHECK(is_call_ic ||
- CodeStub::GetMajorKey(*call_function_stub) ==
- CodeStub::MajorKeyFromKey(key));
-
+ } else if (location.IsCall()) {
// Find target function on the expression stack.
// Expression stack looks like this (top to bottom):
// argN
// arg0
// Receiver
// Function to call
- int expressions_count = frame->ComputeExpressionsCount();
- DCHECK(expressions_count - 2 - call_function_arg_count >= 0);
- Object* fun = frame->GetExpression(
- expressions_count - 2 - call_function_arg_count);
+ int num_expressions_without_args =
+ frame->ComputeExpressionsCount() - location.CallArgumentsCount();
+ DCHECK(num_expressions_without_args >= 2);
+ Object* fun = frame->GetExpression(num_expressions_without_args - 2);
// Flood the actual target of call/apply.
if (fun->IsJSFunction()) {
while (fun->IsJSFunction()) {
Code* code = JSFunction::cast(fun)->shared()->code();
if (code != apply && code != call) break;
- DCHECK(expressions_count - i - call_function_arg_count >= 0);
- fun = frame->GetExpression(expressions_count - i -
- call_function_arg_count);
- i -= 1;
+ DCHECK(num_expressions_without_args >= i);
+ fun = frame->GetExpression(num_expressions_without_args - i);
+ i--;
}
}
// Continue just after the slot.
after_break_target_ = addr + Assembler::kDebugBreakSlotLength;
- } else {
- addr = Assembler::target_address_from_return_address(frame->pc());
- if (IsDebugBreak(Assembler::target_address_at(addr, *code))) {
- // We now know that there is still a debug break call at the target
- // address, so the break point is still there and the original code will
- // hold the address to jump to in order to complete the call which is
- // replaced by a call to DebugBreakXXX.
-
- // Find the corresponding address in the original code.
- addr += original_code->instruction_start() - code->instruction_start();
-
- // Install jump to the call address in the original code. This will be the
- // call which was overwritten by the call to DebugBreakXXX.
- after_break_target_ = Assembler::target_address_at(addr, *original_code);
- } else {
- // There is no longer a break point present. Don't try to look in the
- // original code as the running code will have the right address. This
- // takes care of the case where the last break point is removed from the
- // function and therefore no "original code" is available.
- after_break_target_ = Assembler::target_address_at(addr, *code);
- }
}
}
// Type of exception break.
-enum BreakLocatorType {
- ALL_BREAK_LOCATIONS = 0,
- SOURCE_BREAK_LOCATIONS = 1,
- CALLS_AND_RETURNS = 2
-};
+enum BreakLocatorType { ALL_BREAK_LOCATIONS, CALLS_AND_RETURNS };
// The different types of breakpoint position alignments.
bool IsDebugBreak() const;
inline bool IsExit() const { return RelocInfo::IsJSReturn(rmode_); }
+ inline bool IsCall() const {
+ return IsDebugBreakSlot() && RelocInfo::DebugBreakIsCall(data_);
+ }
inline bool IsConstructCall() const {
- return RelocInfo::IsConstructCall(rmode_);
+ return IsDebugBreakSlot() && RelocInfo::DebugBreakIsConstructCall(data_);
+ }
+ inline int CallArgumentsCount() const {
+ DCHECK(IsCall());
+ return RelocInfo::DebugBreakCallArgumentsCount(data_);
}
- inline bool IsCodeTarget() const { return RelocInfo::IsCodeTarget(rmode_); }
-
- Handle<Code> CodeTarget() const;
- Handle<Code> OriginalCodeTarget() const;
bool IsStepInLocation() const;
inline bool HasBreakPoint() const {
void SetOneShot();
void ClearOneShot();
+
inline RelocInfo rinfo() const {
return RelocInfo(pc(), rmode(), data_, code());
}
- inline RelocInfo original_rinfo() const {
- return RelocInfo(original_pc(), original_rmode(), original_data_,
- original_code());
- }
-
inline int position() const { return position_; }
inline int statement_position() const { return statement_position_; }
inline Address pc() const { return code()->entry() + pc_offset_; }
inline Address original_pc() const {
- return original_code()->entry() + original_pc_offset_;
+ return debug_info_->original_code()->entry() + original_pc_offset_;
}
inline RelocInfo::Mode rmode() const { return rmode_; }
- inline RelocInfo::Mode original_rmode() const { return original_rmode_; }
inline Code* code() const { return debug_info_->code(); }
- inline Code* original_code() const { return debug_info_->original_code(); }
private:
BreakLocation(Handle<DebugInfo> debug_info, RelocInfo* rinfo,
}
inline RelocInfo::Mode rmode() { return reloc_iterator_.rinfo()->rmode(); }
- inline RelocInfo::Mode original_rmode() {
- return reloc_iterator_.rinfo()->rmode();
- }
-
inline RelocInfo* rinfo() { return reloc_iterator_.rinfo(); }
inline RelocInfo* original_rinfo() {
return reloc_iterator_original_.rinfo();
}
inline Address pc() { return rinfo()->pc(); }
- inline Address original_pc() { return original_rinfo()->pc(); }
-
int break_index() const { return break_index_; }
-
inline int position() const { return position_; }
inline int statement_position() const { return statement_position_; }
void SetDebugBreak();
void SetDebugBreakAtReturn();
void SetDebugBreakAtSlot();
- void SetDebugBreakAtIC();
inline bool IsDebuggerStatement() const {
return RelocInfo::IsDebuggerStatement(rmode_);
class DebugCodegen : public AllStatic {
public:
static void GenerateSlot(MacroAssembler* masm);
- static void GenerateCallICStubDebugBreak(MacroAssembler* masm);
- static void GenerateLoadICDebugBreak(MacroAssembler* masm);
- static void GenerateStoreICDebugBreak(MacroAssembler* masm);
- static void GenerateKeyedLoadICDebugBreak(MacroAssembler* masm);
- static void GenerateKeyedStoreICDebugBreak(MacroAssembler* masm);
- static void GenerateCompareNilICDebugBreak(MacroAssembler* masm);
static void GenerateReturnDebugBreak(MacroAssembler* masm);
- static void GenerateCallFunctionStubDebugBreak(MacroAssembler* masm);
- static void GenerateCallConstructStubDebugBreak(MacroAssembler* masm);
- static void GenerateCallConstructStubRecordDebugBreak(MacroAssembler* masm);
static void GenerateSlotDebugBreak(MacroAssembler* masm);
static void GeneratePlainReturnLiveEdit(MacroAssembler* masm);
DCHECK(major_key == CodeStub::MajorKeyFromKey(key));
out.AddFormatted(" %s, %s, ", Code::Kind2String(kind),
CodeStub::MajorName(major_key, false));
- switch (major_key) {
- case CodeStub::CallFunction: {
- int argc = CallFunctionStub::ExtractArgcFromMinorKey(minor_key);
- out.AddFormatted("argc = %d", argc);
- break;
- }
- default:
- out.AddFormatted("minor: %d", minor_key);
- }
+ out.AddFormatted("minor: %d", minor_key);
} else {
out.AddFormatted(" %s", Code::Kind2String(kind));
}
bool recorded = RecordStatementPosition(masm_, stmt->position());
if (recorded && insert_break == INSERT_BREAK && info_->is_debug() &&
!stmt->IsDebuggerStatement()) {
+ masm_->RecordDebugBreakSlot();
DebugCodegen::GenerateSlot(masm_);
}
}
if (expr->position() == RelocInfo::kNoPosition) return;
bool recorded = RecordPosition(masm_, expr->position());
if (recorded && insert_break == INSERT_BREAK && info_->is_debug()) {
+ masm_->RecordDebugBreakSlot();
DebugCodegen::GenerateSlot(masm_);
}
}
void FullCodeGenerator::SetExpressionAsStatementPosition(Expression* expr) {
if (expr->position() == RelocInfo::kNoPosition) return;
bool recorded = RecordStatementPosition(masm_, expr->position());
- if (recorded && info_->is_debug()) DebugCodegen::GenerateSlot(masm_);
+ if (recorded && info_->is_debug()) {
+ masm_->RecordDebugBreakSlot();
+ DebugCodegen::GenerateSlot(masm_);
+ }
+}
+
+
+void FullCodeGenerator::SetCallPosition(Expression* expr, int argc) {
+ if (expr->position() == RelocInfo::kNoPosition) return;
+ RecordPosition(masm_, expr->position());
+ if (info_->is_debug()) {
+ // Always emit a debug break slot before a call.
+ masm_->RecordDebugBreakSlotForCall(argc);
+ DebugCodegen::GenerateSlot(masm_);
+ }
+}
+
+
+void FullCodeGenerator::SetConstructCallPosition(Expression* expr) {
+ if (expr->position() == RelocInfo::kNoPosition) return;
+ RecordPosition(masm_, expr->position());
+ if (info_->is_debug()) {
+ // Always emit a debug break slot before a construct call.
+ masm_->RecordDebugBreakSlotForConstructCall();
+ DebugCodegen::GenerateSlot(masm_);
+ }
}
// This is used in loop headers where we want to break for each iteration.
void SetExpressionAsStatementPosition(Expression* expr);
+ void SetCallPosition(Expression* expr, int argc);
+
+ void SetConstructCallPosition(Expression* expr);
+
// Non-local control flow support.
void EnterTryBlock(int handler_index, Label* handler);
void ExitTryBlock(int handler_index);
// Mark address of a debug break slot.
void RecordDebugBreakSlot();
+ void RecordDebugBreakSlotForCall(int argc);
+ void RecordDebugBreakSlotForConstructCall();
// Record a comment relocation entry that can be used by a disassembler.
// Use --code-comments to enable.
#define __ ACCESS_MASM(masm)
static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
- RegList object_regs,
- RegList non_object_regs,
- bool convert_call_to_jmp) {
+ RegList object_regs) {
// Enter an internal frame.
{
FrameScope scope(masm, StackFrame::INTERNAL);
// 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);
for (int i = 0; i < kNumJSCallerSaved; i++) {
int r = JSCallerSavedCode(i);
Register reg = { r };
if ((object_regs & (1 << r)) != 0) {
__ push(reg);
}
- if ((non_object_regs & (1 << r)) != 0) {
- if (FLAG_debug_code) {
- __ test(reg, Immediate(0xc0000000));
- __ Assert(zero, kUnableToEncodeValueAsSmi);
- }
- __ SmiTag(reg);
- __ push(reg);
- }
}
#ifdef DEBUG
__ pop(reg);
taken = true;
}
- if ((non_object_regs & (1 << r)) != 0) {
- __ pop(reg);
- __ SmiUntag(reg);
- taken = true;
- }
if (!taken) {
unused_reg = reg;
}
// Get rid of the internal frame.
}
- // If this call did not replace a call but patched other code then there will
- // be an unwanted return address left on the stack. Here we get rid of that.
- if (convert_call_to_jmp) {
- __ add(esp, Immediate(kPointerSize));
- }
+ // This call did not replace a call , so there will be an unwanted
+ // return address left on the stack. Here we get rid of that.
+ __ add(esp, Immediate(kPointerSize));
// Now that the break point has been handled, resume normal execution by
// jumping to the target address intended by the caller and that was
}
-void DebugCodegen::GenerateCallICStubDebugBreak(MacroAssembler* masm) {
- // Register state for CallICStub
- // ----------- S t a t e -------------
- // -- edx : type feedback slot (smi)
- // -- edi : function
- // -----------------------------------
- Generate_DebugBreakCallHelper(masm, edx.bit() | edi.bit(),
- 0, false);
-}
-
-
void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) {
// Register state just before return from JS function (from codegen-ia32.cc).
// ----------- S t a t e -------------
// -- eax: return value
// -----------------------------------
- Generate_DebugBreakCallHelper(masm, eax.bit(), 0, true);
-}
-
-
-void DebugCodegen::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
- // Register state for CallFunctionStub (from code-stubs-ia32.cc).
- // ----------- S t a t e -------------
- // -- edi: function
- // -----------------------------------
- Generate_DebugBreakCallHelper(masm, edi.bit(), 0, false);
-}
-
-
-void DebugCodegen::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) {
- // Register state for CallConstructStub (from code-stubs-ia32.cc).
- // eax is the actual number of arguments not encoded as a smi see comment
- // above IC call.
- // ----------- S t a t e -------------
- // -- eax: number of arguments (not smi)
- // -- edi: constructor function
- // -----------------------------------
- // The number of arguments in eax is not smi encoded.
- Generate_DebugBreakCallHelper(masm, edi.bit(), eax.bit(), false);
-}
-
-
-void DebugCodegen::GenerateCallConstructStubRecordDebugBreak(
- MacroAssembler* masm) {
- // Register state for CallConstructStub (from code-stubs-ia32.cc).
- // eax is the actual number of arguments not encoded as a smi see comment
- // above IC call.
- // ----------- S t a t e -------------
- // -- eax: number of arguments (not smi)
- // -- ebx: feedback array
- // -- edx: feedback slot (smi)
- // -- edi: constructor function
- // -----------------------------------
- // The number of arguments in eax is not smi encoded.
- Generate_DebugBreakCallHelper(masm, ebx.bit() | edx.bit() | edi.bit(),
- eax.bit(), false);
+ Generate_DebugBreakCallHelper(masm, eax.bit());
}
// Generate enough nop's to make space for a call instruction.
Label check_codesize;
__ bind(&check_codesize);
- __ RecordDebugBreakSlot();
__ Nop(Assembler::kDebugBreakSlotLength);
DCHECK_EQ(Assembler::kDebugBreakSlotLength,
masm->SizeOfCodeGeneratedSince(&check_codesize));
void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) {
- Generate_DebugBreakCallHelper(masm, 0, 0, true);
+ Generate_DebugBreakCallHelper(masm, 0);
}
CallIC(ic, TypeFeedbackId::None());
__ mov(edi, eax);
__ mov(Operand(esp, 2 * kPointerSize), edi);
+ SetCallPosition(expr, 1);
CallFunctionStub stub(isolate(), 1, CALL_AS_METHOD);
__ CallStub(&stub);
VisitForStackValue(args->at(i));
}
- SetExpressionPosition(expr);
+ SetCallPosition(expr, arg_count);
Handle<Code> ic = CodeFactory::CallIC(isolate(), arg_count, call_type).code();
__ Move(edx, Immediate(SmiFromSlot(expr->CallFeedbackICSlot())));
__ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
PrepareForBailoutForId(expr->EvalId(), NO_REGISTERS);
- SetExpressionPosition(expr);
+ SetCallPosition(expr, arg_count);
CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
__ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
__ CallStub(&stub);
// Call the construct call builtin that handles allocation and
// constructor invocation.
- SetExpressionPosition(expr);
+ SetConstructCallPosition(expr);
// Load function and argument count into edi and eax.
__ Move(eax, Immediate(arg_count));
// Call the construct call builtin that handles allocation and
// constructor invocation.
- SetExpressionPosition(expr);
+ SetConstructCallPosition(expr);
// Load function and argument count into edi and eax.
__ Move(eax, Immediate(arg_count));
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
- SetExpressionPosition(expr);
+ SetCallPosition(expr, arg_count);
CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
__ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
__ CallStub(&stub);
// 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.
#define __ ACCESS_MASM(masm)
-
static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
- RegList object_regs,
- RegList non_object_regs) {
+ RegList object_regs) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
// 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) {
- __ And(at, reg, 0xc0000000);
- __ Assert(eq, kUnableToEncodeValueAsSmi, at, Operand(zero_reg));
- }
- __ sll(reg, reg, kSmiTagSize);
- }
- }
- __ MultiPush(object_regs | non_object_regs);
+ if (object_regs != 0) {
+ __ MultiPush(object_regs);
}
#ifdef DEBUG
__ CallStub(&ceb);
// Restore the register values from the expression stack.
- if ((object_regs | non_object_regs) != 0) {
- __ MultiPop(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) {
- __ srl(reg, reg, kSmiTagSize);
- }
- if (FLAG_debug_code &&
- (((object_regs |non_object_regs) & (1 << r)) == 0)) {
- __ li(reg, kDebugZapValue);
- }
+ if (object_regs != 0) {
+ __ MultiPop(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)) {
+ __ li(reg, kDebugZapValue);
}
}
}
-void DebugCodegen::GenerateCallICStubDebugBreak(MacroAssembler* masm) {
- // Register state for CallICStub
- // ----------- S t a t e -------------
- // -- a1 : function
- // -- a3 : slot in feedback array (smi)
- // -----------------------------------
- Generate_DebugBreakCallHelper(masm, a1.bit() | a3.bit(), 0);
-}
-
-
void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) {
// In places other than IC call sites it is expected that v0 is TOS which
// is an object - this is not generally the case so this should be used with
// care.
- Generate_DebugBreakCallHelper(masm, v0.bit(), 0);
-}
-
-
-void DebugCodegen::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
- // Register state for CallFunctionStub (from code-stubs-mips.cc).
- // ----------- S t a t e -------------
- // -- a1 : function
- // -----------------------------------
- Generate_DebugBreakCallHelper(masm, a1.bit(), 0);
-}
-
-
-void DebugCodegen::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) {
- // Calling convention for CallConstructStub (from code-stubs-mips.cc).
- // ----------- S t a t e -------------
- // -- a0 : number of arguments (not smi)
- // -- a1 : constructor function
- // -----------------------------------
- Generate_DebugBreakCallHelper(masm, a1.bit() , a0.bit());
-}
-
-
-void DebugCodegen::GenerateCallConstructStubRecordDebugBreak(
- MacroAssembler* masm) {
- // Calling convention for CallConstructStub (from code-stubs-mips.cc).
- // ----------- S t a t e -------------
- // -- a0 : number of arguments (not smi)
- // -- a1 : constructor function
- // -- a2 : feedback array
- // -- a3 : feedback slot (smi)
- // -----------------------------------
- Generate_DebugBreakCallHelper(masm, a1.bit() | a2.bit() | a3.bit(), a0.bit());
+ Generate_DebugBreakCallHelper(masm, v0.bit());
}
Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm);
Label check_codesize;
__ bind(&check_codesize);
- __ RecordDebugBreakSlot();
for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
__ nop(MacroAssembler::DEBUG_BREAK_NOP);
}
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);
}
__ mov(a0, v0);
__ mov(a1, a0);
__ sw(a1, MemOperand(sp, 2 * kPointerSize));
+ SetCallPosition(expr, 1);
CallFunctionStub stub(isolate(), 1, CALL_AS_METHOD);
__ CallStub(&stub);
}
// Record source position of the IC call.
- SetExpressionPosition(expr);
+ SetCallPosition(expr, arg_count);
Handle<Code> ic = CodeFactory::CallIC(isolate(), arg_count, call_type).code();
__ li(a3, Operand(SmiFromSlot(expr->CallFeedbackICSlot())));
__ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
// function using the given arguments.
ZoneList<Expression*>* 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.
- __ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
- __ push(a1);
- EmitResolvePossiblyDirectEval(arg_count);
+ // Push a copy of the function (found below the arguments) and
+ // resolve eval.
+ __ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
+ __ push(a1);
+ EmitResolvePossiblyDirectEval(arg_count);
- // Touch up the stack with the resolved function.
- __ sw(v0, MemOperand(sp, (arg_count + 1) * kPointerSize));
+ // Touch up the stack with the resolved function.
+ __ sw(v0, MemOperand(sp, (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);
CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
__ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ CallStub(&stub);
// Call the construct call builtin that handles allocation and
// constructor invocation.
- SetExpressionPosition(expr);
+ SetConstructCallPosition(expr);
// Load function and argument count into a1 and a0.
__ li(a0, Operand(arg_count));
// Call the construct call builtin that handles allocation and
// constructor invocation.
- SetExpressionPosition(expr);
+ SetConstructCallPosition(expr);
// Load function and argument count into a1 and a0.
__ li(a0, Operand(arg_count));
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
- SetExpressionPosition(expr);
+ SetCallPosition(expr, arg_count);
CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
__ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ CallStub(&stub);
// 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.
#define __ ACCESS_MASM(masm)
-
static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
- RegList object_regs,
- RegList non_object_regs) {
+ RegList object_regs) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
// 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);
for (int i = 0; i < kNumJSCallerSaved; i++) {
int r = JSCallerSavedCode(i);
Register reg = { r };
if ((object_regs & (1 << r)) != 0) {
__ push(reg);
}
- if ((non_object_regs & (1 << r)) != 0) {
- __ PushRegisterAsTwoSmis(reg);
- }
}
#ifdef DEBUG
for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
int r = JSCallerSavedCode(i);
Register reg = { r };
- if ((non_object_regs & (1 << r)) != 0) {
- __ PopRegisterAsTwoSmis(reg, at);
- }
if ((object_regs & (1 << r)) != 0) {
__ pop(reg);
}
- if (FLAG_debug_code &&
- (((object_regs |non_object_regs) & (1 << r)) == 0)) {
+ if (FLAG_debug_code && ((object_regs & (1 << r)) == 0)) {
__ li(reg, kDebugZapValue);
}
}
}
-void DebugCodegen::GenerateCallICStubDebugBreak(MacroAssembler* masm) {
- // Register state for CallICStub
- // ----------- S t a t e -------------
- // -- a1 : function
- // -- a3 : slot in feedback array (smi)
- // -----------------------------------
- Generate_DebugBreakCallHelper(masm, a1.bit() | a3.bit(), 0);
-}
-
-
void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) {
// In places other than IC call sites it is expected that v0 is TOS which
// is an object - this is not generally the case so this should be used with
// care.
- Generate_DebugBreakCallHelper(masm, v0.bit(), 0);
-}
-
-
-void DebugCodegen::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
- // Register state for CallFunctionStub (from code-stubs-mips.cc).
- // ----------- S t a t e -------------
- // -- a1 : function
- // -----------------------------------
- Generate_DebugBreakCallHelper(masm, a1.bit(), 0);
-}
-
-
-void DebugCodegen::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) {
- // Calling convention for CallConstructStub (from code-stubs-mips.cc).
- // ----------- S t a t e -------------
- // -- a0 : number of arguments (not smi)
- // -- a1 : constructor function
- // -----------------------------------
- Generate_DebugBreakCallHelper(masm, a1.bit() , a0.bit());
-}
-
-
-
-void DebugCodegen::GenerateCallConstructStubRecordDebugBreak(
- MacroAssembler* masm) {
- // Calling convention for CallConstructStub (from code-stubs-mips.cc).
- // ----------- S t a t e -------------
- // -- a0 : number of arguments (not smi)
- // -- a1 : constructor function
- // -- a2 : feedback array
- // -- a3 : feedback slot (smi)
- // -----------------------------------
- Generate_DebugBreakCallHelper(masm, a1.bit() | a2.bit() | a3.bit(), a0.bit());
+ Generate_DebugBreakCallHelper(masm, v0.bit());
}
Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm);
Label check_codesize;
__ bind(&check_codesize);
- __ RecordDebugBreakSlot();
for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
__ nop(MacroAssembler::DEBUG_BREAK_NOP);
}
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);
}
__ mov(a0, v0);
__ mov(a1, a0);
__ sd(a1, MemOperand(sp, 2 * kPointerSize));
+ SetCallPosition(expr, 1);
CallFunctionStub stub(isolate(), 1, CALL_AS_METHOD);
__ CallStub(&stub);
}
// Record source position of the IC call.
- SetExpressionPosition(expr);
+ SetCallPosition(expr, arg_count);
Handle<Code> ic = CodeFactory::CallIC(isolate(), arg_count, call_type).code();
__ li(a3, Operand(SmiFromSlot(expr->CallFeedbackICSlot())));
__ ld(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
// function using the given arguments.
ZoneList<Expression*>* 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.
- __ ld(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
- __ push(a1);
- EmitResolvePossiblyDirectEval(arg_count);
+ // Push a copy of the function (found below the arguments) and
+ // resolve eval.
+ __ ld(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
+ __ push(a1);
+ EmitResolvePossiblyDirectEval(arg_count);
- // Touch up the stack with the resolved function.
- __ sd(v0, MemOperand(sp, (arg_count + 1) * kPointerSize));
+ // Touch up the stack with the resolved function.
+ __ sd(v0, MemOperand(sp, (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);
CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
__ ld(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ CallStub(&stub);
// Call the construct call builtin that handles allocation and
// constructor invocation.
- SetExpressionPosition(expr);
+ SetConstructCallPosition(expr);
// Load function and argument count into a1 and a0.
__ li(a0, Operand(arg_count));
// Call the construct call builtin that handles allocation and
// constructor invocation.
- SetExpressionPosition(expr);
+ SetConstructCallPosition(expr);
// Load function and argument count into a1 and a0.
__ li(a0, Operand(arg_count));
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
- SetExpressionPosition(expr);
+ SetCallPosition(expr, arg_count);
CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
__ ld(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ CallStub(&stub);
// Mark address of a debug break slot.
void RecordDebugBreakSlot();
+ void RecordDebugBreakSlotForCall(int argc);
+ void RecordDebugBreakSlotForConstructCall();
// Record a comment relocation entry that can be used by a disassembler.
// Use --code-comments to enable.
static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
- RegList object_regs,
- RegList non_object_regs,
- bool convert_call_to_jmp) {
+ RegList object_regs) {
// Enter an internal frame.
{
FrameScope scope(masm, StackFrame::INTERNAL);
// make sure that these are correctly updated during GC. Non object values
// are stored as as two smis 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);
for (int i = 0; i < kNumJSCallerSaved; i++) {
int r = JSCallerSavedCode(i);
Register reg = { r };
if ((object_regs & (1 << r)) != 0) {
__ Push(reg);
}
- if ((non_object_regs & (1 << r)) != 0) {
- __ PushRegisterAsTwoSmis(reg);
- }
}
#ifdef DEBUG
if ((object_regs & (1 << r)) != 0) {
__ Pop(reg);
}
- // Reconstruct the 64-bit value from two smis.
- if ((non_object_regs & (1 << r)) != 0) {
- __ PopRegisterAsTwoSmis(reg);
- }
}
// Read current padding counter and skip corresponding number of words.
// Get rid of the internal frame.
}
- // If this call did not replace a call but patched other code then there will
- // be an unwanted return address left on the stack. Here we get rid of that.
- if (convert_call_to_jmp) {
- __ addp(rsp, Immediate(kPCOnStackSize));
- }
+ // This call did not replace a call , so there will be an unwanted
+ // return address left on the stack. Here we get rid of that.
+ __ addp(rsp, Immediate(kPCOnStackSize));
// Now that the break point has been handled, resume normal execution by
// jumping to the target address intended by the caller and that was
}
-void DebugCodegen::GenerateCallICStubDebugBreak(MacroAssembler* masm) {
- // Register state for CallICStub
- // ----------- S t a t e -------------
- // -- rdx : type feedback slot (smi)
- // -- rdi : function
- // -----------------------------------
- Generate_DebugBreakCallHelper(masm, rdx.bit() | rdi.bit(), 0, false);
-}
-
-
void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) {
// Register state just before return from JS function (from codegen-x64.cc).
// ----------- S t a t e -------------
// -- rax: return value
// -----------------------------------
- Generate_DebugBreakCallHelper(masm, rax.bit(), 0, true);
-}
-
-
-void DebugCodegen::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
- // Register state for CallFunctionStub (from code-stubs-x64.cc).
- // ----------- S t a t e -------------
- // -- rdi : function
- // -----------------------------------
- Generate_DebugBreakCallHelper(masm, rdi.bit(), 0, false);
-}
-
-
-void DebugCodegen::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) {
- // Register state for CallConstructStub (from code-stubs-x64.cc).
- // rax is the actual number of arguments not encoded as a smi, see comment
- // above IC call.
- // ----------- S t a t e -------------
- // -- rax: number of arguments
- // -----------------------------------
- // The number of arguments in rax is not smi encoded.
- Generate_DebugBreakCallHelper(masm, rdi.bit(), rax.bit(), false);
-}
-
-
-void DebugCodegen::GenerateCallConstructStubRecordDebugBreak(
- MacroAssembler* masm) {
- // Register state for CallConstructStub (from code-stubs-x64.cc).
- // rax is the actual number of arguments not encoded as a smi, see comment
- // above IC call.
- // ----------- S t a t e -------------
- // -- rax: number of arguments
- // -- rbx: feedback array
- // -- rdx: feedback slot (smi)
- // -----------------------------------
- // The number of arguments in rax is not smi encoded.
- Generate_DebugBreakCallHelper(masm, rbx.bit() | rdx.bit() | rdi.bit(),
- rax.bit(), false);
+ Generate_DebugBreakCallHelper(masm, rax.bit());
}
// Generate enough nop's to make space for a call instruction.
Label check_codesize;
__ bind(&check_codesize);
- __ RecordDebugBreakSlot();
__ Nop(Assembler::kDebugBreakSlotLength);
DCHECK_EQ(Assembler::kDebugBreakSlotLength,
masm->SizeOfCodeGeneratedSince(&check_codesize));
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, true);
+ Generate_DebugBreakCallHelper(masm, 0);
}
CallIC(ic, TypeFeedbackId::None());
__ movp(rdi, rax);
__ movp(Operand(rsp, 2 * kPointerSize), rdi);
+
+ SetCallPosition(expr, 1);
CallFunctionStub stub(isolate(), 1, CALL_AS_METHOD);
__ CallStub(&stub);
VisitForStackValue(args->at(i));
}
- SetExpressionPosition(expr);
+ SetCallPosition(expr, arg_count);
Handle<Code> ic = CodeFactory::CallIC(isolate(), arg_count, call_type).code();
__ Move(rdx, SmiFromSlot(expr->CallFeedbackICSlot()));
__ movp(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
// function using the given arguments.
ZoneList<Expression*>* 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.
+ __ Push(Operand(rsp, (arg_count + 1) * kPointerSize));
+ EmitResolvePossiblyDirectEval(arg_count);
- // Push a copy of the function (found below the arguments) and resolve
- // eval.
- __ Push(Operand(rsp, (arg_count + 1) * kPointerSize));
- EmitResolvePossiblyDirectEval(arg_count);
+ // Touch up the callee.
+ __ movp(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
- // Touch up the callee.
- __ movp(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
+ PrepareForBailoutForId(expr->EvalId(), NO_REGISTERS);
- 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);
__ movp(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
__ CallStub(&stub);
// Call the construct call builtin that handles allocation and
// constructor invocation.
- SetExpressionPosition(expr);
+ SetConstructCallPosition(expr);
// Load function and argument count into rdi and rax.
__ Set(rax, arg_count);
// Call the construct call builtin that handles allocation and
// constructor invocation.
- SetExpressionPosition(expr);
+ SetConstructCallPosition(expr);
// Load function and argument count into edi and eax.
__ Set(rax, arg_count);
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
- SetExpressionPosition(expr);
+ SetCallPosition(expr, arg_count);
CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
__ movp(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
__ CallStub(&stub);
}
-// Compile a function, set a break point and check that the call at the break
-// location in the code is the expected debug_break function.
-void CheckDebugBreakFunction(DebugLocalContext* env,
- const char* source, const char* name,
- int position, v8::internal::RelocInfo::Mode mode,
- Code* debug_break) {
- EnableDebugger();
- i::Debug* debug = CcTest::i_isolate()->debug();
-
- // Create function and set the break point.
- Handle<i::JSFunction> fun =
- v8::Utils::OpenHandle(*CompileFunction(env, source, name));
- int bp = SetBreakPoint(fun, position);
-
- // Check that the debug break function is as expected.
- Handle<i::SharedFunctionInfo> shared(fun->shared());
- CHECK(Debug::HasDebugInfo(shared));
- i::BreakLocation location = i::BreakLocation::FromPosition(
- Debug::GetDebugInfo(shared), i::SOURCE_BREAK_LOCATIONS, position,
- i::STATEMENT_ALIGNED);
- i::RelocInfo::Mode actual_mode = location.rmode();
- if (actual_mode == i::RelocInfo::CODE_TARGET_WITH_ID) {
- actual_mode = i::RelocInfo::CODE_TARGET;
- }
- CHECK_EQ(mode, actual_mode);
- if (mode != i::RelocInfo::JS_RETURN) {
- CHECK_EQ(debug_break, *location.CodeTarget());
- } else {
- i::RelocInfo rinfo = location.rinfo();
- CHECK(i::RelocInfo::IsJSReturn(rinfo.rmode()));
- CHECK(rinfo.IsPatchedReturnSequence());
- }
-
- // Clear the break point and check that the debug break function is no longer
- // there
- ClearBreakPoint(bp);
- CHECK(!debug->HasDebugInfo(shared));
- CHECK(debug->EnsureDebugInfo(shared, fun));
- location = i::BreakLocation::FromPosition(Debug::GetDebugInfo(shared),
- i::SOURCE_BREAK_LOCATIONS, position,
- i::STATEMENT_ALIGNED);
- actual_mode = location.rmode();
- if (actual_mode == i::RelocInfo::CODE_TARGET_WITH_ID) {
- actual_mode = i::RelocInfo::CODE_TARGET;
- }
- CHECK_EQ(mode, actual_mode);
- if (mode == i::RelocInfo::JS_RETURN) {
- i::RelocInfo rinfo = location.rinfo();
- CHECK(!rinfo.IsPatchedReturnSequence());
- }
-
- DisableDebugger();
-}
-
-
// --- D e b u g E v e n t H a n d l e r s
// ---
// --- The different tests uses a number of debug event handlers.
--- /dev/null
+// 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
+
+var break_count = 0;
+var exception = null;
+
+function listener(event, exec_state, event_data, data) {
+ if (event != Debug.DebugEvent.Break) return;
+ try {
+ var source_line = exec_state.frame(0).sourceLineText();
+ print(source_line);
+ exec_state.prepareStep(Debug.StepAction.StepIn, 1);
+ break_count++;
+ } catch (e) {
+ exception = e;
+ }
+}
+
+var Debug = debug.Debug;
+Debug.setListener(listener);
+
+
+function f() {
+ this.x = 1;
+}
+
+function g() {
+ new f();
+}
+
+Debug.setBreakPoint(g, 6, Debug.BreakPositionAlignment.BreakPosition);
+print(Debug.showBreakPoints(g, undefined,
+ Debug.BreakPositionAlignment.BreakPosition));
+
+g();
+Debug.setListener(null);
+
+assertEquals(6, break_count);
+assertNull(exception);