Quick: PC-relative loads from dex cache arrays on x86.

Rewrite all PC-relative addressing on x86 and implement
PC-relative loads from dex cache arrays. Don't adjust the
base to point to the start of the method, let it point to
the anchor, i.e. the target of the "call +0" insn.

Change-Id: Ic22544a8bc0c5e49eb00a75154dc8f3ead816989
diff --git a/compiler/linker/x86/relative_patcher_x86.cc b/compiler/linker/x86/relative_patcher_x86.cc
index 246cf11..315585d 100644
--- a/compiler/linker/x86/relative_patcher_x86.cc
+++ b/compiler/linker/x86/relative_patcher_x86.cc
@@ -16,14 +16,43 @@
 
 #include "linker/x86/relative_patcher_x86.h"
 
+#include "compiled_method.h"
+
 namespace art {
 namespace linker {
 
-void X86RelativePatcher::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.";
+void X86RelativePatcher::PatchDexCacheReference(std::vector<uint8_t>* code,
+                                                const LinkerPatch& patch,
+                                                uint32_t patch_offset,
+                                                uint32_t target_offset) {
+  uint32_t anchor_literal_offset = patch.PcInsnOffset();
+  uint32_t literal_offset = patch.LiteralOffset();
+
+  // Check that the anchor points to pop in a "call +0; pop <reg>" sequence.
+  DCHECK_GE(anchor_literal_offset, 5u);
+  DCHECK_LT(anchor_literal_offset, code->size());
+  DCHECK_EQ((*code)[anchor_literal_offset - 5u], 0xe8u);
+  DCHECK_EQ((*code)[anchor_literal_offset - 4u], 0x00u);
+  DCHECK_EQ((*code)[anchor_literal_offset - 3u], 0x00u);
+  DCHECK_EQ((*code)[anchor_literal_offset - 2u], 0x00u);
+  DCHECK_EQ((*code)[anchor_literal_offset - 1u], 0x00u);
+  DCHECK_EQ((*code)[anchor_literal_offset] & 0xf8u, 0x58u);
+
+  // Check that the patched data contains kDummy32BitOffset.
+  constexpr int kDummy32BitOffset = 256;  // Must match X86Mir2Lir::kDummy32BitOffset.
+  DCHECK_LE(literal_offset, code->size());
+  DCHECK_EQ((*code)[literal_offset + 0u], static_cast<uint8_t>(kDummy32BitOffset >> 0));
+  DCHECK_EQ((*code)[literal_offset + 1u], static_cast<uint8_t>(kDummy32BitOffset >> 8));
+  DCHECK_EQ((*code)[literal_offset + 2u], static_cast<uint8_t>(kDummy32BitOffset >> 16));
+  DCHECK_EQ((*code)[literal_offset + 3u], static_cast<uint8_t>(kDummy32BitOffset >> 24));
+
+  // Apply patch.
+  uint32_t anchor_offset = patch_offset - literal_offset + anchor_literal_offset;
+  uint32_t diff = target_offset - anchor_offset;
+  (*code)[literal_offset + 0u] = static_cast<uint8_t>(diff >> 0);
+  (*code)[literal_offset + 1u] = static_cast<uint8_t>(diff >> 8);
+  (*code)[literal_offset + 2u] = static_cast<uint8_t>(diff >> 16);
+  (*code)[literal_offset + 3u] = static_cast<uint8_t>(diff >> 24);
 }
 
 }  // namespace linker