[presubmit] Enable readability/namespace linter checking.
[platform/upstream/v8.git] / src / ppc / assembler-ppc-inl.h
index 7ae8988..4f6a35d 100644 (file)
@@ -40,7 +40,7 @@
 #include "src/ppc/assembler-ppc.h"
 
 #include "src/assembler.h"
-#include "src/debug.h"
+#include "src/debug/debug.h"
 
 
 namespace v8 {
@@ -50,15 +50,40 @@ namespace internal {
 bool CpuFeatures::SupportsCrankshaft() { return true; }
 
 
-void RelocInfo::apply(intptr_t delta, ICacheFlushMode icache_flush_mode) {
-  if (IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_)) {
-    // absolute code pointer inside code object moves with the code object.
-    Assembler::RelocateInternalReference(pc_, delta, 0, rmode_,
-                                         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
+    Address target = Memory::Address_at(pc_);
+    Memory::Address_at(pc_) = target + delta;
+  } else {
+    // mov sequence
+    DCHECK(IsInternalReferenceEncoded(rmode_));
+    Address target = Assembler::target_address_at(pc_, host_);
+    Assembler::set_target_address_at(pc_, host_, target + delta,
+                                     SKIP_ICACHE_FLUSH);
   }
 }
 
 
+Address RelocInfo::target_internal_reference() {
+  if (IsInternalReference(rmode_)) {
+    // Jump table entry
+    return Memory::Address_at(pc_);
+  } else {
+    // mov sequence
+    DCHECK(IsInternalReferenceEncoded(rmode_));
+    return Assembler::target_address_at(pc_, host_);
+  }
+}
+
+
+Address RelocInfo::target_internal_reference_address() {
+  DCHECK(IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_));
+  return reinterpret_cast<Address>(pc_);
+}
+
+
 Address RelocInfo::target_address() {
   DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
   return Assembler::target_address_at(pc_, host_);
@@ -69,6 +94,14 @@ 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 embedded 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.
@@ -83,6 +116,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;
 }
@@ -105,11 +146,6 @@ void RelocInfo::set_target_address(Address target,
 }
 
 
-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.
@@ -118,12 +154,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;
 }
 
 
@@ -154,7 +206,7 @@ void RelocInfo::set_target_object(Object* target,
 }
 
 
-Address RelocInfo::target_reference() {
+Address RelocInfo::target_external_reference() {
   DCHECK(rmode_ == EXTERNAL_REFERENCE);
   return Assembler::target_address_at(pc_, host_);
 }
@@ -201,8 +253,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
@@ -238,19 +292,14 @@ void RelocInfo::set_code_age_stub(Code* stub,
 }
 
 
-Address RelocInfo::call_address() {
-  DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
-         (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
-  // The pc_ offset of 0 assumes patched return sequence per
-  // BreakLocationIterator::SetDebugBreakAtReturn(), or debug break
-  // slot per BreakLocationIterator::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);
@@ -260,32 +309,27 @@ void RelocInfo::set_call_address(Address 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_));
-  Assembler::set_target_address_at(pc_, host_, NULL);
+         IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) ||
+         IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_));
+  if (IsInternalReference(rmode_)) {
+    // Jump table entry
+    Memory::Address_at(pc_) = NULL;
+  } else if (IsInternalReferenceEncoded(rmode_)) {
+    // mov sequence
+    // Currently used only by deserializer, no need to flush.
+    Assembler::set_target_address_at(pc_, host_, NULL, SKIP_ICACHE_FLUSH);
+  } else {
+    Assembler::set_target_address_at(pc_, host_, NULL);
+  }
 }
 
 
 bool RelocInfo::IsPatchedReturnSequence() {
   //
   // The patched return sequence is defined by
-  // BreakLocationIterator::SetDebugBreakAtReturn()
+  // BreakLocation::SetDebugBreakAtReturn()
   // FIXED_SEQUENCE
 
   Instr instr0 = Assembler::instr_at(pc_);
@@ -325,12 +369,13 @@ void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
     visitor->VisitCell(this);
   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
     visitor->VisitExternalReference(this);
+  } else if (mode == RelocInfo::INTERNAL_REFERENCE ||
+             mode == RelocInfo::INTERNAL_REFERENCE_ENCODED) {
+    visitor->VisitInternalReference(this);
   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
     visitor->VisitCodeAgeSequence(this);
-  } else if (((RelocInfo::IsJSReturn(mode) && IsPatchedReturnSequence()) ||
-              (RelocInfo::IsDebugBreakSlot(mode) &&
-               IsPatchedDebugBreakSlotSequence())) &&
-             isolate->debug()->has_break_points()) {
+  } else if (RelocInfo::IsDebugBreakSlot(mode) &&
+             IsPatchedDebugBreakSlotSequence()) {
     visitor->VisitDebugTarget(this);
   } else if (IsRuntimeEntry(mode)) {
     visitor->VisitRuntimeEntry(this);
@@ -349,12 +394,13 @@ void RelocInfo::Visit(Heap* heap) {
     StaticVisitor::VisitCell(heap, this);
   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
     StaticVisitor::VisitExternalReference(this);
+  } else if (mode == RelocInfo::INTERNAL_REFERENCE ||
+             mode == RelocInfo::INTERNAL_REFERENCE_ENCODED) {
+    StaticVisitor::VisitInternalReference(this);
   } 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()))) {
+  } else if (RelocInfo::IsDebugBreakSlot(mode) &&
+             IsPatchedDebugBreakSlotSequence()) {
     StaticVisitor::VisitDebugTarget(heap, this);
   } else if (IsRuntimeEntry(mode)) {
     StaticVisitor::VisitRuntimeEntry(this);
@@ -390,8 +436,33 @@ void Assembler::CheckBuffer() {
   }
 }
 
+void Assembler::TrackBranch() {
+  DCHECK(!trampoline_emitted_);
+  int count = tracked_branch_count_++;
+  if (count == 0) {
+    // We leave space (kMaxBlockTrampolineSectionSize)
+    // for BlockTrampolinePoolScope buffer.
+    next_trampoline_check_ =
+        pc_offset() + kMaxCondBranchReach - kMaxBlockTrampolineSectionSize;
+  } else {
+    next_trampoline_check_ -= kTrampolineSlotsSize;
+  }
+}
+
+void Assembler::UntrackBranch() {
+  DCHECK(!trampoline_emitted_);
+  DCHECK(tracked_branch_count_ > 0);
+  int count = --tracked_branch_count_;
+  if (count == 0) {
+    // Reset
+    next_trampoline_check_ = kMaxInt;
+  } else {
+    next_trampoline_check_ += kTrampolineSlotsSize;
+  }
+}
+
 void Assembler::CheckTrampolinePoolQuick() {
-  if (pc_offset() >= next_buffer_check_) {
+  if (pc_offset() >= next_trampoline_check_) {
     CheckTrampolinePool();
   }
 }
@@ -407,8 +478,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
@@ -434,6 +511,127 @@ 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;
+  bool overflowed = false;
+  if (!(opcode == kLoadIntptrOpcode || opcode == LFD)) return false;
+  if (!GetRA(instr).is(kConstantPoolRegister)) {
+    instr = instr_at(pc - kInstrSize);
+    opcode = instr & kOpcodeMask;
+    if ((opcode != ADDIS) || !GetRA(instr).is(kConstantPoolRegister)) {
+      return false;
+    }
+    overflowed = true;
+  }
+  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 =
+      static_cast<ConstantPoolEntry::Access>(-1);
+  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);
+  CHECK(overflowed != is_int16(offset));
+#ifdef DEBUG
+  ConstantPoolEntry::Access access_check =
+      static_cast<ConstantPoolEntry::Access>(-1);
+  DCHECK(IsConstantPoolLoadStart(pc, &access_check));
+  DCHECK(access_check == access);
+#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.
@@ -443,11 +641,31 @@ void Assembler::deserialization_set_special_target_at(
   set_target_address_at(instruction_payload, code, target);
 }
 
+
+void Assembler::deserialization_set_target_internal_reference_at(
+    Address pc, Address target, RelocInfo::Mode mode) {
+  if (RelocInfo::IsInternalReferenceEncoded(mode)) {
+    Code* code = NULL;
+    set_target_address_at(pc, code, target, SKIP_ICACHE_FLUSH);
+  } else {
+    Memory::Address_at(pc) = target;
+  }
+}
+
+
 // 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
@@ -480,7 +698,7 @@ void Assembler::set_target_address_at(Address pc,
     *(p + 3) = instr4;
     *(p + 4) = instr5;
     if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
-      CpuFeatures::FlushICache(p, 5 * kInstrSize);
+      Assembler::FlushICacheWithoutIsolate(p, 5 * kInstrSize);
     }
 #else
     uint32_t* p = reinterpret_cast<uint32_t*>(pc);
@@ -495,14 +713,14 @@ void Assembler::set_target_address_at(Address pc,
     *p = instr1;
     *(p + 1) = instr2;
     if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
-      CpuFeatures::FlushICache(p, 2 * kInstrSize);
+      Assembler::FlushICacheWithoutIsolate(p, 2 * kInstrSize);
     }
 #endif
     return;
   }
   UNREACHABLE();
 }
-}
-}  // namespace v8::internal
+}  // namespace internal
+}  // namespace v8
 
 #endif  // V8_PPC_ASSEMBLER_PPC_INL_H_