bool CpuFeatures::SupportsCrankshaft() { return true; }
-void RelocInfo::apply(intptr_t delta, ICacheFlushMode icache_flush_mode) {
+void RelocInfo::apply(intptr_t delta) {
// absolute code pointer inside code object moves with the code object.
if (IsInternalReference(rmode_)) {
// Jump table entry
DCHECK(IsInternalReferenceEncoded(rmode_));
Address target = Assembler::target_address_at(pc_, host_);
Assembler::set_target_address_at(pc_, host_, target + delta,
- icache_flush_mode);
+ SKIP_ICACHE_FLUSH);
}
}
}
-Address Assembler::break_address_from_return_address(Address pc) {
- return target_address_from_return_address(pc);
-}
-
-
Address Assembler::target_address_from_return_address(Address pc) {
// Returns the address of the call target from the return address that will
// be returned to after a call.
}
-Address RelocInfo::call_address() {
- DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
- (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
- // The pc_ offset of 0 assumes patched return sequence per
- // BreakLocation::SetDebugBreakAtReturn(), or debug break
- // slot per BreakLocation::SetDebugBreakAtSlot().
+Address RelocInfo::debug_call_address() {
+ DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence());
return Assembler::target_address_at(pc_, host_);
}
-void RelocInfo::set_call_address(Address target) {
- DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
- (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
+void RelocInfo::set_debug_call_address(Address target) {
+ DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence());
Assembler::set_target_address_at(pc_, host_, target);
if (host() != NULL) {
Object* target_code = Code::GetCodeFromTargetAddress(target);
}
-Object* RelocInfo::call_object() { return *call_object_address(); }
-
-
-void RelocInfo::set_call_object(Object* target) {
- *call_object_address() = target;
-}
-
-
-Object** RelocInfo::call_object_address() {
- DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
- (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
- return reinterpret_cast<Object**>(pc_ + 2 * Assembler::kInstrSize);
-}
-
-
void RelocInfo::WipeOut() {
DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) ||
IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) ||
visitor->VisitInternalReference(this);
} else if (RelocInfo::IsCodeAgeSequence(mode)) {
visitor->VisitCodeAgeSequence(this);
- } else if (((RelocInfo::IsJSReturn(mode) && IsPatchedReturnSequence()) ||
- (RelocInfo::IsDebugBreakSlot(mode) &&
- IsPatchedDebugBreakSlotSequence())) &&
+ } else if (RelocInfo::IsDebugBreakSlot(mode) &&
+ IsPatchedDebugBreakSlotSequence() &&
isolate->debug()->has_break_points()) {
visitor->VisitDebugTarget(this);
} else if (IsRuntimeEntry(mode)) {
} else if (RelocInfo::IsCodeAgeSequence(mode)) {
StaticVisitor::VisitCodeAgeSequence(heap, this);
} else if (heap->isolate()->debug()->has_break_points() &&
- ((RelocInfo::IsJSReturn(mode) && IsPatchedReturnSequence()) ||
- (RelocInfo::IsDebugBreakSlot(mode) &&
- IsPatchedDebugBreakSlotSequence()))) {
+ RelocInfo::IsDebugBreakSlot(mode) &&
+ IsPatchedDebugBreakSlotSequence()) {
StaticVisitor::VisitDebugTarget(heap, this);
} else if (IsRuntimeEntry(mode)) {
StaticVisitor::VisitRuntimeEntry(this);
// in the instruction stream that the call will return to.
INLINE(static Address return_address_from_call_start(Address pc));
- // Return the code target address of the patch debug break slot
- INLINE(static Address break_address_from_return_address(Address pc));
-
// This sets the branch destination.
// This is for calls and branches within generated code.
inline static void deserialization_set_special_target_at(
static const int kCallTargetAddressOffset =
(kMovInstructions + 2) * kInstrSize;
- // Distance between start of patched return sequence and the emitted address
- // to jump to.
- // Patched return sequence is a FIXED_SEQUENCE:
- // mov r0, <address>
- // mtlr r0
- // blrl
- static const int kPatchReturnSequenceAddressOffset = 0 * kInstrSize;
-
// Distance between start of patched debug break slot and the emitted address
// to jump to.
// Patched debug break slot code is a FIXED_SEQUENCE:
// blrl
static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
- // This is the length of the BreakLocation::SetDebugBreakAtReturn()
- // code patch FIXED_SEQUENCE
- static const int kJSReturnSequenceInstructions =
- kMovInstructionsNoConstantPool + 3;
- static const int kJSReturnSequenceLength =
- kJSReturnSequenceInstructions * kInstrSize;
-
// This is the length of the code sequence from SetDebugBreakAtSlot()
// FIXED_SEQUENCE
static const int kDebugBreakSlotInstructions =
// Debugging
- // Mark address of the ExitJSFrame code.
- void RecordJSReturn();
-
// Mark generator continuation.
void RecordGeneratorContinuation();
// Mark address of a debug break slot.
- void RecordDebugBreakSlot();
- void RecordDebugBreakSlotForCall(int argc);
- void RecordDebugBreakSlotForConstructCall();
+ void RecordDebugBreakSlot(RelocInfo::Mode mode, int argc = 0);
// Record the AST id of the CallIC being compiled, so that it can be placed
// in the relocation information.
namespace v8 {
namespace internal {
-void BreakLocation::SetDebugBreakAtReturn() {
- // Patch the code changing the return from JS function sequence from
- //
- // LeaveFrame
- // blr
- //
- // to a call to the debug break return code.
- // this uses a FIXED_SEQUENCE to load an address constant
- //
- // mov r0, <address>
- // mtlr r0
- // blrl
- // bkpt
- //
- CodePatcher patcher(pc(), Assembler::kJSReturnSequenceInstructions);
- Assembler::BlockTrampolinePoolScope block_trampoline_pool(patcher.masm());
- patcher.masm()->mov(
- v8::internal::r0,
- Operand(reinterpret_cast<intptr_t>(debug_info_->GetIsolate()
- ->builtins()
- ->Return_DebugBreak()
- ->entry())));
- patcher.masm()->mtctr(v8::internal::r0);
- patcher.masm()->bctrl();
- patcher.masm()->bkpt(0);
+#define __ ACCESS_MASM(masm)
+
+
+void EmitDebugBreakSlot(MacroAssembler* masm) {
+ Label check_size;
+ __ bind(&check_size);
+ for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
+ __ nop(MacroAssembler::DEBUG_BREAK_NOP);
+ }
+ DCHECK_EQ(Assembler::kDebugBreakSlotInstructions,
+ masm->InstructionsGeneratedSince(&check_size));
}
-void BreakLocation::SetDebugBreakAtSlot() {
- DCHECK(IsDebugBreakSlot());
+void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode,
+ int call_argc) {
+ // Generate enough nop's to make space for a call instruction. Avoid emitting
+ // the trampoline pool in the debug break slot code.
+ Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm);
+ masm->RecordDebugBreakSlot(mode, call_argc);
+ EmitDebugBreakSlot(masm);
+}
+
+
+void DebugCodegen::ClearDebugBreakSlot(Address pc) {
+ CodePatcher patcher(pc, Assembler::kDebugBreakSlotInstructions);
+ EmitDebugBreakSlot(patcher.masm());
+}
+
+
+void DebugCodegen::PatchDebugBreakSlot(Address pc, Handle<Code> code) {
+ DCHECK_EQ(Code::BUILTIN, code->kind());
+ CodePatcher patcher(pc, Assembler::kDebugBreakSlotInstructions);
// Patch the code changing the debug break slot code from
//
// ori r3, r3, 0
// mtlr r0
// blrl
//
- CodePatcher patcher(pc(), Assembler::kDebugBreakSlotInstructions);
Assembler::BlockTrampolinePoolScope block_trampoline_pool(patcher.masm());
- patcher.masm()->mov(
- v8::internal::r0,
- Operand(reinterpret_cast<intptr_t>(
- debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry())));
+ patcher.masm()->mov(v8::internal::r0,
+ Operand(reinterpret_cast<intptr_t>(code->entry())));
patcher.masm()->mtctr(v8::internal::r0);
patcher.masm()->bctrl();
}
-#define __ ACCESS_MASM(masm)
-
-
-static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
- RegList object_regs) {
+void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
+ DebugBreakCallHelperMode mode) {
+ __ RecordComment("Debug break");
{
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ LoadSmiLiteral(ip, Smi::FromInt(LiveEdit::kFramePaddingInitialSize));
__ push(ip);
- // Store the registers containing live values on the expression stack to
- // 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);
- if (object_regs != 0) {
- __ MultiPush(object_regs);
- }
+ if (mode == SAVE_RESULT_REGISTER) __ push(r3);
-#ifdef DEBUG
- __ RecordComment("// Calling from debug break to runtime - come in - over");
-#endif
__ mov(r3, Operand::Zero()); // no arguments
__ mov(r4, Operand(ExternalReference::debug_break(masm->isolate())));
CEntryStub ceb(masm->isolate(), 1);
__ CallStub(&ceb);
- // Restore the register values from the expression stack.
- 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)) {
+ if (FLAG_debug_code) {
+ for (int i = 0; i < kNumJSCallerSaved; i++) {
+ Register reg = {JSCallerSavedCode(i)};
__ mov(reg, Operand(kDebugZapValue));
}
}
+ if (mode == SAVE_RESULT_REGISTER) __ pop(r3);
+
// Don't bother removing padding bytes pushed on the stack
// as the frame is going to be restored right away.
}
-void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) {
- // In places other than IC call sites it is expected that r3 is TOS which
- // is an object - this is not generally the case so this should be used with
- // care.
- Generate_DebugBreakCallHelper(masm, r3.bit());
-}
-
-
-void DebugCodegen::GenerateSlot(MacroAssembler* masm,
- DebugCodegen::SlotLocation location,
- int call_argc) {
- // Generate enough nop's to make space for a call instruction. Avoid emitting
- // the trampoline pool in the debug break slot code.
- Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm);
- Label check_codesize;
- __ bind(&check_codesize);
- RecordRelocInfo(masm, location, call_argc);
- for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
- __ nop(MacroAssembler::DEBUG_BREAK_NOP);
- }
- DCHECK_EQ(Assembler::kDebugBreakSlotInstructions,
- masm->InstructionsGeneratedSince(&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);
-}
-
-
void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
__ Ret();
}
EmitProfilingCounterReset();
__ bind(&ok);
-#ifdef DEBUG
- // Add a label for checking the size of the code used for returning.
- Label check_exit_codesize;
- __ bind(&check_exit_codesize);
-#endif
// Make sure that the constant pool is not emitted inside of the return
// sequence.
{
int32_t arg_count = info_->scope()->num_parameters() + 1;
int32_t sp_delta = arg_count * kPointerSize;
SetReturnPosition(function());
- __ RecordJSReturn();
int no_frame_start = __ LeaveFrame(StackFrame::JAVA_SCRIPT, sp_delta);
-#if V8_TARGET_ARCH_PPC64
- // With 64bit we may need nop() instructions to ensure we have
- // enough space to SetDebugBreakAtReturn()
- if (is_int16(sp_delta)) {
- if (!FLAG_enable_embedded_constant_pool) masm_->nop();
- masm_->nop();
- }
-#endif
__ blr();
info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
}
-
-#ifdef DEBUG
- // Check that the size of the code used for returning is large enough
- // for the debugger's requirements.
- DCHECK(Assembler::kJSReturnSequenceInstructions <=
- masm_->InstructionsGeneratedSince(&check_exit_codesize));
-#endif
}
}
enum FlushICache { FLUSH, DONT_FLUSH };
CodePatcher(byte* address, int instructions, FlushICache flush_cache = FLUSH);
- virtual ~CodePatcher();
+ ~CodePatcher();
// Macro assembler to emit code.
MacroAssembler* masm() { return &masm_; }