Object* RelocInfo::target_object() {
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
- return reinterpret_cast<Object*>(Assembler::target_address_at(pc_));
+ return Memory::Object_at(Assembler::target_address_address_at(pc_));
+}
+
+
+Handle<Object> RelocInfo::target_object_handle(Assembler *origin) {
+ ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
+ return Memory::Object_Handle_at(Assembler::target_address_address_at(pc_));
}
INLINE(Address target_address());
INLINE(void set_target_address(Address target));
INLINE(Object* target_object());
+ INLINE(Handle<Object> target_object_handle(Assembler* origin));
INLINE(Object** target_object_address());
INLINE(void set_target_object(Object* target));
Object* RelocInfo::target_object() {
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
- return *reinterpret_cast<Object**>(pc_);
+ return Memory::Object_at(pc_);
+}
+
+
+Handle<Object> RelocInfo::target_object_handle(Assembler *origin) {
+ ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
+ return Memory::Object_Handle_at(pc_);
}
Object** RelocInfo::target_object_address() {
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
- return reinterpret_cast<Object**>(pc_);
+ return &Memory::Object_at(pc_);
}
void RelocInfo::set_target_object(Object* target) {
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
- *reinterpret_cast<Object**>(pc_) = target;
+ Memory::Object_at(pc_) = target;
}
rinfo->IsCallInstruction());
HeapObject* code = Code::GetCodeFromTargetAddress(rinfo->call_address());
MarkCompactCollector::MarkObject(code);
- // When compacting we convert the call to a real object pointer.
- if (IsCompacting()) rinfo->set_call_object(code);
}
private:
reinterpret_cast<Code*>(target)->instruction_start());
}
+ void VisitDebugTarget(RelocInfo* rinfo) {
+ ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()) && rinfo->IsCallInstruction());
+ Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
+ VisitPointer(&target);
+ rinfo->set_call_address(
+ reinterpret_cast<Code*>(target)->instruction_start());
+ }
+
private:
void UpdatePointer(Object** p) {
if (!(*p)->IsHeapObject()) return;
static Object*& Object_at(Address addr) {
return *reinterpret_cast<Object**>(addr);
}
+
+ static Handle<Object>& Object_Handle_at(Address addr) {
+ return *reinterpret_cast<Handle<Object>*>(addr);
+ }
};
} } // namespace v8::internal
int mode_mask = RelocInfo::kCodeTargetMask |
RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
RelocInfo::kApplyMask;
+ Assembler* origin = desc.origin; // Needed to find target_object on X64.
for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
RelocInfo::Mode mode = it.rinfo()->rmode();
if (mode == RelocInfo::EMBEDDED_OBJECT) {
- Object** p = reinterpret_cast<Object**>(it.rinfo()->target_object());
+ Handle<Object> p = it.rinfo()->target_object_handle(origin);
it.rinfo()->set_target_object(*p);
} else if (RelocInfo::IsCodeTarget(mode)) {
// rewrite code handles in inline cache targets to direct
// pointers to the first instruction in the code object
- Object** p = reinterpret_cast<Object**>(it.rinfo()->target_object());
+ Handle<Object> p = it.rinfo()->target_object_handle(origin);
Code* code = Code::cast(*p);
it.rinfo()->set_target_address(code->instruction_start());
} else {
serializer_(serializer),
reference_encoder_(serializer->reference_encoder_),
offsets_(8),
- addresses_(8) {
+ addresses_(8),
+ offsets_32_bit_(0),
+ data_32_bit_(0) {
}
virtual void VisitPointers(Object** start, Object** end) {
ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
Address encoded_target = serializer_->GetSavedAddress(target);
- offsets_.Add(rinfo->target_address_address() - obj_address_);
- addresses_.Add(encoded_target);
- }
+ // All calls and jumps are to code objects that encode into 32 bits.
+ offsets_32_bit_.Add(rinfo->target_address_address() - obj_address_);
+ uint32_t small_target =
+ static_cast<uint32_t>(reinterpret_cast<uintptr_t>(encoded_target));
+ ASSERT(reinterpret_cast<uintptr_t>(encoded_target) == small_target);
+ data_32_bit_.Add(small_target);
+ }
virtual void VisitExternalReferences(Address* start, Address* end) {
for (int i = 0; i < offsets_.length(); i++) {
memcpy(start_address + offsets_[i], &addresses_[i], sizeof(Address));
}
+ for (int i = 0; i < offsets_32_bit_.length(); i++) {
+ memcpy(start_address + offsets_32_bit_[i], &data_32_bit_[i],
+ sizeof(uint32_t));
+ }
}
private:
ExternalReferenceEncoder* reference_encoder_;
List<int> offsets_;
List<Address> addresses_;
+ // Some updates are 32-bit even on a 64-bit platform.
+ // We keep a separate list of them on 64-bit platforms.
+ List<int> offsets_32_bit_;
+ List<uint32_t> data_32_bit_;
};
void Deserializer::VisitCodeTarget(RelocInfo* rinfo) {
ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
- Address encoded_address = reinterpret_cast<Address>(rinfo->target_object());
+ // On all platforms, the encoded code object address is only 32 bits.
+ Address encoded_address = reinterpret_cast<Address>(Memory::uint32_at(
+ reinterpret_cast<Address>(rinfo->target_object_address())));
Code* target_object = reinterpret_cast<Code*>(Resolve(encoded_address));
rinfo->set_target_address(target_object->instruction_start());
}
// Encoded addresses of HeapObjects always have 'HeapObject' tags.
ASSERT(o->IsHeapObject());
-
switch (GetSpace(encoded)) {
// For Map space and Old space, we cache the known Pages in map_pages,
// old_pointer_pages and old_data_pages. Even though MapSpace keeps a list
}
+void Assembler::emit_code_target(Handle<Code> target, RelocInfo::Mode rmode) {
+ ASSERT(RelocInfo::IsCodeTarget(rmode));
+ RecordRelocInfo(rmode);
+ int current = code_targets_.length();
+ if (current > 0 && code_targets_.last().is_identical_to(target)) {
+ // Optimization if we keep jumping to the same code target.
+ emitl(current - 1);
+ } else {
+ code_targets_.Add(target);
+ emitl(current);
+ }
+}
+
+
void Assembler::emit_rex_64(Register reg, Register rm_reg) {
emit(0x48 | reg.high_bit() << 2 | rm_reg.high_bit());
}
Address Assembler::target_address_at(Address pc) {
- return Memory::Address_at(pc);
+ return Memory::int32_at(pc) + pc + 4;
}
void Assembler::set_target_address_at(Address pc, Address target) {
- Memory::Address_at(pc) = target;
- CPU::FlushICache(pc, sizeof(intptr_t));
+ Memory::int32_at(pc) = target - pc - 4;
+ CPU::FlushICache(pc, sizeof(int32_t));
}
+Handle<Object> Assembler::code_target_object_handle_at(Address pc) {
+ return code_targets_[Memory::int32_at(pc)];
+}
// -----------------------------------------------------------------------------
// Implementation of RelocInfo
void RelocInfo::apply(intptr_t delta) {
if (IsInternalReference(rmode_)) {
// absolute code pointer inside code object moves with the code object.
- intptr_t* p = reinterpret_cast<intptr_t*>(pc_);
- *p += delta; // relocate entry
+ Memory::Address_at(pc_) += delta;
+ } else if (IsCodeTarget(rmode_)) {
+ Memory::int32_at(pc_) -= delta;
+ } else if (rmode_ == JS_RETURN && IsCallInstruction()) {
+ // Special handling of js_return when a break point is set (call
+ // instruction has been inserted).
+ Memory::int32_at(pc_ + 1) -= delta; // relocate entry
}
}
Address RelocInfo::target_address() {
ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
- return Assembler::target_address_at(pc_);
+ if (IsCodeTarget(rmode_)) {
+ return Assembler::target_address_at(pc_);
+ } else {
+ return Memory::Address_at(pc_);
+ }
}
void RelocInfo::set_target_address(Address target) {
ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
- Assembler::set_target_address_at(pc_, target);
+ if (IsCodeTarget(rmode_)) {
+ Assembler::set_target_address_at(pc_, target);
+ } else {
+ Memory::Address_at(pc_) = target;
+ }
}
Object* RelocInfo::target_object() {
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
- return *reinterpret_cast<Object**>(pc_);
+ return Memory::Object_at(pc_);
+}
+
+
+Handle<Object> RelocInfo::target_object_handle(Assembler *origin) {
+ ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
+ if (rmode_ == EMBEDDED_OBJECT) {
+ return Memory::Object_Handle_at(pc_);
+ } else {
+ return origin->code_target_object_handle_at(pc_);
+ }
}
Address RelocInfo::call_address() {
ASSERT(IsCallInstruction());
- return Assembler::target_address_at(
- pc_ + Assembler::kPatchReturnSequenceAddressOffset);
+ return Memory::Address_at(
+ pc_ + Assembler::kRealPatchReturnSequenceAddressOffset);
}
void RelocInfo::set_call_address(Address target) {
ASSERT(IsCallInstruction());
- Assembler::set_target_address_at(
- pc_ + Assembler::kPatchReturnSequenceAddressOffset,
- target);
+ Memory::Address_at(pc_ + Assembler::kRealPatchReturnSequenceAddressOffset) =
+ target;
}
byte* Assembler::spare_buffer_ = NULL;
-Assembler::Assembler(void* buffer, int buffer_size) {
+Assembler::Assembler(void* buffer, int buffer_size)
+ : code_targets_(100) {
if (buffer == NULL) {
// do our own buffer management
if (buffer_size <= kMinimalBufferSize) {
}
+void Assembler::call(Handle<Code> target, RelocInfo::Mode rmode) {
+ EnsureSpace ensure_space(this);
+ last_pc_ = pc_;
+ // 1110 1000 #32-bit disp
+ emit(0xE8);
+ emit_code_target(target, rmode);
+}
+
+
void Assembler::call(Register adr) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
}
+void Assembler::j(Condition cc,
+ Handle<Code> target,
+ RelocInfo::Mode rmode) {
+ EnsureSpace ensure_space(this);
+ last_pc_ = pc_;
+ ASSERT(is_uint4(cc));
+ // 0000 1111 1000 tttn #32-bit disp
+ emit(0x0F);
+ emit(0x80 | cc);
+ emit_code_target(target, rmode);
+}
+
+
void Assembler::jmp(Label* L) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
}
+void Assembler::jmp(Handle<Code> target, RelocInfo::Mode rmode) {
+ EnsureSpace ensure_space(this);
+ last_pc_ = pc_;
+ // 1110 1001 #32-bit disp
+ emit(0xE9);
+ emit_code_target(target, rmode);
+}
+
+
void Assembler::jmp(Register target) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
}
-const int RelocInfo::kApplyMask = 1 << RelocInfo::INTERNAL_REFERENCE;
-
+const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask |
+ 1 << RelocInfo::INTERNAL_REFERENCE |
+ 1 << RelocInfo::JS_RETURN;
} } // namespace v8::internal
// Assembler functions are invoked in between GetCode() calls.
void GetCode(CodeDesc* desc);
- // Read/Modify the code target in the branch/call instruction at pc.
- // On the x64 architecture, the address is absolute, not relative.
+ // Read/Modify the code target in the relative branch/call instruction at pc.
+ // On the x64 architecture, we use relative jumps with a 32-bit displacement
+ // to jump to other Code objects in the Code space in the heap.
+ // Jumps to C functions are done indirectly through a 64-bit register holding
+ // the absolute address of the target.
+ // These functions convert between absolute Addresses of Code objects and
+ // the relative displacements stored in the code.
static inline Address target_address_at(Address pc);
static inline void set_target_address_at(Address pc, Address target);
-
+ inline Handle<Object> code_target_object_handle_at(Address pc);
// Distance between the address of the code target in the call instruction
- // and the return address. Checked in the debug build.
- static const int kCallTargetAddressOffset = 3 + kPointerSize;
- // Distance between start of patched return sequence and the emitted address
- // to jump to (movq = REX.W 0xB8+r.).
- static const int kPatchReturnSequenceAddressOffset = 2;
-
+ // and the return address pushed on the stack.
+ static const int kCallTargetAddressOffset = 4; // Use 32-bit displacement.
+ // Distance between the start of the JS return sequence and where the
+ // 32-bit displacement of a near call would be, relative to the pushed
+ // return address. TODO: Use return sequence length instead.
+ // Should equal Debug::kX64JSReturnSequenceLength - kCallTargetAddressOffset;
+ static const int kPatchReturnSequenceAddressOffset = 13 - 4;
+ // TODO(X64): Rename this, removing the "Real", after changing the above.
+ static const int kRealPatchReturnSequenceAddressOffset = 2;
// ---------------------------------------------------------------------------
// Code generation
//
// Calls
// Call near relative 32-bit displacement, relative to next instruction.
void call(Label* L);
+ void call(Handle<Code> target, RelocInfo::Mode rmode);
// Call near absolute indirect, address in register
void call(Register adr);
// Jumps
// Jump short or near relative.
+ // Use a 32-bit signed displacement.
void jmp(Label* L); // unconditional jump to L
+ void jmp(Handle<Code> target, RelocInfo::Mode rmode);
// Jump near absolute indirect (r64)
void jmp(Register adr);
// Conditional jumps
void j(Condition cc, Label* L);
+ void j(Condition cc, Handle<Code> target, RelocInfo::Mode rmode);
// Floating-point operations
void fld(int i);
void RecordStatementPosition(int pos);
void WriteRecordedPositions();
- // Writes a doubleword of data in the code stream.
- // Used for inline tables, e.g., jump-tables.
- // void dd(uint32_t data);
-
- // Writes a quadword of data in the code stream.
- // Used for inline tables, e.g., jump-tables.
- // void dd(uint64_t data, RelocInfo::Mode reloc_info);
-
int pc_offset() const { return pc_ - buffer_; }
int current_statement_position() const { return current_statement_position_; }
int current_position() const { return current_position_; }
void emit(byte x) { *pc_++ = x; }
inline void emitl(uint32_t x);
- inline void emit(Handle<Object> handle);
inline void emitq(uint64_t x, RelocInfo::Mode rmode);
inline void emitw(uint16_t x);
+ inline void emit_code_target(Handle<Code> target, RelocInfo::Mode rmode);
void emit(Immediate x) { emitl(x.value_); }
// Emits a REX prefix that encodes a 64-bit operand size and
byte* pc_; // the program counter; moves forward
RelocInfoWriter reloc_info_writer;
+ List< Handle<Code> > code_targets_;
// push-pop elimination
byte* last_pc_;
// Set the entry point and jump to the C entry runtime stub.
movq(rbx, ext);
CEntryStub ces(result_size);
- movq(kScratchRegister, ces.GetCode(), RelocInfo::CODE_TARGET);
- jmp(kScratchRegister);
+ jmp(ces.GetCode(), RelocInfo::CODE_TARGET);
}
void MacroAssembler::Jump(Handle<Code> code_object, RelocInfo::Mode rmode) {
- ASSERT(RelocInfo::IsCodeTarget(rmode));
- movq(kScratchRegister, code_object, rmode);
-#ifdef DEBUG
- Label target;
- bind(&target);
-#endif
- jmp(kScratchRegister);
-#ifdef DEBUG
- ASSERT_EQ(kCallTargetAddressOffset,
- SizeOfCodeGeneratedSince(&target) + kPointerSize);
-#endif
+ // TODO(X64): Inline this
+ jmp(code_object, rmode);
}
void MacroAssembler::Call(Handle<Code> code_object, RelocInfo::Mode rmode) {
ASSERT(RelocInfo::IsCodeTarget(rmode));
WriteRecordedPositions();
- movq(kScratchRegister, code_object, rmode);
-#ifdef DEBUG
- // Patch target is kPointer size bytes *before* target label.
- Label target;
- bind(&target);
-#endif
- call(kScratchRegister);
-#ifdef DEBUG
- ASSERT_EQ(kCallTargetAddressOffset,
- SizeOfCodeGeneratedSince(&target) + kPointerSize);
-#endif
+ call(code_object, rmode);
}
if (!resolved) {
uint32_t flags =
Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
- Bootstrapper::FixupFlagsIsPCRelative::encode(false) |
+ Bootstrapper::FixupFlagsIsPCRelative::encode(true) |
Bootstrapper::FixupFlagsUseCodeObject::encode(false);
Unresolved entry =
{ pc_offset() - kCallTargetAddressOffset, flags, name };