PC-relative loads from dex cache arrays for x86-64.

Change-Id: I6cfe22c7e69512b3c0f95b073aaa572db74ec189
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 04f0db6..2c3f982 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -105,9 +105,9 @@
   DISALLOW_COPY_AND_ASSIGN(NoRelativePatcher);
 };
 
-class OatWriter::X86RelativePatcher FINAL : public RelativePatcher {
+class OatWriter::X86BaseRelativePatcher : public RelativePatcher {
  public:
-  X86RelativePatcher() { }
+  X86BaseRelativePatcher() { }
 
   uint32_t ReserveSpace(uint32_t offset,
                         const CompiledMethod* compiled_method ATTRIBUTE_UNUSED) OVERRIDE {
@@ -129,19 +129,42 @@
     reinterpret_cast<unaligned_int32_t*>(&(*code)[literal_offset])[0] = displacement;
   }
 
+ protected:
+  // PC displacement from patch location; the base address of x86/x86-64 relative
+  // calls and x86-64 RIP-relative addressing is the PC of the next instruction and
+  // the patch location is 4 bytes earlier.
+  static constexpr int32_t kPcDisplacement = 4;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(X86BaseRelativePatcher);
+};
+
+class OatWriter::X86RelativePatcher FINAL : public X86BaseRelativePatcher {
+ public:
+  X86RelativePatcher() { }
+
   virtual void PatchDexCacheReference(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
                                       const LinkerPatch& patch ATTRIBUTE_UNUSED,
                                       uint32_t patch_offset ATTRIBUTE_UNUSED,
                                       uint32_t target_offset ATTRIBUTE_UNUSED) {
     LOG(FATAL) << "Unexpected relative dex cache array patch.";
   }
+};
 
- private:
-  // PC displacement from patch location; x86 PC for relative calls points to the next
-  // instruction and the patch location is 4 bytes earlier.
-  static constexpr int32_t kPcDisplacement = 4;
+class OatWriter::X86_64RelativePatcher FINAL : public X86BaseRelativePatcher {
+ public:
+  X86_64RelativePatcher() { }
 
-  DISALLOW_COPY_AND_ASSIGN(X86RelativePatcher);
+  virtual void PatchDexCacheReference(std::vector<uint8_t>* code, const LinkerPatch& patch,
+                                      uint32_t patch_offset, uint32_t target_offset) {
+    DCHECK_LE(patch.LiteralOffset() + 4u, code->size());
+    // Unsigned arithmetic with its well-defined overflow behavior is just fine here.
+    uint32_t displacement = target_offset - patch_offset;
+    displacement -= kPcDisplacement;  // The base PC is at the end of the 4-byte patch.
+
+    typedef __attribute__((__aligned__(1))) int32_t unaligned_int32_t;
+    reinterpret_cast<unaligned_int32_t*>(&(*code)[patch.LiteralOffset()])[0] = displacement;
+  }
 };
 
 class OatWriter::ArmBaseRelativePatcher : public RelativePatcher {
@@ -706,9 +729,11 @@
 
   switch (compiler_driver_->GetInstructionSet()) {
     case kX86:
-    case kX86_64:
       relative_patcher_.reset(new X86RelativePatcher);
       break;
+    case kX86_64:
+      relative_patcher_.reset(new X86_64RelativePatcher);
+      break;
     case kArm:
       // Fall through: we generate Thumb2 code for "arm".
     case kThumb2: