Index: src/ppc/assembler-ppc-inl.h |
diff --git a/src/ppc/assembler-ppc-inl.h b/src/ppc/assembler-ppc-inl.h |
index d95c7ec5968a5e8fec471bdabed8f6dcf84d01d4..89a3d7ef7e0ec1e7cd032016028947ee4b10633f 100644 |
--- a/src/ppc/assembler-ppc-inl.h |
+++ b/src/ppc/assembler-ppc-inl.h |
@@ -94,6 +94,13 @@ Address RelocInfo::target_address_address() { |
DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) || |
rmode_ == EMBEDDED_OBJECT || rmode_ == EXTERNAL_REFERENCE); |
+ if (FLAG_enable_embedded_constant_pool && |
+ Assembler::IsConstantPoolLoadStart(pc_)) { |
+ // We return the PC for ool constant pool since this function is used by the |
+ // serializer and expects the address to reside within the code object. |
+ return reinterpret_cast<Address>(pc_); |
+ } |
+ |
// Read the address of the word containing the target_address in an |
// instruction stream. |
// The only architecture-independent user of this function is the serializer. |
@@ -108,6 +115,14 @@ Address RelocInfo::target_address_address() { |
Address RelocInfo::constant_pool_entry_address() { |
+ if (FLAG_enable_embedded_constant_pool) { |
+ Address constant_pool = host_->constant_pool(); |
+ DCHECK(constant_pool); |
+ ConstantPoolEntry::Access access; |
+ if (Assembler::IsConstantPoolLoadStart(pc_, &access)) |
+ return Assembler::target_constant_pool_address_at( |
+ pc_, constant_pool, access, ConstantPoolEntry::INTPTR); |
+ } |
UNREACHABLE(); |
return NULL; |
} |
@@ -143,12 +158,28 @@ Address Assembler::target_address_from_return_address(Address pc) { |
// mtlr ip |
// blrl |
// @ return address |
- return pc - (kMovInstructions + 2) * kInstrSize; |
+ int len; |
+ ConstantPoolEntry::Access access; |
+ if (FLAG_enable_embedded_constant_pool && |
+ IsConstantPoolLoadEnd(pc - 3 * kInstrSize, &access)) { |
+ len = (access == ConstantPoolEntry::OVERFLOWED) ? 2 : 1; |
+ } else { |
+ len = kMovInstructionsNoConstantPool; |
+ } |
+ return pc - (len + 2) * kInstrSize; |
} |
Address Assembler::return_address_from_call_start(Address pc) { |
- return pc + (kMovInstructions + 2) * kInstrSize; |
+ int len; |
+ ConstantPoolEntry::Access access; |
+ if (FLAG_enable_embedded_constant_pool && |
+ IsConstantPoolLoadStart(pc, &access)) { |
+ len = (access == ConstantPoolEntry::OVERFLOWED) ? 2 : 1; |
+ } else { |
+ len = kMovInstructionsNoConstantPool; |
+ } |
+ return pc + (len + 2) * kInstrSize; |
} |
@@ -226,8 +257,10 @@ void RelocInfo::set_target_cell(Cell* cell, WriteBarrierMode write_barrier_mode, |
} |
-static const int kNoCodeAgeInstructions = 6; |
-static const int kCodeAgingInstructions = Assembler::kMovInstructions + 3; |
+static const int kNoCodeAgeInstructions = |
+ FLAG_enable_embedded_constant_pool ? 7 : 6; |
+static const int kCodeAgingInstructions = |
+ Assembler::kMovInstructionsNoConstantPool + 3; |
static const int kNoCodeAgeSequenceInstructions = |
((kNoCodeAgeInstructions >= kCodeAgingInstructions) |
? kNoCodeAgeInstructions |
@@ -448,8 +481,14 @@ bool Operand::is_reg() const { return rm_.is_valid(); } |
// Fetch the 32bit value from the FIXED_SEQUENCE lis/ori |
-Address Assembler::target_address_at(Address pc, |
- ConstantPoolArray* constant_pool) { |
+Address Assembler::target_address_at(Address pc, Address constant_pool) { |
+ if (FLAG_enable_embedded_constant_pool && constant_pool) { |
+ ConstantPoolEntry::Access access; |
+ if (IsConstantPoolLoadStart(pc, &access)) |
+ return Memory::Address_at(target_constant_pool_address_at( |
+ pc, constant_pool, access, ConstantPoolEntry::INTPTR)); |
+ } |
+ |
Instr instr1 = instr_at(pc); |
Instr instr2 = instr_at(pc + kInstrSize); |
// Interpret 2 instructions generated by lis/ori |
@@ -475,6 +514,124 @@ Address Assembler::target_address_at(Address pc, |
} |
+#if V8_TARGET_ARCH_PPC64 |
+const int kLoadIntptrOpcode = LD; |
+#else |
+const int kLoadIntptrOpcode = LWZ; |
+#endif |
+ |
+// Constant pool load sequence detection: |
+// 1) REGULAR access: |
+// load <dst>, kConstantPoolRegister + <offset> |
+// |
+// 2) OVERFLOWED access: |
+// addis <scratch>, kConstantPoolRegister, <offset_high> |
+// load <dst>, <scratch> + <offset_low> |
+bool Assembler::IsConstantPoolLoadStart(Address pc, |
+ ConstantPoolEntry::Access* access) { |
+ Instr instr = instr_at(pc); |
+ int opcode = instr & kOpcodeMask; |
+ if (!GetRA(instr).is(kConstantPoolRegister)) return false; |
+ bool overflowed = (opcode == ADDIS); |
+#ifdef DEBUG |
+ if (overflowed) { |
+ opcode = instr_at(pc + kInstrSize) & kOpcodeMask; |
+ } |
+ DCHECK(opcode == kLoadIntptrOpcode || opcode == LFD); |
+#endif |
+ if (access) { |
+ *access = (overflowed ? ConstantPoolEntry::OVERFLOWED |
+ : ConstantPoolEntry::REGULAR); |
+ } |
+ return true; |
+} |
+ |
+ |
+bool Assembler::IsConstantPoolLoadEnd(Address pc, |
+ ConstantPoolEntry::Access* access) { |
+ Instr instr = instr_at(pc); |
+ int opcode = instr & kOpcodeMask; |
+ if (!(opcode == kLoadIntptrOpcode || opcode == LFD)) return false; |
+ bool overflowed = !GetRA(instr).is(kConstantPoolRegister); |
+#ifdef DEBUG |
+ if (overflowed) { |
+ instr = instr_at(pc - kInstrSize); |
+ opcode = instr & kOpcodeMask; |
+ DCHECK((opcode == ADDIS) && GetRA(instr).is(kConstantPoolRegister)); |
+ } |
+#endif |
+ if (access) { |
+ *access = (overflowed ? ConstantPoolEntry::OVERFLOWED |
+ : ConstantPoolEntry::REGULAR); |
+ } |
+ return true; |
+} |
+ |
+ |
+int Assembler::GetConstantPoolOffset(Address pc, |
+ ConstantPoolEntry::Access access, |
+ ConstantPoolEntry::Type type) { |
+ bool overflowed = (access == ConstantPoolEntry::OVERFLOWED); |
+#ifdef DEBUG |
+ ConstantPoolEntry::Access access_check; |
+ DCHECK(IsConstantPoolLoadStart(pc, &access_check)); |
+ DCHECK(access_check == access); |
+#endif |
+ int offset; |
+ if (overflowed) { |
+ offset = (instr_at(pc) & kImm16Mask) << 16; |
+ offset += SIGN_EXT_IMM16(instr_at(pc + kInstrSize) & kImm16Mask); |
+ DCHECK(!is_int16(offset)); |
+ } else { |
+ offset = SIGN_EXT_IMM16((instr_at(pc) & kImm16Mask)); |
+ } |
+ return offset; |
+} |
+ |
+ |
+void Assembler::PatchConstantPoolAccessInstruction( |
+ int pc_offset, int offset, ConstantPoolEntry::Access access, |
+ ConstantPoolEntry::Type type) { |
+ Address pc = buffer_ + pc_offset; |
+ bool overflowed = (access == ConstantPoolEntry::OVERFLOWED); |
+#ifdef DEBUG |
+ ConstantPoolEntry::Access access_check; |
+ DCHECK(IsConstantPoolLoadStart(pc, &access_check)); |
+ DCHECK(access_check == access); |
+ DCHECK(overflowed != is_int16(offset)); |
+#endif |
+ if (overflowed) { |
+ int hi_word = static_cast<int>(offset >> 16); |
+ int lo_word = static_cast<int>(offset & 0xffff); |
+ if (lo_word & 0x8000) hi_word++; |
+ |
+ Instr instr1 = instr_at(pc); |
+ Instr instr2 = instr_at(pc + kInstrSize); |
+ instr1 &= ~kImm16Mask; |
+ instr1 |= (hi_word & kImm16Mask); |
+ instr2 &= ~kImm16Mask; |
+ instr2 |= (lo_word & kImm16Mask); |
+ instr_at_put(pc, instr1); |
+ instr_at_put(pc + kInstrSize, instr2); |
+ } else { |
+ Instr instr = instr_at(pc); |
+ instr &= ~kImm16Mask; |
+ instr |= (offset & kImm16Mask); |
+ instr_at_put(pc, instr); |
+ } |
+} |
+ |
+ |
+Address Assembler::target_constant_pool_address_at( |
+ Address pc, Address constant_pool, ConstantPoolEntry::Access access, |
+ ConstantPoolEntry::Type type) { |
+ Address addr = constant_pool; |
+ DCHECK(addr); |
+ addr += GetConstantPoolOffset(pc, access, type); |
+ return addr; |
+} |
+ |
+ |
// This sets the branch destination (which gets loaded at the call address). |
// This is for calls and branches within generated code. The serializer |
// has already deserialized the mov instructions etc. |
@@ -497,10 +654,18 @@ void Assembler::deserialization_set_target_internal_reference_at( |
// This code assumes the FIXED_SEQUENCE of lis/ori |
-void Assembler::set_target_address_at(Address pc, |
- ConstantPoolArray* constant_pool, |
+void Assembler::set_target_address_at(Address pc, Address constant_pool, |
Address target, |
ICacheFlushMode icache_flush_mode) { |
+ if (FLAG_enable_embedded_constant_pool && constant_pool) { |
+ ConstantPoolEntry::Access access; |
+ if (IsConstantPoolLoadStart(pc, &access)) { |
+ Memory::Address_at(target_constant_pool_address_at( |
+ pc, constant_pool, access, ConstantPoolEntry::INTPTR)) = target; |
+ return; |
+ } |
+ } |
+ |
Instr instr1 = instr_at(pc); |
Instr instr2 = instr_at(pc + kInstrSize); |
// Interpret 2 instructions generated by lis/ori |