Commit be5763fc authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

Cleanup the way the debugger stores live registers when entering at a break

The live registers are now only stored to the expression stack with the non pointer values being stored as smis (on the 32-bit platforms these values are assumed to be 31-bit max).

This makes the CEntryStub entry/exit code much simpler, and there is no longer any need for a mode (debug or normal) on it.

Fix a missing live register when breaking at ARM keyed load.
Review URL: http://codereview.chromium.org/3141047

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5358 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent ee1dc277
...@@ -2702,7 +2702,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, ...@@ -2702,7 +2702,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
// r0:r1: result // r0:r1: result
// sp: stack pointer // sp: stack pointer
// fp: frame pointer // fp: frame pointer
__ LeaveExitFrame(mode_); __ LeaveExitFrame();
// check if we should retry or throw exception // check if we should retry or throw exception
Label retry; Label retry;
...@@ -2751,7 +2751,7 @@ void CEntryStub::Generate(MacroAssembler* masm) { ...@@ -2751,7 +2751,7 @@ void CEntryStub::Generate(MacroAssembler* masm) {
// builtin once. // builtin once.
// Enter the exit frame that transitions from JavaScript to C++. // Enter the exit frame that transitions from JavaScript to C++.
__ EnterExitFrame(mode_); __ EnterExitFrame();
// r4: number of arguments (C callee-saved) // r4: number of arguments (C callee-saved)
// r5: pointer to builtin function (C callee-saved) // r5: pointer to builtin function (C callee-saved)
......
...@@ -130,21 +130,30 @@ void BreakLocationIterator::ClearDebugBreakAtSlot() { ...@@ -130,21 +130,30 @@ void BreakLocationIterator::ClearDebugBreakAtSlot() {
static void Generate_DebugBreakCallHelper(MacroAssembler* masm, static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
RegList pointer_regs) { RegList object_regs,
// Save the content of all general purpose registers in memory. This copy in RegList non_object_regs) {
// memory is later pushed onto the JS expression stack for the fake JS frame
// generated and also to the C frame generated on top of that. In the JS
// frame ONLY the registers containing pointers will be pushed on the
// expression stack. This causes the GC to update these pointers so that
// they will have the correct value when returning from the debugger.
__ SaveRegistersToMemory(kJSCallerSaved);
__ EnterInternalFrame(); __ EnterInternalFrame();
// Store the registers containing object pointers on the expression stack to // Store the registers containing live values on the expression stack to
// make sure that these are correctly updated during GC. // make sure that these are correctly updated during GC. Non object values
// Use sp as base to push. // are stored as a smi causing it to be untouched by GC.
__ CopyRegistersFromMemoryToStack(sp, pointer_regs); ASSERT((object_regs & ~kJSCallerSaved) == 0);
ASSERT((non_object_regs & ~kJSCallerSaved) == 0);
ASSERT((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, "Unable to encode value as smi");
}
__ mov(reg, Operand(reg, LSL, kSmiTagSize));
}
}
__ stm(db_w, sp, object_regs | non_object_regs);
}
#ifdef DEBUG #ifdef DEBUG
__ RecordComment("// Calling from debug break to runtime - come in - over"); __ RecordComment("// Calling from debug break to runtime - come in - over");
...@@ -152,19 +161,27 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, ...@@ -152,19 +161,27 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
__ mov(r0, Operand(0)); // no arguments __ mov(r0, Operand(0)); // no arguments
__ mov(r1, Operand(ExternalReference::debug_break())); __ mov(r1, Operand(ExternalReference::debug_break()));
CEntryStub ceb(1, ExitFrame::MODE_DEBUG); CEntryStub ceb(1);
__ CallStub(&ceb); __ CallStub(&ceb);
// Restore the register values containing object pointers from the expression // Restore the register values from the expression stack.
// stack in the reverse order as they where pushed. if ((object_regs | non_object_regs) != 0) {
// Use sp as base to pop. __ ldm(ia_w, sp, object_regs | non_object_regs);
__ CopyRegistersFromStackToMemory(sp, r3, pointer_regs); for (int i = 0; i < kNumJSCallerSaved; i++) {
int r = JSCallerSavedCode(i);
Register reg = { r };
if ((non_object_regs & (1 << r)) != 0) {
__ mov(reg, Operand(reg, LSR, kSmiTagSize));
}
if (FLAG_debug_code &&
(((object_regs |non_object_regs) & (1 << r)) == 0)) {
__ mov(reg, Operand(kDebugZapValue));
}
}
}
__ LeaveInternalFrame(); __ LeaveInternalFrame();
// Finally restore all registers.
__ RestoreRegistersFromMemory(kJSCallerSaved);
// Now that the break point has been handled, resume normal execution by // Now that the break point has been handled, resume normal execution by
// jumping to the target address intended by the caller and that was // jumping to the target address intended by the caller and that was
// overwritten by the address of DebugBreakXXX. // overwritten by the address of DebugBreakXXX.
...@@ -184,7 +201,7 @@ void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) { ...@@ -184,7 +201,7 @@ void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
// ----------------------------------- // -----------------------------------
// Registers r0 and r2 contain objects that need to be pushed on the // Registers r0 and r2 contain objects that need to be pushed on the
// expression stack of the fake JS frame. // expression stack of the fake JS frame.
Generate_DebugBreakCallHelper(masm, r0.bit() | r2.bit()); Generate_DebugBreakCallHelper(masm, r0.bit() | r2.bit(), 0);
} }
...@@ -198,7 +215,7 @@ void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) { ...@@ -198,7 +215,7 @@ void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) {
// ----------------------------------- // -----------------------------------
// Registers r0, r1, and r2 contain objects that need to be pushed on the // Registers r0, r1, and r2 contain objects that need to be pushed on the
// expression stack of the fake JS frame. // expression stack of the fake JS frame.
Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit() | r2.bit()); Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit() | r2.bit(), 0);
} }
...@@ -206,9 +223,8 @@ void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) { ...@@ -206,9 +223,8 @@ void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
// ---------- S t a t e -------------- // ---------- S t a t e --------------
// -- lr : return address // -- lr : return address
// -- r0 : key // -- r0 : key
// -- sp[0] : key // -- r1 : receiver
// -- sp[4] : receiver Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit(), 0);
Generate_DebugBreakCallHelper(masm, r0.bit());
} }
...@@ -218,24 +234,24 @@ void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) { ...@@ -218,24 +234,24 @@ void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
// -- r1 : key // -- r1 : key
// -- r2 : receiver // -- r2 : receiver
// -- lr : return address // -- lr : return address
Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit() | r2.bit()); Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit() | r2.bit(), 0);
} }
void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) { void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) {
// Calling convention for IC call (from ic-arm.cc) // Calling convention for IC call (from ic-arm.cc)
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r2: name // -- r2 : name
// ----------------------------------- // -----------------------------------
Generate_DebugBreakCallHelper(masm, r2.bit()); Generate_DebugBreakCallHelper(masm, r2.bit(), 0);
} }
void Debug::GenerateConstructCallDebugBreak(MacroAssembler* masm) { void Debug::GenerateConstructCallDebugBreak(MacroAssembler* masm) {
// In places other than IC call sites it is expected that r0 is TOS which // Calling convention for construct call (from builtins-arm.cc)
// is an object - this is not generally the case so this should be used with // -- r0 : number of arguments (not smi)
// care. // -- r1 : constructor function
Generate_DebugBreakCallHelper(masm, r0.bit()); Generate_DebugBreakCallHelper(masm, r1.bit(), r0.bit());
} }
...@@ -243,7 +259,7 @@ void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) { ...@@ -243,7 +259,7 @@ void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) {
// In places other than IC call sites it is expected that r0 is TOS which // 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 // is an object - this is not generally the case so this should be used with
// care. // care.
Generate_DebugBreakCallHelper(masm, r0.bit()); Generate_DebugBreakCallHelper(masm, r0.bit(), 0);
} }
...@@ -251,7 +267,7 @@ void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) { ...@@ -251,7 +267,7 @@ void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// No registers used on entry. // No registers used on entry.
// ----------------------------------- // -----------------------------------
Generate_DebugBreakCallHelper(masm, 0); Generate_DebugBreakCallHelper(masm, 0, 0);
} }
...@@ -273,7 +289,7 @@ void Debug::GenerateSlot(MacroAssembler* masm) { ...@@ -273,7 +289,7 @@ void Debug::GenerateSlot(MacroAssembler* masm) {
void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) { void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) {
// In the places where a debug break slot is inserted no registers can contain // In the places where a debug break slot is inserted no registers can contain
// object pointers. // object pointers.
Generate_DebugBreakCallHelper(masm, 0); Generate_DebugBreakCallHelper(masm, 0, 0);
} }
......
...@@ -55,17 +55,13 @@ StackFrame::Type StackFrame::ComputeType(State* state) { ...@@ -55,17 +55,13 @@ StackFrame::Type StackFrame::ComputeType(State* state) {
StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) { StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
if (fp == 0) return NONE; if (fp == 0) return NONE;
// Compute frame type and stack pointer. // Compute frame type and stack pointer.
Address sp = fp + ExitFrameConstants::kSPDisplacement; Address sp = fp + ExitFrameConstants::kSPOffset;
const int offset = ExitFrameConstants::kCodeOffset;
Object* code = Memory::Object_at(fp + offset);
bool is_debug_exit = code->IsSmi();
if (is_debug_exit) {
sp -= kNumJSCallerSaved * kPointerSize;
}
// Fill in the state. // Fill in the state.
state->sp = sp; state->sp = sp;
state->fp = fp; state->fp = fp;
state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize); state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize);
ASSERT(*state->pc_address != NULL);
return EXIT; return EXIT;
} }
......
...@@ -96,11 +96,8 @@ class EntryFrameConstants : public AllStatic { ...@@ -96,11 +96,8 @@ class EntryFrameConstants : public AllStatic {
class ExitFrameConstants : public AllStatic { class ExitFrameConstants : public AllStatic {
public: public:
// Exit frames have a debug marker on the stack.
static const int kSPDisplacement = -1 * kPointerSize;
// The debug marker is just above the frame pointer.
static const int kCodeOffset = -1 * kPointerSize; static const int kCodeOffset = -1 * kPointerSize;
static const int kSPOffset = -1 * kPointerSize;
static const int kSavedRegistersOffset = 0 * kPointerSize; static const int kSavedRegistersOffset = 0 * kPointerSize;
......
...@@ -513,7 +513,7 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) { ...@@ -513,7 +513,7 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) {
} }
void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode) { void MacroAssembler::EnterExitFrame() {
// Compute the argv pointer and keep it in a callee-saved register. // Compute the argv pointer and keep it in a callee-saved register.
// r0 is argc. // r0 is argc.
add(r6, sp, Operand(r0, LSL, kPointerSizeLog2)); add(r6, sp, Operand(r0, LSL, kPointerSizeLog2));
...@@ -556,16 +556,6 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode) { ...@@ -556,16 +556,6 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode) {
// Setup argc and the builtin function in callee-saved registers. // Setup argc and the builtin function in callee-saved registers.
mov(r4, Operand(r0)); mov(r4, Operand(r0));
mov(r5, Operand(r1)); mov(r5, Operand(r1));
#ifdef ENABLE_DEBUGGER_SUPPORT
// Save the state of all registers to the stack from the memory
// location. This is needed to allow nested break points.
if (mode == ExitFrame::MODE_DEBUG) {
// Use sp as base to push.
CopyRegistersFromMemoryToStack(sp, kJSCallerSaved);
}
#endif
} }
...@@ -600,19 +590,7 @@ int MacroAssembler::ActivationFrameAlignment() { ...@@ -600,19 +590,7 @@ int MacroAssembler::ActivationFrameAlignment() {
} }
void MacroAssembler::LeaveExitFrame(ExitFrame::Mode mode) { void MacroAssembler::LeaveExitFrame() {
#ifdef ENABLE_DEBUGGER_SUPPORT
// Restore the memory copy of the registers by digging them out from
// the stack. This is needed to allow nested break points.
if (mode == ExitFrame::MODE_DEBUG) {
// This code intentionally clobbers r2 and r3.
const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize;
const int kOffset = ExitFrameConstants::kCodeOffset - kCallerSavedSize;
add(r3, fp, Operand(kOffset));
CopyRegistersFromStackToMemory(r3, r2, kJSCallerSaved);
}
#endif
// Clear top frame. // Clear top frame.
mov(r3, Operand(0)); mov(r3, Operand(0));
mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address))); mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
...@@ -779,66 +757,8 @@ void MacroAssembler::InvokeFunction(JSFunction* function, ...@@ -779,66 +757,8 @@ void MacroAssembler::InvokeFunction(JSFunction* function,
InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET, flag); InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET, flag);
} }
#ifdef ENABLE_DEBUGGER_SUPPORT
void MacroAssembler::SaveRegistersToMemory(RegList regs) {
ASSERT((regs & ~kJSCallerSaved) == 0);
// Copy the content of registers to memory location.
for (int i = 0; i < kNumJSCallerSaved; i++) {
int r = JSCallerSavedCode(i);
if ((regs & (1 << r)) != 0) {
Register reg = { r };
mov(ip, Operand(ExternalReference(Debug_Address::Register(i))));
str(reg, MemOperand(ip));
}
}
}
void MacroAssembler::RestoreRegistersFromMemory(RegList regs) {
ASSERT((regs & ~kJSCallerSaved) == 0);
// Copy the content of memory location to registers.
for (int i = kNumJSCallerSaved; --i >= 0;) {
int r = JSCallerSavedCode(i);
if ((regs & (1 << r)) != 0) {
Register reg = { r };
mov(ip, Operand(ExternalReference(Debug_Address::Register(i))));
ldr(reg, MemOperand(ip));
}
}
}
void MacroAssembler::CopyRegistersFromMemoryToStack(Register base,
RegList regs) {
ASSERT((regs & ~kJSCallerSaved) == 0);
// Copy the content of the memory location to the stack and adjust base.
for (int i = kNumJSCallerSaved; --i >= 0;) {
int r = JSCallerSavedCode(i);
if ((regs & (1 << r)) != 0) {
mov(ip, Operand(ExternalReference(Debug_Address::Register(i))));
ldr(ip, MemOperand(ip));
str(ip, MemOperand(base, 4, NegPreIndex));
}
}
}
void MacroAssembler::CopyRegistersFromStackToMemory(Register base,
Register scratch,
RegList regs) {
ASSERT((regs & ~kJSCallerSaved) == 0);
// Copy the content of the stack to the memory location and adjust base.
for (int i = 0; i < kNumJSCallerSaved; i++) {
int r = JSCallerSavedCode(i);
if ((regs & (1 << r)) != 0) {
mov(ip, Operand(ExternalReference(Debug_Address::Register(i))));
ldr(scratch, MemOperand(base, 4, PostIndex));
str(scratch, MemOperand(ip));
}
}
}
#ifdef ENABLE_DEBUGGER_SUPPORT
void MacroAssembler::DebugBreak() { void MacroAssembler::DebugBreak() {
ASSERT(allow_stub_calls()); ASSERT(allow_stub_calls());
mov(r0, Operand(0)); mov(r0, Operand(0));
......
...@@ -250,14 +250,14 @@ class MacroAssembler: public Assembler { ...@@ -250,14 +250,14 @@ class MacroAssembler: public Assembler {
void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); } void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); }
void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); } void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); }
// Enter specific kind of exit frame; either normal or debug mode. // Enter exit frame.
// Expects the number of arguments in register r0 and // Expects the number of arguments in register r0 and
// the builtin function to call in register r1. Exits with argc in // the builtin function to call in register r1. Exits with argc in
// r4, argv in r6, and and the builtin function to call in r5. // r4, argv in r6, and and the builtin function to call in r5.
void EnterExitFrame(ExitFrame::Mode mode); void EnterExitFrame();
// Leave the current exit frame. Expects the return value in r0. // Leave the current exit frame. Expects the return value in r0.
void LeaveExitFrame(ExitFrame::Mode mode); void LeaveExitFrame();
// Get the actual activation frame alignment for target environment. // Get the actual activation frame alignment for target environment.
static int ActivationFrameAlignment(); static int ActivationFrameAlignment();
...@@ -294,12 +294,6 @@ class MacroAssembler: public Assembler { ...@@ -294,12 +294,6 @@ class MacroAssembler: public Assembler {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Debugger Support // Debugger Support
void SaveRegistersToMemory(RegList regs);
void RestoreRegistersFromMemory(RegList regs);
void CopyRegistersFromMemoryToStack(Register base, RegList regs);
void CopyRegistersFromStackToMemory(Register base,
Register scratch,
RegList regs);
void DebugBreak(); void DebugBreak();
#endif #endif
......
...@@ -501,12 +501,11 @@ void ArgumentsAccessStub::Generate(MacroAssembler* masm) { ...@@ -501,12 +501,11 @@ void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
int CEntryStub::MinorKey() { int CEntryStub::MinorKey() {
ASSERT(result_size_ <= 2); ASSERT(result_size_ == 1 || result_size_ == 2);
#ifdef _WIN64 #ifdef _WIN64
return ExitFrameModeBits::encode(mode_) return result_size_ == 1 ? 0 : 1;
| IndirectResultBits::encode(result_size_ > 1);
#else #else
return ExitFrameModeBits::encode(mode_); return 0;
#endif #endif
} }
......
...@@ -560,9 +560,7 @@ class CompareStub: public CodeStub { ...@@ -560,9 +560,7 @@ class CompareStub: public CodeStub {
class CEntryStub : public CodeStub { class CEntryStub : public CodeStub {
public: public:
explicit CEntryStub(int result_size, explicit CEntryStub(int result_size) : result_size_(result_size) { }
ExitFrame::Mode mode = ExitFrame::MODE_NORMAL)
: result_size_(result_size), mode_(mode) { }
void Generate(MacroAssembler* masm); void Generate(MacroAssembler* masm);
...@@ -580,10 +578,8 @@ class CEntryStub : public CodeStub { ...@@ -580,10 +578,8 @@ class CEntryStub : public CodeStub {
// Number of pointers/values returned. // Number of pointers/values returned.
const int result_size_; const int result_size_;
const ExitFrame::Mode mode_;
// Minor key encoding // Minor key encoding
class ExitFrameModeBits: public BitField<ExitFrame::Mode, 0, 1> {};
class IndirectResultBits: public BitField<bool, 1, 1> {}; class IndirectResultBits: public BitField<bool, 1, 1> {};
Major MajorKey() { return CEntry; } Major MajorKey() { return CEntry; }
......
...@@ -332,8 +332,7 @@ class Debug { ...@@ -332,8 +332,7 @@ class Debug {
k_after_break_target_address, k_after_break_target_address,
k_debug_break_return_address, k_debug_break_return_address,
k_debug_break_slot_address, k_debug_break_slot_address,
k_restarter_frame_function_pointer, k_restarter_frame_function_pointer
k_register_address
}; };
// Support for setting the address to jump to when returning from break point. // Support for setting the address to jump to when returning from break point.
...@@ -953,10 +952,7 @@ class DisableBreak BASE_EMBEDDED { ...@@ -953,10 +952,7 @@ class DisableBreak BASE_EMBEDDED {
// code. // code.
class Debug_Address { class Debug_Address {
public: public:
Debug_Address(Debug::AddressId id, int reg = 0) Debug_Address(Debug::AddressId id) : id_(id) { }
: id_(id), reg_(reg) {
ASSERT(reg == 0 || id == Debug::k_register_address);
}
static Debug_Address AfterBreakTarget() { static Debug_Address AfterBreakTarget() {
return Debug_Address(Debug::k_after_break_target_address); return Debug_Address(Debug::k_after_break_target_address);
...@@ -970,10 +966,6 @@ class Debug_Address { ...@@ -970,10 +966,6 @@ class Debug_Address {
return Debug_Address(Debug::k_restarter_frame_function_pointer); return Debug_Address(Debug::k_restarter_frame_function_pointer);
} }
static Debug_Address Register(int reg) {
return Debug_Address(Debug::k_register_address, reg);
}
Address address() const { Address address() const {
switch (id_) { switch (id_) {
case Debug::k_after_break_target_address: case Debug::k_after_break_target_address:
...@@ -985,8 +977,6 @@ class Debug_Address { ...@@ -985,8 +977,6 @@ class Debug_Address {
case Debug::k_restarter_frame_function_pointer: case Debug::k_restarter_frame_function_pointer:
return reinterpret_cast<Address>( return reinterpret_cast<Address>(
Debug::restarter_frame_function_pointer_address()); Debug::restarter_frame_function_pointer_address());
case Debug::k_register_address:
return reinterpret_cast<Address>(Debug::register_address(reg_));
default: default:
UNREACHABLE(); UNREACHABLE();
return NULL; return NULL;
...@@ -994,7 +984,6 @@ class Debug_Address { ...@@ -994,7 +984,6 @@ class Debug_Address {
} }
private: private:
Debug::AddressId id_; Debug::AddressId id_;
int reg_;
}; };
// The optional thread that Debug Agent may use to temporary call V8 to process // The optional thread that Debug Agent may use to temporary call V8 to process
......
...@@ -280,7 +280,6 @@ class EntryConstructFrame: public EntryFrame { ...@@ -280,7 +280,6 @@ class EntryConstructFrame: public EntryFrame {
// Exit frames are used to exit JavaScript execution and go to C. // Exit frames are used to exit JavaScript execution and go to C.
class ExitFrame: public StackFrame { class ExitFrame: public StackFrame {
public: public:
enum Mode { MODE_NORMAL, MODE_DEBUG };
virtual Type type() const { return EXIT; } virtual Type type() const { return EXIT; }
virtual Code* unchecked_code() const; virtual Code* unchecked_code() const;
......
...@@ -3054,7 +3054,7 @@ void ApiGetterEntryStub::Generate(MacroAssembler* masm) { ...@@ -3054,7 +3054,7 @@ void ApiGetterEntryStub::Generate(MacroAssembler* masm) {
Label empty_handle; Label empty_handle;
Label prologue; Label prologue;
Label promote_scheduled_exception; Label promote_scheduled_exception;
__ EnterApiExitFrame(ExitFrame::MODE_NORMAL, kStackSpace, kArgc); __ EnterApiExitFrame(kStackSpace, kArgc);
STATIC_ASSERT(kArgc == 4); STATIC_ASSERT(kArgc == 4);
if (kPassHandlesDirectly) { if (kPassHandlesDirectly) {
// When handles as passed directly we don't have to allocate extra // When handles as passed directly we don't have to allocate extra
...@@ -3100,7 +3100,7 @@ void ApiGetterEntryStub::Generate(MacroAssembler* masm) { ...@@ -3100,7 +3100,7 @@ void ApiGetterEntryStub::Generate(MacroAssembler* masm) {
// It was non-zero. Dereference to get the result value. // It was non-zero. Dereference to get the result value.
__ mov(eax, Operand(eax, 0)); __ mov(eax, Operand(eax, 0));
__ bind(&prologue); __ bind(&prologue);
__ LeaveExitFrame(ExitFrame::MODE_NORMAL); __ LeaveExitFrame();
__ ret(0); __ ret(0);
__ bind(&promote_scheduled_exception); __ bind(&promote_scheduled_exception);
__ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1); __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
...@@ -3177,7 +3177,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, ...@@ -3177,7 +3177,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
__ j(zero, &failure_returned, not_taken); __ j(zero, &failure_returned, not_taken);
// Exit the JavaScript to C++ exit frame. // Exit the JavaScript to C++ exit frame.
__ LeaveExitFrame(mode_); __ LeaveExitFrame();
__ ret(0); __ ret(0);
// Handling of failure. // Handling of failure.
...@@ -3277,7 +3277,7 @@ void CEntryStub::Generate(MacroAssembler* masm) { ...@@ -3277,7 +3277,7 @@ void CEntryStub::Generate(MacroAssembler* masm) {
// a garbage collection and retrying the builtin (twice). // a garbage collection and retrying the builtin (twice).
// Enter the exit frame that transitions from JavaScript to C++. // Enter the exit frame that transitions from JavaScript to C++.
__ EnterExitFrame(mode_); __ EnterExitFrame();
// eax: result parameter for PerformGC, if any (setup below) // eax: result parameter for PerformGC, if any (setup below)
// ebx: pointer to builtin function (C callee-saved) // ebx: pointer to builtin function (C callee-saved)
......
...@@ -94,22 +94,33 @@ void BreakLocationIterator::ClearDebugBreakAtSlot() { ...@@ -94,22 +94,33 @@ void BreakLocationIterator::ClearDebugBreakAtSlot() {
static void Generate_DebugBreakCallHelper(MacroAssembler* masm, static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
RegList pointer_regs, RegList object_regs,
RegList non_object_regs,
bool convert_call_to_jmp) { bool convert_call_to_jmp) {
// Save the content of all general purpose registers in memory. This copy in
// memory is later pushed onto the JS expression stack for the fake JS frame
// generated and also to the C frame generated on top of that. In the JS
// frame ONLY the registers containing pointers will be pushed on the
// expression stack. This causes the GC to update these pointers so that
// they will have the correct value when returning from the debugger.
__ SaveRegistersToMemory(kJSCallerSaved);
// Enter an internal frame. // Enter an internal frame.
__ EnterInternalFrame(); __ EnterInternalFrame();
// Store the registers containing object pointers on the expression stack to // Store the registers containing live values on the expression stack to
// make sure that these are correctly updated during GC. // make sure that these are correctly updated during GC. Non object values
__ PushRegistersFromMemory(pointer_regs); // are stored as a smi causing it to be untouched by GC.
ASSERT((object_regs & ~kJSCallerSaved) == 0);
ASSERT((non_object_regs & ~kJSCallerSaved) == 0);
ASSERT((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, "Unable to encode value as smi");
}
__ SmiTag(reg);
__ push(reg);
}
}
#ifdef DEBUG #ifdef DEBUG
__ RecordComment("// Calling from debug break to runtime - come in - over"); __ RecordComment("// Calling from debug break to runtime - come in - over");
...@@ -117,12 +128,25 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, ...@@ -117,12 +128,25 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
__ Set(eax, Immediate(0)); // no arguments __ Set(eax, Immediate(0)); // no arguments
__ mov(ebx, Immediate(ExternalReference::debug_break())); __ mov(ebx, Immediate(ExternalReference::debug_break()));
CEntryStub ceb(1, ExitFrame::MODE_DEBUG); CEntryStub ceb(1);
__ CallStub(&ceb); __ CallStub(&ceb);
// Restore the register values containing object pointers from the expression // Restore the register values containing object pointers from the expression
// stack in the reverse order as they where pushed. // stack.
__ PopRegistersToMemory(pointer_regs); for (int i = kNumJSCallerSaved; --i >= 0;) {
int r = JSCallerSavedCode(i);
Register reg = { r };
if (FLAG_debug_code) {
__ Set(reg, Immediate(kDebugZapValue));
}
if ((object_regs & (1 << r)) != 0) {
__ pop(reg);
}
if ((non_object_regs & (1 << r)) != 0) {
__ pop(reg);
__ SmiUntag(reg);
}
}
// Get rid of the internal frame. // Get rid of the internal frame.
__ LeaveInternalFrame(); __ LeaveInternalFrame();
...@@ -130,12 +154,9 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, ...@@ -130,12 +154,9 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
// If this call did not replace a call but patched other code then there will // 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. // be an unwanted return address left on the stack. Here we get rid of that.
if (convert_call_to_jmp) { if (convert_call_to_jmp) {
__ pop(eax); __ add(Operand(esp), Immediate(kPointerSize));
} }
// Finally restore all registers.
__ RestoreRegistersFromMemory(kJSCallerSaved);
// Now that the break point has been handled, resume normal execution by // Now that the break point has been handled, resume normal execution by
// jumping to the target address intended by the caller and that was // jumping to the target address intended by the caller and that was
// overwritten by the address of DebugBreakXXX. // overwritten by the address of DebugBreakXXX.
...@@ -151,7 +172,7 @@ void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) { ...@@ -151,7 +172,7 @@ void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
// -- eax : receiver // -- eax : receiver
// -- ecx : name // -- ecx : name
// ----------------------------------- // -----------------------------------
Generate_DebugBreakCallHelper(masm, eax.bit() | ecx.bit(), false); Generate_DebugBreakCallHelper(masm, eax.bit() | ecx.bit(), 0, false);
} }
...@@ -162,7 +183,8 @@ void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) { ...@@ -162,7 +183,8 @@ void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) {
// -- ecx : name // -- ecx : name
// -- edx : receiver // -- edx : receiver
// ----------------------------------- // -----------------------------------
Generate_DebugBreakCallHelper(masm, eax.bit() | ecx.bit() | edx.bit(), false); Generate_DebugBreakCallHelper(
masm, eax.bit() | ecx.bit() | edx.bit(), 0, false);
} }
...@@ -172,7 +194,7 @@ void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) { ...@@ -172,7 +194,7 @@ void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
// -- edx : receiver // -- edx : receiver
// -- eax : key // -- eax : key
// ----------------------------------- // -----------------------------------
Generate_DebugBreakCallHelper(masm, eax.bit() | edx.bit(), false); Generate_DebugBreakCallHelper(masm, eax.bit() | edx.bit(), 0, false);
} }
...@@ -183,7 +205,8 @@ void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) { ...@@ -183,7 +205,8 @@ void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
// -- ecx : key // -- ecx : key
// -- edx : receiver // -- edx : receiver
// ----------------------------------- // -----------------------------------
Generate_DebugBreakCallHelper(masm, eax.bit() | ecx.bit() | edx.bit(), false); Generate_DebugBreakCallHelper(
masm, eax.bit() | ecx.bit() | edx.bit(), 0, false);
} }
...@@ -192,7 +215,7 @@ void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) { ...@@ -192,7 +215,7 @@ void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- ecx: name // -- ecx: name
// ----------------------------------- // -----------------------------------
Generate_DebugBreakCallHelper(masm, ecx.bit(), false); Generate_DebugBreakCallHelper(masm, ecx.bit(), 0, false);
} }
...@@ -201,10 +224,11 @@ void Debug::GenerateConstructCallDebugBreak(MacroAssembler* masm) { ...@@ -201,10 +224,11 @@ void Debug::GenerateConstructCallDebugBreak(MacroAssembler* masm) {
// eax is the actual number of arguments not encoded as a smi see comment // eax is the actual number of arguments not encoded as a smi see comment
// above IC call. // above IC call.
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- eax: number of arguments // -- eax: number of arguments (not smi)
// -- edi: constructor function
// ----------------------------------- // -----------------------------------
// The number of arguments in eax is not smi encoded. // The number of arguments in eax is not smi encoded.
Generate_DebugBreakCallHelper(masm, 0, false); Generate_DebugBreakCallHelper(masm, edi.bit(), eax.bit(), false);
} }
...@@ -213,7 +237,7 @@ void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) { ...@@ -213,7 +237,7 @@ void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- eax: return value // -- eax: return value
// ----------------------------------- // -----------------------------------
Generate_DebugBreakCallHelper(masm, eax.bit(), true); Generate_DebugBreakCallHelper(masm, eax.bit(), 0, true);
} }
...@@ -222,7 +246,7 @@ void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) { ...@@ -222,7 +246,7 @@ void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// No registers used on entry. // No registers used on entry.
// ----------------------------------- // -----------------------------------
Generate_DebugBreakCallHelper(masm, 0, false); Generate_DebugBreakCallHelper(masm, 0, 0, false);
} }
...@@ -242,7 +266,7 @@ void Debug::GenerateSlot(MacroAssembler* masm) { ...@@ -242,7 +266,7 @@ void Debug::GenerateSlot(MacroAssembler* masm) {
void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) { void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) {
// In the places where a debug break slot is inserted no registers can contain // In the places where a debug break slot is inserted no registers can contain
// object pointers. // object pointers.
Generate_DebugBreakCallHelper(masm, 0, true); Generate_DebugBreakCallHelper(masm, 0, 0, true);
} }
......
...@@ -58,6 +58,7 @@ StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) { ...@@ -58,6 +58,7 @@ StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
state->fp = fp; state->fp = fp;
state->sp = sp; state->sp = sp;
state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize); state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize);
ASSERT(*state->pc_address != NULL);
return EXIT; return EXIT;
} }
......
...@@ -191,81 +191,6 @@ void MacroAssembler::StackLimitCheck(Label* on_stack_overflow) { ...@@ -191,81 +191,6 @@ void MacroAssembler::StackLimitCheck(Label* on_stack_overflow) {
#ifdef ENABLE_DEBUGGER_SUPPORT #ifdef ENABLE_DEBUGGER_SUPPORT
void MacroAssembler::SaveRegistersToMemory(RegList regs) {
ASSERT((regs & ~kJSCallerSaved) == 0);
// Copy the content of registers to memory location.
for (int i = 0; i < kNumJSCallerSaved; i++) {
int r = JSCallerSavedCode(i);
if ((regs & (1 << r)) != 0) {
Register reg = { r };
ExternalReference reg_addr =
ExternalReference(Debug_Address::Register(i));
mov(Operand::StaticVariable(reg_addr), reg);
}
}
}
void MacroAssembler::RestoreRegistersFromMemory(RegList regs) {
ASSERT((regs & ~kJSCallerSaved) == 0);
// Copy the content of memory location to registers.
for (int i = kNumJSCallerSaved; --i >= 0;) {
int r = JSCallerSavedCode(i);
if ((regs & (1 << r)) != 0) {
Register reg = { r };
ExternalReference reg_addr =
ExternalReference(Debug_Address::Register(i));
mov(reg, Operand::StaticVariable(reg_addr));
}
}
}
void MacroAssembler::PushRegistersFromMemory(RegList regs) {
ASSERT((regs & ~kJSCallerSaved) == 0);
// Push the content of the memory location to the stack.
for (int i = 0; i < kNumJSCallerSaved; i++) {
int r = JSCallerSavedCode(i);
if ((regs & (1 << r)) != 0) {
ExternalReference reg_addr =
ExternalReference(Debug_Address::Register(i));
push(Operand::StaticVariable(reg_addr));
}
}
}
void MacroAssembler::PopRegistersToMemory(RegList regs) {
ASSERT((regs & ~kJSCallerSaved) == 0);
// Pop the content from the stack to the memory location.
for (int i = kNumJSCallerSaved; --i >= 0;) {
int r = JSCallerSavedCode(i);
if ((regs & (1 << r)) != 0) {
ExternalReference reg_addr =
ExternalReference(Debug_Address::Register(i));
pop(Operand::StaticVariable(reg_addr));
}
}
}
void MacroAssembler::CopyRegistersFromStackToMemory(Register base,
Register scratch,
RegList regs) {
ASSERT((regs & ~kJSCallerSaved) == 0);
// Copy the content of the stack to the memory location and adjust base.
for (int i = kNumJSCallerSaved; --i >= 0;) {
int r = JSCallerSavedCode(i);
if ((regs & (1 << r)) != 0) {
mov(scratch, Operand(base, 0));
ExternalReference reg_addr =
ExternalReference(Debug_Address::Register(i));
mov(Operand::StaticVariable(reg_addr), scratch);
lea(base, Operand(base, kPointerSize));
}
}
}
void MacroAssembler::DebugBreak() { void MacroAssembler::DebugBreak() {
Set(eax, Immediate(0)); Set(eax, Immediate(0));
mov(ebx, Immediate(ExternalReference(Runtime::kDebugBreak))); mov(ebx, Immediate(ExternalReference(Runtime::kDebugBreak)));
...@@ -274,6 +199,7 @@ void MacroAssembler::DebugBreak() { ...@@ -274,6 +199,7 @@ void MacroAssembler::DebugBreak() {
} }
#endif #endif
void MacroAssembler::Set(Register dst, const Immediate& x) { void MacroAssembler::Set(Register dst, const Immediate& x) {
if (x.is_zero()) { if (x.is_zero()) {
xor_(dst, Operand(dst)); // shorter than mov xor_(dst, Operand(dst)); // shorter than mov
...@@ -405,7 +331,8 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) { ...@@ -405,7 +331,8 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) {
leave(); leave();
} }
void MacroAssembler::EnterExitFramePrologue(ExitFrame::Mode mode) {
void MacroAssembler::EnterExitFramePrologue() {
// Setup the frame structure on the stack. // Setup the frame structure on the stack.
ASSERT(ExitFrameConstants::kCallerSPDisplacement == +2 * kPointerSize); ASSERT(ExitFrameConstants::kCallerSPDisplacement == +2 * kPointerSize);
ASSERT(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize); ASSERT(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize);
...@@ -413,7 +340,7 @@ void MacroAssembler::EnterExitFramePrologue(ExitFrame::Mode mode) { ...@@ -413,7 +340,7 @@ void MacroAssembler::EnterExitFramePrologue(ExitFrame::Mode mode) {
push(ebp); push(ebp);
mov(ebp, Operand(esp)); mov(ebp, Operand(esp));
// Reserve room for entry stack pointer and push the debug marker. // Reserve room for entry stack pointer and push the code object.
ASSERT(ExitFrameConstants::kSPOffset == -1 * kPointerSize); ASSERT(ExitFrameConstants::kSPOffset == -1 * kPointerSize);
push(Immediate(0)); // Saved entry sp, patched before call. push(Immediate(0)); // Saved entry sp, patched before call.
push(Immediate(CodeObject())); // Accessed from ExitFrame::code_slot. push(Immediate(CodeObject())); // Accessed from ExitFrame::code_slot.
...@@ -425,21 +352,8 @@ void MacroAssembler::EnterExitFramePrologue(ExitFrame::Mode mode) { ...@@ -425,21 +352,8 @@ void MacroAssembler::EnterExitFramePrologue(ExitFrame::Mode mode) {
mov(Operand::StaticVariable(context_address), esi); mov(Operand::StaticVariable(context_address), esi);
} }
void MacroAssembler::EnterExitFrameEpilogue(ExitFrame::Mode mode, int argc) {
#ifdef ENABLE_DEBUGGER_SUPPORT
// Save the state of all registers to the stack from the memory
// location. This is needed to allow nested break points.
if (mode == ExitFrame::MODE_DEBUG) {
// TODO(1243899): This should be symmetric to
// CopyRegistersFromStackToMemory() but it isn't! esp is assumed
// correct here, but computed for the other call. Very error
// prone! FIX THIS. Actually there are deeper problems with
// register saving than this asymmetry (see the bug report
// associated with this issue).
PushRegistersFromMemory(kJSCallerSaved);
}
#endif
void MacroAssembler::EnterExitFrameEpilogue(int argc) {
// Reserve space for arguments. // Reserve space for arguments.
sub(Operand(esp), Immediate(argc * kPointerSize)); sub(Operand(esp), Immediate(argc * kPointerSize));
...@@ -455,44 +369,30 @@ void MacroAssembler::EnterExitFrameEpilogue(ExitFrame::Mode mode, int argc) { ...@@ -455,44 +369,30 @@ void MacroAssembler::EnterExitFrameEpilogue(ExitFrame::Mode mode, int argc) {
} }
void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode) { void MacroAssembler::EnterExitFrame() {
EnterExitFramePrologue(mode); EnterExitFramePrologue();
// Setup argc and argv in callee-saved registers. // Setup argc and argv in callee-saved registers.
int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
mov(edi, Operand(eax)); mov(edi, Operand(eax));
lea(esi, Operand(ebp, eax, times_4, offset)); lea(esi, Operand(ebp, eax, times_4, offset));
EnterExitFrameEpilogue(mode, 2); EnterExitFrameEpilogue(2);
} }
void MacroAssembler::EnterApiExitFrame(ExitFrame::Mode mode, void MacroAssembler::EnterApiExitFrame(int stack_space,
int stack_space,
int argc) { int argc) {
EnterExitFramePrologue(mode); EnterExitFramePrologue();
int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
lea(esi, Operand(ebp, (stack_space * kPointerSize) + offset)); lea(esi, Operand(ebp, (stack_space * kPointerSize) + offset));
EnterExitFrameEpilogue(mode, argc); EnterExitFrameEpilogue(argc);
} }
void MacroAssembler::LeaveExitFrame(ExitFrame::Mode mode) { void MacroAssembler::LeaveExitFrame() {
#ifdef ENABLE_DEBUGGER_SUPPORT
// Restore the memory copy of the registers by digging them out from
// the stack. This is needed to allow nested break points.
if (mode == ExitFrame::MODE_DEBUG) {
// It's okay to clobber register ebx below because we don't need
// the function pointer after this.
const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize;
int kOffset = ExitFrameConstants::kCodeOffset - kCallerSavedSize;
lea(ebx, Operand(ebp, kOffset));
CopyRegistersFromStackToMemory(ebx, ecx, kJSCallerSaved);
}
#endif
// Get the return address from the stack and restore the frame pointer. // Get the return address from the stack and restore the frame pointer.
mov(ecx, Operand(ebp, 1 * kPointerSize)); mov(ecx, Operand(ebp, 1 * kPointerSize));
mov(ebp, Operand(ebp, 0 * kPointerSize)); mov(ebp, Operand(ebp, 0 * kPointerSize));
......
...@@ -99,13 +99,6 @@ class MacroAssembler: public Assembler { ...@@ -99,13 +99,6 @@ class MacroAssembler: public Assembler {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Debugger Support // Debugger Support
void SaveRegistersToMemory(RegList regs);
void RestoreRegistersFromMemory(RegList regs);
void PushRegistersFromMemory(RegList regs);
void PopRegistersToMemory(RegList regs);
void CopyRegistersFromStackToMemory(Register base,
Register scratch,
RegList regs);
void DebugBreak(); void DebugBreak();
#endif #endif
...@@ -128,14 +121,14 @@ class MacroAssembler: public Assembler { ...@@ -128,14 +121,14 @@ class MacroAssembler: public Assembler {
// Expects the number of arguments in register eax and // Expects the number of arguments in register eax and
// sets up the number of arguments in register edi and the pointer // sets up the number of arguments in register edi and the pointer
// to the first argument in register esi. // to the first argument in register esi.
void EnterExitFrame(ExitFrame::Mode mode); void EnterExitFrame();
void EnterApiExitFrame(ExitFrame::Mode mode, int stack_space, int argc); void EnterApiExitFrame(int stack_space, int argc);
// Leave the current exit frame. Expects the return value in // Leave the current exit frame. Expects the return value in
// register eax:edx (untouched) and the pointer to the first // register eax:edx (untouched) and the pointer to the first
// argument in register esi. // argument in register esi.
void LeaveExitFrame(ExitFrame::Mode mode); void LeaveExitFrame();
// Find the function context up the context chain. // Find the function context up the context chain.
void LoadContext(Register dst, int context_chain_length); void LoadContext(Register dst, int context_chain_length);
...@@ -571,8 +564,8 @@ class MacroAssembler: public Assembler { ...@@ -571,8 +564,8 @@ class MacroAssembler: public Assembler {
void EnterFrame(StackFrame::Type type); void EnterFrame(StackFrame::Type type);
void LeaveFrame(StackFrame::Type type); void LeaveFrame(StackFrame::Type type);
void EnterExitFramePrologue(ExitFrame::Mode mode); void EnterExitFramePrologue();
void EnterExitFrameEpilogue(ExitFrame::Mode mode, int argc); void EnterExitFrameEpilogue(int argc);
// Allocation support helpers. // Allocation support helpers.
void LoadAllocationTopHelper(Register result, void LoadAllocationTopHelper(Register result,
......
...@@ -241,16 +241,6 @@ void ExternalReferenceTable::PopulateTable() { ...@@ -241,16 +241,6 @@ void ExternalReferenceTable::PopulateTable() {
DEBUG_ADDRESS, DEBUG_ADDRESS,
Debug::k_restarter_frame_function_pointer << kDebugIdShift, Debug::k_restarter_frame_function_pointer << kDebugIdShift,
"Debug::restarter_frame_function_pointer_address()"); "Debug::restarter_frame_function_pointer_address()");
const char* debug_register_format = "Debug::register_address(%i)";
int dr_format_length = StrLength(debug_register_format);
for (int i = 0; i < kNumJSCallerSaved; ++i) {
Vector<char> name = Vector<char>::New(dr_format_length + 1);
OS::SNPrintF(name, debug_register_format, i);
Add(Debug_Address(Debug::k_register_address, i).address(),
DEBUG_ADDRESS,
Debug::k_register_address << kDebugIdShift | i,
name.start());
}
#endif #endif
// Stat counters // Stat counters
......
...@@ -2476,7 +2476,7 @@ void ApiGetterEntryStub::Generate(MacroAssembler* masm) { ...@@ -2476,7 +2476,7 @@ void ApiGetterEntryStub::Generate(MacroAssembler* masm) {
Label empty_result; Label empty_result;
Label prologue; Label prologue;
Label promote_scheduled_exception; Label promote_scheduled_exception;
__ EnterApiExitFrame(ExitFrame::MODE_NORMAL, kStackSpace, 0); __ EnterApiExitFrame(kStackSpace, 0);
ASSERT_EQ(kArgc, 4); ASSERT_EQ(kArgc, 4);
#ifdef _WIN64 #ifdef _WIN64
// All the parameters should be set up by a caller. // All the parameters should be set up by a caller.
...@@ -2507,7 +2507,7 @@ void ApiGetterEntryStub::Generate(MacroAssembler* masm) { ...@@ -2507,7 +2507,7 @@ void ApiGetterEntryStub::Generate(MacroAssembler* masm) {
// It was non-zero. Dereference to get the result value. // It was non-zero. Dereference to get the result value.
__ movq(rax, Operand(rax, 0)); __ movq(rax, Operand(rax, 0));
__ bind(&prologue); __ bind(&prologue);
__ LeaveExitFrame(ExitFrame::MODE_NORMAL); __ LeaveExitFrame();
__ ret(0); __ ret(0);
__ bind(&promote_scheduled_exception); __ bind(&promote_scheduled_exception);
__ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1); __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
...@@ -2617,7 +2617,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, ...@@ -2617,7 +2617,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
__ j(zero, &failure_returned); __ j(zero, &failure_returned);
// Exit the JavaScript to C++ exit frame. // Exit the JavaScript to C++ exit frame.
__ LeaveExitFrame(mode_, result_size_); __ LeaveExitFrame(result_size_);
__ ret(0); __ ret(0);
// Handling of failure. // Handling of failure.
...@@ -2721,7 +2721,7 @@ void CEntryStub::Generate(MacroAssembler* masm) { ...@@ -2721,7 +2721,7 @@ void CEntryStub::Generate(MacroAssembler* masm) {
// builtin once. // builtin once.
// Enter the exit frame that transitions from JavaScript to C++. // Enter the exit frame that transitions from JavaScript to C++.
__ EnterExitFrame(mode_, result_size_); __ EnterExitFrame(result_size_);
// rax: Holds the context at this point, but should not be used. // rax: Holds the context at this point, but should not be used.
// On entry to code generated by GenerateCore, it must hold // On entry to code generated by GenerateCore, it must hold
......
...@@ -47,22 +47,35 @@ bool Debug::IsDebugBreakAtReturn(v8::internal::RelocInfo* rinfo) { ...@@ -47,22 +47,35 @@ bool Debug::IsDebugBreakAtReturn(v8::internal::RelocInfo* rinfo) {
#define __ ACCESS_MASM(masm) #define __ ACCESS_MASM(masm)
static void Generate_DebugBreakCallHelper(MacroAssembler* masm, static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
RegList pointer_regs, RegList object_regs,
RegList non_object_regs,
bool convert_call_to_jmp) { bool convert_call_to_jmp) {
// Save the content of all general purpose registers in memory. This copy in
// memory is later pushed onto the JS expression stack for the fake JS frame
// generated and also to the C frame generated on top of that. In the JS
// frame ONLY the registers containing pointers will be pushed on the
// expression stack. This causes the GC to update these pointers so that
// they will have the correct value when returning from the debugger.
__ SaveRegistersToMemory(kJSCallerSaved);
// Enter an internal frame. // Enter an internal frame.
__ EnterInternalFrame(); __ EnterInternalFrame();
// Store the registers containing object pointers on the expression stack to // Store the registers containing live values on the expression stack to
// make sure that these are correctly updated during GC. // make sure that these are correctly updated during GC. Non object values
__ PushRegistersFromMemory(pointer_regs); // are stored as as two smi causing it to be untouched by GC.
ASSERT((object_regs & ~kJSCallerSaved) == 0);
ASSERT((non_object_regs & ~kJSCallerSaved) == 0);
ASSERT((object_regs & non_object_regs) == 0);
for (int i = 0; i < kNumJSCallerSaved; i++) {
int r = JSCallerSavedCode(i);
Register reg = { r };
ASSERT(!reg.is(kScratchRegister));
if ((object_regs & (1 << r)) != 0) {
__ push(reg);
}
// Store the 64-bit value as two smis.
if ((non_object_regs & (1 << r)) != 0) {
__ movq(kScratchRegister, reg);
__ Integer32ToSmi(reg, reg);
__ push(reg);
__ sar(kScratchRegister, Immediate(32));
__ Integer32ToSmi(kScratchRegister, kScratchRegister);
__ push(kScratchRegister);
}
}
#ifdef DEBUG #ifdef DEBUG
__ RecordComment("// Calling from debug break to runtime - come in - over"); __ RecordComment("// Calling from debug break to runtime - come in - over");
...@@ -70,12 +83,29 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, ...@@ -70,12 +83,29 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
__ xor_(rax, rax); // No arguments (argc == 0). __ xor_(rax, rax); // No arguments (argc == 0).
__ movq(rbx, ExternalReference::debug_break()); __ movq(rbx, ExternalReference::debug_break());
CEntryStub ceb(1, ExitFrame::MODE_DEBUG); CEntryStub ceb(1);
__ CallStub(&ceb); __ CallStub(&ceb);
// Restore the register values containing object pointers from the expression // Restore the register values from the expression stack.
// stack in the reverse order as they where pushed. for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
__ PopRegistersToMemory(pointer_regs); int r = JSCallerSavedCode(i);
Register reg = { r };
if (FLAG_debug_code) {
__ Set(reg, kDebugZapValue);
}
if ((object_regs & (1 << r)) != 0) {
__ pop(reg);
}
// Reconstruct the 64-bit value from two smis.
if ((non_object_regs & (1 << r)) != 0) {
__ pop(kScratchRegister);
__ SmiToInteger32(kScratchRegister, kScratchRegister);
__ shl(kScratchRegister, Immediate(32));
__ pop(reg);
__ SmiToInteger32(reg, reg);
__ or_(reg, kScratchRegister);
}
}
// Get rid of the internal frame. // Get rid of the internal frame.
__ LeaveInternalFrame(); __ LeaveInternalFrame();
...@@ -83,12 +113,9 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, ...@@ -83,12 +113,9 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
// If this call did not replace a call but patched other code then there will // 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. // be an unwanted return address left on the stack. Here we get rid of that.
if (convert_call_to_jmp) { if (convert_call_to_jmp) {
__ pop(rax); __ addq(rsp, Immediate(kPointerSize));
} }
// Finally restore all registers.
__ RestoreRegistersFromMemory(kJSCallerSaved);
// Now that the break point has been handled, resume normal execution by // Now that the break point has been handled, resume normal execution by
// jumping to the target address intended by the caller and that was // jumping to the target address intended by the caller and that was
// overwritten by the address of DebugBreakXXX. // overwritten by the address of DebugBreakXXX.
...@@ -104,7 +131,7 @@ void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) { ...@@ -104,7 +131,7 @@ void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- rcx: function name // -- rcx: function name
// ----------------------------------- // -----------------------------------
Generate_DebugBreakCallHelper(masm, rcx.bit(), false); Generate_DebugBreakCallHelper(masm, rcx.bit(), 0, false);
} }
...@@ -116,7 +143,7 @@ void Debug::GenerateConstructCallDebugBreak(MacroAssembler* masm) { ...@@ -116,7 +143,7 @@ void Debug::GenerateConstructCallDebugBreak(MacroAssembler* masm) {
// -- rax: number of arguments // -- rax: number of arguments
// ----------------------------------- // -----------------------------------
// The number of arguments in rax is not smi encoded. // The number of arguments in rax is not smi encoded.
Generate_DebugBreakCallHelper(masm, 0, false); Generate_DebugBreakCallHelper(masm, rdi.bit(), rax.bit(), false);
} }
...@@ -126,7 +153,7 @@ void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) { ...@@ -126,7 +153,7 @@ void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
// -- rax : key // -- rax : key
// -- rdx : receiver // -- rdx : receiver
// ----------------------------------- // -----------------------------------
Generate_DebugBreakCallHelper(masm, rax.bit() | rdx.bit(), false); Generate_DebugBreakCallHelper(masm, rax.bit() | rdx.bit(), 0, false);
} }
...@@ -137,7 +164,8 @@ void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) { ...@@ -137,7 +164,8 @@ void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
// -- rcx : key // -- rcx : key
// -- rdx : receiver // -- rdx : receiver
// ----------------------------------- // -----------------------------------
Generate_DebugBreakCallHelper(masm, rax.bit() | rcx.bit() | rdx.bit(), false); Generate_DebugBreakCallHelper(
masm, rax.bit() | rcx.bit() | rdx.bit(), 0, false);
} }
...@@ -147,7 +175,7 @@ void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) { ...@@ -147,7 +175,7 @@ void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
// -- rax : receiver // -- rax : receiver
// -- rcx : name // -- rcx : name
// ----------------------------------- // -----------------------------------
Generate_DebugBreakCallHelper(masm, rax.bit() | rcx.bit(), false); Generate_DebugBreakCallHelper(masm, rax.bit() | rcx.bit(), 0, false);
} }
...@@ -156,7 +184,7 @@ void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) { ...@@ -156,7 +184,7 @@ void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- rax: return value // -- rax: return value
// ----------------------------------- // -----------------------------------
Generate_DebugBreakCallHelper(masm, rax.bit(), true); Generate_DebugBreakCallHelper(masm, rax.bit(), 0, true);
} }
...@@ -167,7 +195,8 @@ void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) { ...@@ -167,7 +195,8 @@ void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) {
// -- rcx : name // -- rcx : name
// -- rdx : receiver // -- rdx : receiver
// ----------------------------------- // -----------------------------------
Generate_DebugBreakCallHelper(masm, rax.bit() | rcx.bit() | rdx.bit(), false); Generate_DebugBreakCallHelper(
masm, rax.bit() | rcx.bit() | rdx.bit(), 0, false);
} }
...@@ -176,7 +205,7 @@ void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) { ...@@ -176,7 +205,7 @@ void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// No registers used on entry. // No registers used on entry.
// ----------------------------------- // -----------------------------------
Generate_DebugBreakCallHelper(masm, 0, false); Generate_DebugBreakCallHelper(masm, 0, 0, false);
} }
...@@ -196,7 +225,7 @@ void Debug::GenerateSlot(MacroAssembler* masm) { ...@@ -196,7 +225,7 @@ void Debug::GenerateSlot(MacroAssembler* masm) {
void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) { void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) {
// In the places where a debug break slot is inserted no registers can contain // In the places where a debug break slot is inserted no registers can contain
// object pointers. // object pointers.
Generate_DebugBreakCallHelper(masm, 0, true); Generate_DebugBreakCallHelper(masm, 0, 0, true);
} }
......
...@@ -58,7 +58,7 @@ StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) { ...@@ -58,7 +58,7 @@ StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
state->fp = fp; state->fp = fp;
state->sp = sp; state->sp = sp;
state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize); state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize);
// Determine frame type. ASSERT(*state->pc_address != NULL);
return EXIT; return EXIT;
} }
......
...@@ -2102,91 +2102,8 @@ void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) { ...@@ -2102,91 +2102,8 @@ void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) {
} }
} }
#ifdef ENABLE_DEBUGGER_SUPPORT
void MacroAssembler::PushRegistersFromMemory(RegList regs) {
ASSERT((regs & ~kJSCallerSaved) == 0);
// Push the content of the memory location to the stack.
for (int i = 0; i < kNumJSCallerSaved; i++) {
int r = JSCallerSavedCode(i);
if ((regs & (1 << r)) != 0) {
ExternalReference reg_addr =
ExternalReference(Debug_Address::Register(i));
movq(kScratchRegister, reg_addr);
push(Operand(kScratchRegister, 0));
}
}
}
void MacroAssembler::SaveRegistersToMemory(RegList regs) {
ASSERT((regs & ~kJSCallerSaved) == 0);
// Copy the content of registers to memory location.
for (int i = 0; i < kNumJSCallerSaved; i++) {
int r = JSCallerSavedCode(i);
if ((regs & (1 << r)) != 0) {
Register reg = { r };
ExternalReference reg_addr =
ExternalReference(Debug_Address::Register(i));
movq(kScratchRegister, reg_addr);
movq(Operand(kScratchRegister, 0), reg);
}
}
}
void MacroAssembler::RestoreRegistersFromMemory(RegList regs) {
ASSERT((regs & ~kJSCallerSaved) == 0);
// Copy the content of memory location to registers.
for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
int r = JSCallerSavedCode(i);
if ((regs & (1 << r)) != 0) {
Register reg = { r };
ExternalReference reg_addr =
ExternalReference(Debug_Address::Register(i));
movq(kScratchRegister, reg_addr);
movq(reg, Operand(kScratchRegister, 0));
}
}
}
void MacroAssembler::PopRegistersToMemory(RegList regs) {
ASSERT((regs & ~kJSCallerSaved) == 0);
// Pop the content from the stack to the memory location.
for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
int r = JSCallerSavedCode(i);
if ((regs & (1 << r)) != 0) {
ExternalReference reg_addr =
ExternalReference(Debug_Address::Register(i));
movq(kScratchRegister, reg_addr);
pop(Operand(kScratchRegister, 0));
}
}
}
void MacroAssembler::CopyRegistersFromStackToMemory(Register base,
Register scratch,
RegList regs) {
ASSERT(!scratch.is(kScratchRegister));
ASSERT(!base.is(kScratchRegister));
ASSERT(!base.is(scratch));
ASSERT((regs & ~kJSCallerSaved) == 0);
// Copy the content of the stack to the memory location and adjust base.
for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
int r = JSCallerSavedCode(i);
if ((regs & (1 << r)) != 0) {
movq(scratch, Operand(base, 0));
ExternalReference reg_addr =
ExternalReference(Debug_Address::Register(i));
movq(kScratchRegister, reg_addr);
movq(Operand(kScratchRegister, 0), scratch);
lea(base, Operand(base, kPointerSize));
}
}
}
#ifdef ENABLE_DEBUGGER_SUPPORT
void MacroAssembler::DebugBreak() { void MacroAssembler::DebugBreak() {
ASSERT(allow_stub_calls()); ASSERT(allow_stub_calls());
xor_(rax, rax); // no arguments xor_(rax, rax); // no arguments
...@@ -2356,8 +2273,7 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) { ...@@ -2356,8 +2273,7 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) {
} }
void MacroAssembler::EnterExitFramePrologue(ExitFrame::Mode mode, void MacroAssembler::EnterExitFramePrologue(bool save_rax) {
bool save_rax) {
// Setup the frame structure on the stack. // Setup the frame structure on the stack.
// All constants are relative to the frame pointer of the exit frame. // All constants are relative to the frame pointer of the exit frame.
ASSERT(ExitFrameConstants::kCallerSPDisplacement == +2 * kPointerSize); ASSERT(ExitFrameConstants::kCallerSPDisplacement == +2 * kPointerSize);
...@@ -2366,7 +2282,7 @@ void MacroAssembler::EnterExitFramePrologue(ExitFrame::Mode mode, ...@@ -2366,7 +2282,7 @@ void MacroAssembler::EnterExitFramePrologue(ExitFrame::Mode mode,
push(rbp); push(rbp);
movq(rbp, rsp); movq(rbp, rsp);
// Reserve room for entry stack pointer and push the debug marker. // Reserve room for entry stack pointer and push the code object.
ASSERT(ExitFrameConstants::kSPOffset == -1 * kPointerSize); ASSERT(ExitFrameConstants::kSPOffset == -1 * kPointerSize);
push(Immediate(0)); // Saved entry sp, patched before call. push(Immediate(0)); // Saved entry sp, patched before call.
movq(kScratchRegister, CodeObject(), RelocInfo::EMBEDDED_OBJECT); movq(kScratchRegister, CodeObject(), RelocInfo::EMBEDDED_OBJECT);
...@@ -2385,23 +2301,8 @@ void MacroAssembler::EnterExitFramePrologue(ExitFrame::Mode mode, ...@@ -2385,23 +2301,8 @@ void MacroAssembler::EnterExitFramePrologue(ExitFrame::Mode mode,
store_rax(context_address); store_rax(context_address);
} }
void MacroAssembler::EnterExitFrameEpilogue(ExitFrame::Mode mode, void MacroAssembler::EnterExitFrameEpilogue(int result_size,
int result_size,
int argc) { int argc) {
#ifdef ENABLE_DEBUGGER_SUPPORT
// Save the state of all registers to the stack from the memory
// location. This is needed to allow nested break points.
if (mode == ExitFrame::MODE_DEBUG) {
// TODO(1243899): This should be symmetric to
// CopyRegistersFromStackToMemory() but it isn't! esp is assumed
// correct here, but computed for the other call. Very error
// prone! FIX THIS. Actually there are deeper problems with
// register saving than this asymmetry (see the bug report
// associated with this issue).
PushRegistersFromMemory(kJSCallerSaved);
}
#endif
#ifdef _WIN64 #ifdef _WIN64
// Reserve space on stack for result and argument structures, if necessary. // Reserve space on stack for result and argument structures, if necessary.
int result_stack_space = (result_size < 2) ? 0 : result_size * kPointerSize; int result_stack_space = (result_size < 2) ? 0 : result_size * kPointerSize;
...@@ -2430,48 +2331,35 @@ void MacroAssembler::EnterExitFrameEpilogue(ExitFrame::Mode mode, ...@@ -2430,48 +2331,35 @@ void MacroAssembler::EnterExitFrameEpilogue(ExitFrame::Mode mode,
} }
void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode, int result_size) { void MacroAssembler::EnterExitFrame(int result_size) {
EnterExitFramePrologue(mode, true); EnterExitFramePrologue(true);
// Setup argv in callee-saved register r12. It is reused in LeaveExitFrame, // Setup argv in callee-saved register r12. It is reused in LeaveExitFrame,
// so it must be retained across the C-call. // so it must be retained across the C-call.
int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
lea(r12, Operand(rbp, r14, times_pointer_size, offset)); lea(r12, Operand(rbp, r14, times_pointer_size, offset));
EnterExitFrameEpilogue(mode, result_size, 2); EnterExitFrameEpilogue(result_size, 2);
} }
void MacroAssembler::EnterApiExitFrame(ExitFrame::Mode mode, void MacroAssembler::EnterApiExitFrame(int stack_space,
int stack_space,
int argc, int argc,
int result_size) { int result_size) {
EnterExitFramePrologue(mode, false); EnterExitFramePrologue(false);
// Setup argv in callee-saved register r12. It is reused in LeaveExitFrame, // Setup argv in callee-saved register r12. It is reused in LeaveExitFrame,
// so it must be retained across the C-call. // so it must be retained across the C-call.
int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
lea(r12, Operand(rbp, (stack_space * kPointerSize) + offset)); lea(r12, Operand(rbp, (stack_space * kPointerSize) + offset));
EnterExitFrameEpilogue(mode, result_size, argc); EnterExitFrameEpilogue(result_size, argc);
} }
void MacroAssembler::LeaveExitFrame(ExitFrame::Mode mode, int result_size) { void MacroAssembler::LeaveExitFrame(int result_size) {
// Registers: // Registers:
// r12 : argv // r12 : argv
#ifdef ENABLE_DEBUGGER_SUPPORT
// Restore the memory copy of the registers by digging them out from
// the stack. This is needed to allow nested break points.
if (mode == ExitFrame::MODE_DEBUG) {
// It's okay to clobber register rbx below because we don't need
// the function pointer after this.
const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize;
int kOffset = ExitFrameConstants::kCodeOffset - kCallerSavedSize;
lea(rbx, Operand(rbp, kOffset));
CopyRegistersFromStackToMemory(rbx, rcx, kJSCallerSaved);
}
#endif
// Get the return address from the stack and restore the frame pointer. // Get the return address from the stack and restore the frame pointer.
movq(rcx, Operand(rbp, 1 * kPointerSize)); movq(rcx, Operand(rbp, 1 * kPointerSize));
......
...@@ -132,13 +132,6 @@ class MacroAssembler: public Assembler { ...@@ -132,13 +132,6 @@ class MacroAssembler: public Assembler {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Debugger Support // Debugger Support
void SaveRegistersToMemory(RegList regs);
void RestoreRegistersFromMemory(RegList regs);
void PushRegistersFromMemory(RegList regs);
void PopRegistersToMemory(RegList regs);
void CopyRegistersFromStackToMemory(Register base,
Register scratch,
RegList regs);
void DebugBreak(); void DebugBreak();
#endif #endif
...@@ -161,17 +154,16 @@ class MacroAssembler: public Assembler { ...@@ -161,17 +154,16 @@ class MacroAssembler: public Assembler {
// debug mode. Expects the number of arguments in register rax and // debug mode. Expects the number of arguments in register rax and
// sets up the number of arguments in register rdi and the pointer // sets up the number of arguments in register rdi and the pointer
// to the first argument in register rsi. // to the first argument in register rsi.
void EnterExitFrame(ExitFrame::Mode mode, int result_size = 1); void EnterExitFrame(int result_size = 1);
void EnterApiExitFrame(ExitFrame::Mode mode, void EnterApiExitFrame(int stack_space,
int stack_space,
int argc, int argc,
int result_size = 1); int result_size = 1);
// Leave the current exit frame. Expects/provides the return value in // Leave the current exit frame. Expects/provides the return value in
// register rax:rdx (untouched) and the pointer to the first // register rax:rdx (untouched) and the pointer to the first
// argument in register rsi. // argument in register rsi.
void LeaveExitFrame(ExitFrame::Mode mode, int result_size = 1); void LeaveExitFrame(int result_size = 1);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
...@@ -878,8 +870,8 @@ class MacroAssembler: public Assembler { ...@@ -878,8 +870,8 @@ class MacroAssembler: public Assembler {
void EnterFrame(StackFrame::Type type); void EnterFrame(StackFrame::Type type);
void LeaveFrame(StackFrame::Type type); void LeaveFrame(StackFrame::Type type);
void EnterExitFramePrologue(ExitFrame::Mode mode, bool save_rax); void EnterExitFramePrologue(bool save_rax);
void EnterExitFrameEpilogue(ExitFrame::Mode mode, int result_size, int argc); void EnterExitFrameEpilogue(int result_size, int argc);
// Allocation support helpers. // Allocation support helpers.
// Loads the top of new-space into the result register. // Loads the top of new-space into the result register.
......
...@@ -56,10 +56,6 @@ test-api/OutOfMemoryNested: SKIP ...@@ -56,10 +56,6 @@ test-api/OutOfMemoryNested: SKIP
# BUG(355): Test crashes on ARM. # BUG(355): Test crashes on ARM.
test-log/ProfLazyMode: SKIP test-log/ProfLazyMode: SKIP
# BUG(845)
test-debug/GCDuringBreakPointProcessing: SKIP
test-debug/BreakPointICCallWithGC: SKIP
[ $arch == mips ] [ $arch == mips ]
test-accessors: SKIP test-accessors: SKIP
test-alloc: SKIP test-alloc: SKIP
......
...@@ -869,7 +869,7 @@ static void DebugEventBreakPointCollectGarbage( ...@@ -869,7 +869,7 @@ static void DebugEventBreakPointCollectGarbage(
// Scavenge. // Scavenge.
Heap::CollectGarbage(0, v8::internal::NEW_SPACE); Heap::CollectGarbage(0, v8::internal::NEW_SPACE);
} else { } else {
// Mark sweep (and perhaps compact). // Mark sweep compact.
Heap::CollectAllGarbage(true); Heap::CollectAllGarbage(true);
} }
} }
...@@ -1177,6 +1177,40 @@ TEST(BreakPointICCallWithGC) { ...@@ -1177,6 +1177,40 @@ TEST(BreakPointICCallWithGC) {
} }
// Test that a break point can be set at an IC call location and survive a GC.
TEST(BreakPointConstructCallWithGC) {
break_point_hit_count = 0;
v8::HandleScope scope;
DebugLocalContext env;
v8::Debug::SetDebugEventListener(DebugEventBreakPointCollectGarbage,
v8::Undefined());
v8::Script::Compile(v8::String::New("function bar(){ this.x = 1;}"))->Run();
v8::Script::Compile(v8::String::New(
"function foo(){return new bar(1).x;}"))->Run();
v8::Local<v8::Function> foo =
v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
// Run without breakpoints.
CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
CHECK_EQ(0, break_point_hit_count);
// Run with breakpoint.
int bp = SetBreakPoint(foo, 0);
CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
CHECK_EQ(1, break_point_hit_count);
CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
CHECK_EQ(2, break_point_hit_count);
// Run without breakpoints.
ClearBreakPoint(bp);
foo->Call(env->Global(), 0, NULL);
CHECK_EQ(2, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
}
// Test that a break point can be set at a return store location. // Test that a break point can be set at a return store location.
TEST(BreakPointReturn) { TEST(BreakPointReturn) {
break_point_hit_count = 0; break_point_hit_count = 0;
......
...@@ -98,13 +98,6 @@ static int make_code(TypeCode type, int id) { ...@@ -98,13 +98,6 @@ static int make_code(TypeCode type, int id) {
} }
#ifdef ENABLE_DEBUGGER_SUPPORT
static int register_code(int reg) {
return Debug::k_register_address << kDebugIdShift | reg;
}
#endif // ENABLE_DEBUGGER_SUPPORT
TEST(ExternalReferenceEncoder) { TEST(ExternalReferenceEncoder) {
StatsTable::SetCounterFunction(counter_function); StatsTable::SetCounterFunction(counter_function);
Heap::Setup(false); Heap::Setup(false);
...@@ -115,10 +108,6 @@ TEST(ExternalReferenceEncoder) { ...@@ -115,10 +108,6 @@ TEST(ExternalReferenceEncoder) {
Encode(encoder, Runtime::kAbort)); Encode(encoder, Runtime::kAbort));
CHECK_EQ(make_code(IC_UTILITY, IC::kLoadCallbackProperty), CHECK_EQ(make_code(IC_UTILITY, IC::kLoadCallbackProperty),
Encode(encoder, IC_Utility(IC::kLoadCallbackProperty))); Encode(encoder, IC_Utility(IC::kLoadCallbackProperty)));
#ifdef ENABLE_DEBUGGER_SUPPORT
CHECK_EQ(make_code(DEBUG_ADDRESS, register_code(3)),
Encode(encoder, Debug_Address(Debug::k_register_address, 3)));
#endif // ENABLE_DEBUGGER_SUPPORT
ExternalReference keyed_load_function_prototype = ExternalReference keyed_load_function_prototype =
ExternalReference(&Counters::keyed_load_function_prototype); ExternalReference(&Counters::keyed_load_function_prototype);
CHECK_EQ(make_code(STATS_COUNTER, Counters::k_keyed_load_function_prototype), CHECK_EQ(make_code(STATS_COUNTER, Counters::k_keyed_load_function_prototype),
...@@ -156,10 +145,6 @@ TEST(ExternalReferenceDecoder) { ...@@ -156,10 +145,6 @@ TEST(ExternalReferenceDecoder) {
decoder.Decode(make_code(RUNTIME_FUNCTION, Runtime::kAbort))); decoder.Decode(make_code(RUNTIME_FUNCTION, Runtime::kAbort)));
CHECK_EQ(AddressOf(IC_Utility(IC::kLoadCallbackProperty)), CHECK_EQ(AddressOf(IC_Utility(IC::kLoadCallbackProperty)),
decoder.Decode(make_code(IC_UTILITY, IC::kLoadCallbackProperty))); decoder.Decode(make_code(IC_UTILITY, IC::kLoadCallbackProperty)));
#ifdef ENABLE_DEBUGGER_SUPPORT
CHECK_EQ(AddressOf(Debug_Address(Debug::k_register_address, 3)),
decoder.Decode(make_code(DEBUG_ADDRESS, register_code(3))));
#endif // ENABLE_DEBUGGER_SUPPORT
ExternalReference keyed_load_function = ExternalReference keyed_load_function =
ExternalReference(&Counters::keyed_load_function_prototype); ExternalReference(&Counters::keyed_load_function_prototype);
CHECK_EQ(keyed_load_function.address(), CHECK_EQ(keyed_load_function.address(),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment