Commit 63199d0b authored by rmcilroy@chromium.org's avatar rmcilroy@chromium.org

Avoid flushing the icache unnecessarily when updating target addresses in code.

This CL updates RelocInfo update operations and set_target_address_at to enable
skipping of the icache flush if it going to be batched up later.
Code::CopyFrom and Code::Relocate are modified to avoid individual icache
flushes since the whole code area will be flushed after the reloc info is
updated.

These changes reduce a regression when enabling the OOL constant pool on Arm,
since this change can cause MovT/MovW instructions for relocatable targets
if the constant pool is full.

Scores for Mandreel latency on a Nexus 5:
 - OOL CP disabled: 3533
 - OOL CP enabled, without this CL: 1825
 - OOL CP enabled, with change: 3015

R=rodolph.perfetta@arm.com, ulan@chromium.org

Review URL: https://codereview.chromium.org/284153004

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21380 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 9d9fa6af
......@@ -91,7 +91,7 @@ DwVfpRegister DwVfpRegister::FromAllocationIndex(int index) {
}
void RelocInfo::apply(intptr_t delta) {
void RelocInfo::apply(intptr_t delta, ICacheFlushMode icache_flush_mode) {
if (RelocInfo::IsInternalReference(rmode_)) {
// absolute code pointer inside code object moves with the code object.
int32_t* p = reinterpret_cast<int32_t*>(pc_);
......@@ -142,10 +142,13 @@ int RelocInfo::target_address_size() {
}
void RelocInfo::set_target_address(Address target, WriteBarrierMode mode) {
void RelocInfo::set_target_address(Address target,
WriteBarrierMode write_barrier_mode,
ICacheFlushMode icache_flush_mode) {
ASSERT(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
Assembler::set_target_address_at(pc_, host_, target);
if (mode == UPDATE_WRITE_BARRIER && host() != NULL && IsCodeTarget(rmode_)) {
Assembler::set_target_address_at(pc_, host_, target, icache_flush_mode);
if (write_barrier_mode == UPDATE_WRITE_BARRIER &&
host() != NULL && IsCodeTarget(rmode_)) {
Object* target_code = Code::GetCodeFromTargetAddress(target);
host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
host(), this, HeapObject::cast(target_code));
......@@ -166,12 +169,15 @@ Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
}
void RelocInfo::set_target_object(Object* target, WriteBarrierMode mode) {
void RelocInfo::set_target_object(Object* target,
WriteBarrierMode write_barrier_mode,
ICacheFlushMode icache_flush_mode) {
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
ASSERT(!target->IsConsString());
Assembler::set_target_address_at(pc_, host_,
reinterpret_cast<Address>(target));
if (mode == UPDATE_WRITE_BARRIER &&
reinterpret_cast<Address>(target),
icache_flush_mode);
if (write_barrier_mode == UPDATE_WRITE_BARRIER &&
host() != NULL &&
target->IsHeapObject()) {
host()->GetHeap()->incremental_marking()->RecordWrite(
......@@ -193,9 +199,11 @@ Address RelocInfo::target_runtime_entry(Assembler* origin) {
void RelocInfo::set_target_runtime_entry(Address target,
WriteBarrierMode mode) {
WriteBarrierMode write_barrier_mode,
ICacheFlushMode icache_flush_mode) {
ASSERT(IsRuntimeEntry(rmode_));
if (target_address() != target) set_target_address(target, mode);
if (target_address() != target)
set_target_address(target, write_barrier_mode, icache_flush_mode);
}
......@@ -212,11 +220,13 @@ Cell* RelocInfo::target_cell() {
}
void RelocInfo::set_target_cell(Cell* cell, WriteBarrierMode mode) {
void RelocInfo::set_target_cell(Cell* cell,
WriteBarrierMode write_barrier_mode,
ICacheFlushMode icache_flush_mode) {
ASSERT(rmode_ == RelocInfo::CELL);
Address address = cell->address() + Cell::kValueOffset;
Memory::Address_at(pc_) = address;
if (mode == UPDATE_WRITE_BARRIER && host() != NULL) {
if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL) {
// TODO(1550) We are passing NULL as a slot because cell can never be on
// evacuation candidate.
host()->GetHeap()->incremental_marking()->RecordWrite(
......@@ -242,7 +252,8 @@ Code* RelocInfo::code_age_stub() {
}
void RelocInfo::set_code_age_stub(Code* stub) {
void RelocInfo::set_code_age_stub(Code* stub,
ICacheFlushMode icache_flush_mode) {
ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
Memory::Address_at(pc_ +
(kNoCodeAgeSequenceLength - Assembler::kInstrSize)) =
......@@ -506,24 +517,27 @@ static Instr EncodeMovwImmediate(uint32_t immediate) {
}
static Instr PatchMovwImmediate(Instr instruction, uint32_t immediate) {
instruction &= ~EncodeMovwImmediate(0xffff);
return instruction | EncodeMovwImmediate(immediate);
}
void Assembler::set_target_address_at(Address pc,
ConstantPoolArray* constant_pool,
Address target) {
Address target,
ICacheFlushMode icache_flush_mode) {
if (IsMovW(Memory::int32_at(pc))) {
ASSERT(IsMovT(Memory::int32_at(pc + kInstrSize)));
uint32_t* instr_ptr = reinterpret_cast<uint32_t*>(pc);
uint32_t immediate = reinterpret_cast<uint32_t>(target);
uint32_t intermediate = instr_ptr[0];
intermediate &= ~EncodeMovwImmediate(0xFFFF);
intermediate |= EncodeMovwImmediate(immediate & 0xFFFF);
instr_ptr[0] = intermediate;
intermediate = instr_ptr[1];
intermediate &= ~EncodeMovwImmediate(0xFFFF);
intermediate |= EncodeMovwImmediate(immediate >> 16);
instr_ptr[1] = intermediate;
instr_ptr[0] = PatchMovwImmediate(instr_ptr[0], immediate & 0xFFFF);
instr_ptr[1] = PatchMovwImmediate(instr_ptr[1], immediate >> 16);
ASSERT(IsMovW(Memory::int32_at(pc)));
ASSERT(IsMovT(Memory::int32_at(pc + kInstrSize)));
CPU::FlushICache(pc, 2 * kInstrSize);
if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
CPU::FlushICache(pc, 2 * kInstrSize);
}
} else if (FLAG_enable_ool_constant_pool) {
ASSERT(IsLdrPpImmediateOffset(Memory::int32_at(pc)));
Memory::Address_at(
......
......@@ -763,16 +763,20 @@ class Assembler : public AssemblerBase {
ConstantPoolArray* constant_pool));
INLINE(static void set_target_address_at(Address pc,
ConstantPoolArray* constant_pool,
Address target));
Address target,
ICacheFlushMode icache_flush_mode =
FLUSH_ICACHE_IF_NEEDED));
INLINE(static Address target_address_at(Address pc, Code* code)) {
ConstantPoolArray* constant_pool = code ? code->constant_pool() : NULL;
return target_address_at(pc, constant_pool);
}
INLINE(static void set_target_address_at(Address pc,
Code* code,
Address target)) {
Address target,
ICacheFlushMode icache_flush_mode =
FLUSH_ICACHE_IF_NEEDED)) {
ConstantPoolArray* constant_pool = code ? code->constant_pool() : NULL;
set_target_address_at(pc, constant_pool, target);
set_target_address_at(pc, constant_pool, target, icache_flush_mode);
}
// Return the code target address at a call site from the return address
......
......@@ -17,15 +17,18 @@ namespace internal {
bool CpuFeatures::SupportsCrankshaft() { return true; }
void RelocInfo::apply(intptr_t delta) {
void RelocInfo::apply(intptr_t delta, ICacheFlushMode icache_flush_mode) {
UNIMPLEMENTED();
}
void RelocInfo::set_target_address(Address target, WriteBarrierMode mode) {
void RelocInfo::set_target_address(Address target,
WriteBarrierMode write_barrier_mode,
ICacheFlushMode icache_flush_mode) {
ASSERT(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
Assembler::set_target_address_at(pc_, host_, target);
if (mode == UPDATE_WRITE_BARRIER && host() != NULL && IsCodeTarget(rmode_)) {
Assembler::set_target_address_at(pc_, host_, target, icache_flush_mode);
if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL &&
IsCodeTarget(rmode_)) {
Object* target_code = Code::GetCodeFromTargetAddress(target);
host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
host(), this, HeapObject::cast(target_code));
......@@ -625,7 +628,8 @@ void Assembler::deserialization_set_special_target_at(
void Assembler::set_target_address_at(Address pc,
ConstantPoolArray* constant_pool,
Address target) {
Address target,
ICacheFlushMode icache_flush_mode) {
Memory::Address_at(target_pointer_address_at(pc)) = target;
// Intuitively, we would think it is necessary to always flush the
// instruction cache after patching a target address in the code as follows:
......@@ -640,9 +644,10 @@ void Assembler::set_target_address_at(Address pc,
void Assembler::set_target_address_at(Address pc,
Code* code,
Address target) {
Address target,
ICacheFlushMode icache_flush_mode) {
ConstantPoolArray* constant_pool = code ? code->constant_pool() : NULL;
set_target_address_at(pc, constant_pool, target);
set_target_address_at(pc, constant_pool, target, icache_flush_mode);
}
......@@ -684,12 +689,15 @@ Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
}
void RelocInfo::set_target_object(Object* target, WriteBarrierMode mode) {
void RelocInfo::set_target_object(Object* target,
WriteBarrierMode write_barrier_mode,
ICacheFlushMode icache_flush_mode) {
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
ASSERT(!target->IsConsString());
Assembler::set_target_address_at(pc_, host_,
reinterpret_cast<Address>(target));
if (mode == UPDATE_WRITE_BARRIER &&
reinterpret_cast<Address>(target),
icache_flush_mode);
if (write_barrier_mode == UPDATE_WRITE_BARRIER &&
host() != NULL &&
target->IsHeapObject()) {
host()->GetHeap()->incremental_marking()->RecordWrite(
......@@ -711,9 +719,12 @@ Address RelocInfo::target_runtime_entry(Assembler* origin) {
void RelocInfo::set_target_runtime_entry(Address target,
WriteBarrierMode mode) {
WriteBarrierMode write_barrier_mode,
ICacheFlushMode icache_flush_mode) {
ASSERT(IsRuntimeEntry(rmode_));
if (target_address() != target) set_target_address(target, mode);
if (target_address() != target) {
set_target_address(target, write_barrier_mode, icache_flush_mode);
}
}
......@@ -730,7 +741,9 @@ Cell* RelocInfo::target_cell() {
}
void RelocInfo::set_target_cell(Cell* cell, WriteBarrierMode mode) {
void RelocInfo::set_target_cell(Cell* cell,
WriteBarrierMode write_barrier_mode,
ICacheFlushMode icache_flush_mode) {
UNIMPLEMENTED();
}
......@@ -753,7 +766,8 @@ Code* RelocInfo::code_age_stub() {
}
void RelocInfo::set_code_age_stub(Code* stub) {
void RelocInfo::set_code_age_stub(Code* stub,
ICacheFlushMode icache_flush_mode) {
ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
ASSERT(!Code::IsYoungSequence(stub->GetIsolate(), pc_));
// Overwrite the stub entry point in the code age sequence. This is loaded as
......
......@@ -788,11 +788,15 @@ class Assembler : public AssemblerBase {
ConstantPoolArray* constant_pool);
inline static void set_target_address_at(Address pc,
ConstantPoolArray* constant_pool,
Address target);
Address target,
ICacheFlushMode icache_flush_mode =
FLUSH_ICACHE_IF_NEEDED);
static inline Address target_address_at(Address pc, Code* code);
static inline void set_target_address_at(Address pc,
Code* code,
Address target);
Address target,
ICacheFlushMode icache_flush_mode =
FLUSH_ICACHE_IF_NEEDED);
// Return the code target address at a call site from the return address of
// that call in the instruction stream.
......
......@@ -276,6 +276,12 @@ class Label BASE_EMBEDDED {
enum SaveFPRegsMode { kDontSaveFPRegs, kSaveFPRegs };
// Specifies whether to perform icache flush operations on RelocInfo updates.
// If FLUSH_ICACHE_IF_NEEDED, the icache will always be flushed if an
// instruction was modified. If SKIP_ICACHE_FLUSH the flush will always be
// skipped (only use this if you will flush the icache manually before it is
// executed).
enum ICacheFlushMode { FLUSH_ICACHE_IF_NEEDED, SKIP_ICACHE_FLUSH };
// -----------------------------------------------------------------------------
// Relocation information
......@@ -360,7 +366,6 @@ class RelocInfo {
LAST_STANDARD_NONCOMPACT_ENUM = INTERNAL_REFERENCE
};
RelocInfo() {}
RelocInfo(byte* pc, Mode rmode, intptr_t data, Code* host)
......@@ -452,7 +457,9 @@ class RelocInfo {
void set_host(Code* host) { host_ = host; }
// Apply a relocation by delta bytes
INLINE(void apply(intptr_t delta));
INLINE(void apply(intptr_t delta,
ICacheFlushMode icache_flush_mode =
FLUSH_ICACHE_IF_NEEDED));
// Is the pointer this relocation info refers to coded like a plain pointer
// or is it strange in some way (e.g. relative or patched into a series of
......@@ -468,22 +475,35 @@ class RelocInfo {
// can only be called if IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)
INLINE(Address target_address());
INLINE(void set_target_address(Address target,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER));
WriteBarrierMode write_barrier_mode =
UPDATE_WRITE_BARRIER,
ICacheFlushMode icache_flush_mode =
FLUSH_ICACHE_IF_NEEDED));
INLINE(Object* target_object());
INLINE(Handle<Object> target_object_handle(Assembler* origin));
INLINE(void set_target_object(Object* target,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER));
WriteBarrierMode write_barrier_mode =
UPDATE_WRITE_BARRIER,
ICacheFlushMode icache_flush_mode =
FLUSH_ICACHE_IF_NEEDED));
INLINE(Address target_runtime_entry(Assembler* origin));
INLINE(void set_target_runtime_entry(Address target,
WriteBarrierMode mode =
UPDATE_WRITE_BARRIER));
WriteBarrierMode write_barrier_mode =
UPDATE_WRITE_BARRIER,
ICacheFlushMode icache_flush_mode =
FLUSH_ICACHE_IF_NEEDED));
INLINE(Cell* target_cell());
INLINE(Handle<Cell> target_cell_handle());
INLINE(void set_target_cell(Cell* cell,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER));
WriteBarrierMode write_barrier_mode =
UPDATE_WRITE_BARRIER,
ICacheFlushMode icache_flush_mode =
FLUSH_ICACHE_IF_NEEDED));
INLINE(Handle<Object> code_age_stub_handle(Assembler* origin));
INLINE(Code* code_age_stub());
INLINE(void set_code_age_stub(Code* stub));
INLINE(void set_code_age_stub(Code* stub,
ICacheFlushMode icache_flush_mode =
FLUSH_ICACHE_IF_NEEDED));
// Returns the address of the constant pool entry where the target address
// is held. This should only be called if IsInConstantPool returns true.
......
......@@ -53,34 +53,35 @@ static const int kNoCodeAgeSequenceLength = 5;
// The modes possibly affected by apply must be in kApplyMask.
void RelocInfo::apply(intptr_t delta) {
void RelocInfo::apply(intptr_t delta, ICacheFlushMode icache_flush_mode) {
bool flush_icache = icache_flush_mode != SKIP_ICACHE_FLUSH;
if (IsRuntimeEntry(rmode_) || IsCodeTarget(rmode_)) {
int32_t* p = reinterpret_cast<int32_t*>(pc_);
*p -= delta; // Relocate entry.
CPU::FlushICache(p, sizeof(uint32_t));
if (flush_icache) CPU::FlushICache(p, sizeof(uint32_t));
} else if (rmode_ == CODE_AGE_SEQUENCE) {
if (*pc_ == kCallOpcode) {
int32_t* p = reinterpret_cast<int32_t*>(pc_ + 1);
*p -= delta; // Relocate entry.
CPU::FlushICache(p, sizeof(uint32_t));
if (flush_icache) CPU::FlushICache(p, sizeof(uint32_t));
}
} else if (rmode_ == JS_RETURN && IsPatchedReturnSequence()) {
// Special handling of js_return when a break point is set (call
// instruction has been inserted).
int32_t* p = reinterpret_cast<int32_t*>(pc_ + 1);
*p -= delta; // Relocate entry.
CPU::FlushICache(p, sizeof(uint32_t));
if (flush_icache) CPU::FlushICache(p, sizeof(uint32_t));
} else if (rmode_ == DEBUG_BREAK_SLOT && IsPatchedDebugBreakSlotSequence()) {
// Special handling of a debug break slot when a break point is set (call
// instruction has been inserted).
int32_t* p = reinterpret_cast<int32_t*>(pc_ + 1);
*p -= delta; // Relocate entry.
CPU::FlushICache(p, sizeof(uint32_t));
if (flush_icache) CPU::FlushICache(p, sizeof(uint32_t));
} else if (IsInternalReference(rmode_)) {
// absolute code pointer inside code object moves with the code object.
int32_t* p = reinterpret_cast<int32_t*>(pc_);
*p += delta; // Relocate entry.
CPU::FlushICache(p, sizeof(uint32_t));
if (flush_icache) CPU::FlushICache(p, sizeof(uint32_t));
}
}
......@@ -110,10 +111,13 @@ int RelocInfo::target_address_size() {
}
void RelocInfo::set_target_address(Address target, WriteBarrierMode mode) {
Assembler::set_target_address_at(pc_, host_, target);
void RelocInfo::set_target_address(Address target,
WriteBarrierMode write_barrier_mode,
ICacheFlushMode icache_flush_mode) {
Assembler::set_target_address_at(pc_, host_, target, icache_flush_mode);
ASSERT(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
if (mode == UPDATE_WRITE_BARRIER && host() != NULL && IsCodeTarget(rmode_)) {
if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL &&
IsCodeTarget(rmode_)) {
Object* target_code = Code::GetCodeFromTargetAddress(target);
host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
host(), this, HeapObject::cast(target_code));
......@@ -133,12 +137,16 @@ Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
}
void RelocInfo::set_target_object(Object* target, WriteBarrierMode mode) {
void RelocInfo::set_target_object(Object* target,
WriteBarrierMode write_barrier_mode,
ICacheFlushMode icache_flush_mode) {
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
ASSERT(!target->IsConsString());
Memory::Object_at(pc_) = target;
CPU::FlushICache(pc_, sizeof(Address));
if (mode == UPDATE_WRITE_BARRIER &&
if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
CPU::FlushICache(pc_, sizeof(Address));
}
if (write_barrier_mode == UPDATE_WRITE_BARRIER &&
host() != NULL &&
target->IsHeapObject()) {
host()->GetHeap()->incremental_marking()->RecordWrite(
......@@ -160,9 +168,12 @@ Address RelocInfo::target_runtime_entry(Assembler* origin) {
void RelocInfo::set_target_runtime_entry(Address target,
WriteBarrierMode mode) {
WriteBarrierMode write_barrier_mode,
ICacheFlushMode icache_flush_mode) {
ASSERT(IsRuntimeEntry(rmode_));
if (target_address() != target) set_target_address(target, mode);
if (target_address() != target) {
set_target_address(target, write_barrier_mode, icache_flush_mode);
}
}
......@@ -179,12 +190,16 @@ Cell* RelocInfo::target_cell() {
}
void RelocInfo::set_target_cell(Cell* cell, WriteBarrierMode mode) {
void RelocInfo::set_target_cell(Cell* cell,
WriteBarrierMode write_barrier_mode,
ICacheFlushMode icache_flush_mode) {
ASSERT(rmode_ == RelocInfo::CELL);
Address address = cell->address() + Cell::kValueOffset;
Memory::Address_at(pc_) = address;
CPU::FlushICache(pc_, sizeof(Address));
if (mode == UPDATE_WRITE_BARRIER && host() != NULL) {
if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
CPU::FlushICache(pc_, sizeof(Address));
}
if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL) {
// TODO(1550) We are passing NULL as a slot because cell can never be on
// evacuation candidate.
host()->GetHeap()->incremental_marking()->RecordWrite(
......@@ -208,10 +223,12 @@ Code* RelocInfo::code_age_stub() {
}
void RelocInfo::set_code_age_stub(Code* stub) {
void RelocInfo::set_code_age_stub(Code* stub,
ICacheFlushMode icache_flush_mode) {
ASSERT(*pc_ == kCallOpcode);
ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
Assembler::set_target_address_at(pc_ + 1, host_, stub->instruction_start());
Assembler::set_target_address_at(pc_ + 1, host_, stub->instruction_start(),
icache_flush_mode);
}
......@@ -451,10 +468,13 @@ Address Assembler::target_address_at(Address pc,
void Assembler::set_target_address_at(Address pc,
ConstantPoolArray* constant_pool,
Address target) {
Address target,
ICacheFlushMode icache_flush_mode) {
int32_t* p = reinterpret_cast<int32_t*>(pc);
*p = target - (pc + sizeof(int32_t));
CPU::FlushICache(p, sizeof(int32_t));
if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
CPU::FlushICache(p, sizeof(int32_t));
}
}
......
......@@ -493,14 +493,18 @@ class Assembler : public AssemblerBase {
ConstantPoolArray* constant_pool);
inline static void set_target_address_at(Address pc,
ConstantPoolArray* constant_pool,
Address target);
Address target,
ICacheFlushMode icache_flush_mode =
FLUSH_ICACHE_IF_NEEDED);
static inline Address target_address_at(Address pc, Code* code) {
ConstantPoolArray* constant_pool = code ? code->constant_pool() : NULL;
return target_address_at(pc, constant_pool);
}
static inline void set_target_address_at(Address pc,
Code* code,
Address target) {
Address target,
ICacheFlushMode icache_flush_mode =
FLUSH_ICACHE_IF_NEEDED) {
ConstantPoolArray* constant_pool = code ? code->constant_pool() : NULL;
set_target_address_at(pc, constant_pool, target);
}
......
......@@ -10969,7 +10969,7 @@ void Code::InvalidateEmbeddedObjects() {
void Code::Relocate(intptr_t delta) {
for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
it.rinfo()->apply(delta);
it.rinfo()->apply(delta, SKIP_ICACHE_FLUSH);
}
CPU::FlushICache(instruction_start(), instruction_size());
}
......@@ -11001,26 +11001,28 @@ void Code::CopyFrom(const CodeDesc& desc) {
RelocInfo::Mode mode = it.rinfo()->rmode();
if (mode == RelocInfo::EMBEDDED_OBJECT) {
Handle<Object> p = it.rinfo()->target_object_handle(origin);
it.rinfo()->set_target_object(*p, SKIP_WRITE_BARRIER);
it.rinfo()->set_target_object(*p, SKIP_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
} else if (mode == RelocInfo::CELL) {
Handle<Cell> cell = it.rinfo()->target_cell_handle();
it.rinfo()->set_target_cell(*cell, SKIP_WRITE_BARRIER);
it.rinfo()->set_target_cell(*cell, SKIP_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
} else if (RelocInfo::IsCodeTarget(mode)) {
// rewrite code handles in inline cache targets to direct
// pointers to the first instruction in the code object
Handle<Object> p = it.rinfo()->target_object_handle(origin);
Code* code = Code::cast(*p);
it.rinfo()->set_target_address(code->instruction_start(),
SKIP_WRITE_BARRIER);
SKIP_WRITE_BARRIER,
SKIP_ICACHE_FLUSH);
} else if (RelocInfo::IsRuntimeEntry(mode)) {
Address p = it.rinfo()->target_runtime_entry(origin);
it.rinfo()->set_target_runtime_entry(p, SKIP_WRITE_BARRIER);
it.rinfo()->set_target_runtime_entry(p, SKIP_WRITE_BARRIER,
SKIP_ICACHE_FLUSH);
} else if (mode == RelocInfo::CODE_AGE_SEQUENCE) {
Handle<Object> p = it.rinfo()->code_age_stub_handle(origin);
Code* code = Code::cast(*p);
it.rinfo()->set_code_age_stub(code);
it.rinfo()->set_code_age_stub(code, SKIP_ICACHE_FLUSH);
} else {
it.rinfo()->apply(delta);
it.rinfo()->apply(delta, SKIP_ICACHE_FLUSH);
}
}
CPU::FlushICache(instruction_start(), instruction_size());
......
......@@ -193,9 +193,12 @@ Address Assembler::target_address_at(Address pc,
void Assembler::set_target_address_at(Address pc,
ConstantPoolArray* constant_pool,
Address target) {
Address target,
ICacheFlushMode icache_flush_mode) {
Memory::int32_at(pc) = static_cast<int32_t>(target - pc - 4);
CPU::FlushICache(pc, sizeof(int32_t));
if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
CPU::FlushICache(pc, sizeof(int32_t));
}
}
......@@ -218,19 +221,20 @@ Address Assembler::runtime_entry_at(Address pc) {
// Implementation of RelocInfo
// The modes possibly affected by apply must be in kApplyMask.
void RelocInfo::apply(intptr_t delta) {
void RelocInfo::apply(intptr_t delta, ICacheFlushMode icache_flush_mode) {
bool flush_icache = icache_flush_mode != SKIP_ICACHE_FLUSH;
if (IsInternalReference(rmode_)) {
// absolute code pointer inside code object moves with the code object.
Memory::Address_at(pc_) += static_cast<int32_t>(delta);
CPU::FlushICache(pc_, sizeof(Address));
if (flush_icache) CPU::FlushICache(pc_, sizeof(Address));
} else if (IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)) {
Memory::int32_at(pc_) -= static_cast<int32_t>(delta);
CPU::FlushICache(pc_, sizeof(int32_t));
if (flush_icache) CPU::FlushICache(pc_, sizeof(int32_t));
} else if (rmode_ == CODE_AGE_SEQUENCE) {
if (*pc_ == kCallOpcode) {
int32_t* p = reinterpret_cast<int32_t*>(pc_ + 1);
*p -= static_cast<int32_t>(delta); // Relocate entry.
CPU::FlushICache(p, sizeof(uint32_t));
if (flush_icache) CPU::FlushICache(p, sizeof(uint32_t));
}
}
}
......@@ -265,10 +269,13 @@ int RelocInfo::target_address_size() {
}
void RelocInfo::set_target_address(Address target, WriteBarrierMode mode) {
void RelocInfo::set_target_address(Address target,
WriteBarrierMode write_barrier_mode,
ICacheFlushMode icache_flush_mode) {
ASSERT(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
Assembler::set_target_address_at(pc_, host_, target);
if (mode == UPDATE_WRITE_BARRIER && host() != NULL && IsCodeTarget(rmode_)) {
Assembler::set_target_address_at(pc_, host_, target, icache_flush_mode);
if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL &&
IsCodeTarget(rmode_)) {
Object* target_code = Code::GetCodeFromTargetAddress(target);
host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
host(), this, HeapObject::cast(target_code));
......@@ -298,12 +305,16 @@ Address RelocInfo::target_reference() {
}
void RelocInfo::set_target_object(Object* target, WriteBarrierMode mode) {
void RelocInfo::set_target_object(Object* target,
WriteBarrierMode write_barrier_mode,
ICacheFlushMode icache_flush_mode) {
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
ASSERT(!target->IsConsString());
Memory::Object_at(pc_) = target;
CPU::FlushICache(pc_, sizeof(Address));
if (mode == UPDATE_WRITE_BARRIER &&
if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
CPU::FlushICache(pc_, sizeof(Address));
}
if (write_barrier_mode == UPDATE_WRITE_BARRIER &&
host() != NULL &&
target->IsHeapObject()) {
host()->GetHeap()->incremental_marking()->RecordWrite(
......@@ -319,9 +330,12 @@ Address RelocInfo::target_runtime_entry(Assembler* origin) {
void RelocInfo::set_target_runtime_entry(Address target,
WriteBarrierMode mode) {
WriteBarrierMode write_barrier_mode,
ICacheFlushMode icache_flush_mode) {
ASSERT(IsRuntimeEntry(rmode_));
if (target_address() != target) set_target_address(target, mode);
if (target_address() != target) {
set_target_address(target, write_barrier_mode, icache_flush_mode);
}
}
......@@ -338,12 +352,16 @@ Cell* RelocInfo::target_cell() {
}
void RelocInfo::set_target_cell(Cell* cell, WriteBarrierMode mode) {
void RelocInfo::set_target_cell(Cell* cell,
WriteBarrierMode write_barrier_mode,
ICacheFlushMode icache_flush_mode) {
ASSERT(rmode_ == RelocInfo::CELL);
Address address = cell->address() + Cell::kValueOffset;
Memory::Address_at(pc_) = address;
CPU::FlushICache(pc_, sizeof(Address));
if (mode == UPDATE_WRITE_BARRIER &&
if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
CPU::FlushICache(pc_, sizeof(Address));
}
if (write_barrier_mode == UPDATE_WRITE_BARRIER &&
host() != NULL) {
// TODO(1550) We are passing NULL as a slot because cell can never be on
// evacuation candidate.
......@@ -397,10 +415,12 @@ Code* RelocInfo::code_age_stub() {
}
void RelocInfo::set_code_age_stub(Code* stub) {
void RelocInfo::set_code_age_stub(Code* stub,
ICacheFlushMode icache_flush_mode) {
ASSERT(*pc_ == kCallOpcode);
ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
Assembler::set_target_address_at(pc_ + 1, host_, stub->instruction_start());
Assembler::set_target_address_at(pc_ + 1, host_, stub->instruction_start(),
icache_flush_mode);
}
......
......@@ -518,16 +518,20 @@ class Assembler : public AssemblerBase {
ConstantPoolArray* constant_pool);
static inline void set_target_address_at(Address pc,
ConstantPoolArray* constant_pool,
Address target);
Address target,
ICacheFlushMode icache_flush_mode =
FLUSH_ICACHE_IF_NEEDED) ;
static inline Address target_address_at(Address pc, Code* code) {
ConstantPoolArray* constant_pool = code ? code->constant_pool() : NULL;
return target_address_at(pc, constant_pool);
}
static inline void set_target_address_at(Address pc,
Code* code,
Address target) {
Address target,
ICacheFlushMode icache_flush_mode =
FLUSH_ICACHE_IF_NEEDED) {
ConstantPoolArray* constant_pool = code ? code->constant_pool() : NULL;
set_target_address_at(pc, constant_pool, target);
set_target_address_at(pc, constant_pool, target, icache_flush_mode);
}
// Return the code target address at a call site from the return 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