Patch support for the boot image.

Requires oat and image writer support.

Change-Id: Ic87dd481a4f86d15faa1e830ea1dd0b3d664c220
diff --git a/src/compiler.cc b/src/compiler.cc
index 5156122..6a65b69 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -696,10 +696,6 @@
   if (sharp_type != kStatic && sharp_type != kDirect) {
     return;
   }
-  bool compiling_boot = Runtime::Current()->GetHeap()->GetSpaces().size() == 1;
-  if (compiling_boot) {
-    return;
-  }
   bool method_code_in_boot = method->GetDeclaringClass()->GetClassLoader() == NULL;
   if (!method_code_in_boot) {
     return;
@@ -710,10 +706,22 @@
   }
   stats_->DirectCallsToBoot(type);
   stats_->DirectMethodsToBoot(type);
-  if (Runtime::Current()->GetHeap()->GetImageSpace()->Contains(method)) {
-    direct_method = reinterpret_cast<uintptr_t>(method);
+  bool compiling_boot = Runtime::Current()->GetHeap()->GetSpaces().size() == 1;
+  if (compiling_boot) {
+    const bool kSupportBootImageFixup = false;
+    if (kSupportBootImageFixup) {
+      MethodHelper mh(method);
+      if (IsImageClass(mh.GetDeclaringClassDescriptor())) {
+        direct_method = -1;
+      }
+      direct_code = -1;
+    }
+  } else {
+    if (Runtime::Current()->GetHeap()->GetImageSpace()->Contains(method)) {
+      direct_method = reinterpret_cast<uintptr_t>(method);
+    }
+    direct_code = reinterpret_cast<uintptr_t>(method->GetCode());
   }
-  direct_code = reinterpret_cast<uintptr_t>(method->GetCode());
 }
 
 bool Compiler::ComputeInvokeInfo(uint32_t method_idx, OatCompilationUnit* mUnit, InvokeType& type,
@@ -785,6 +793,21 @@
   return false;  // Incomplete knowledge needs slow path.
 }
 
+void Compiler::AddCodePatch(DexCache* dex_cache, const DexFile* dex_file,
+                            uint32_t referrer_method_idx, uint32_t target_method_idx,
+                            size_t literal_offset) {
+  MutexLock mu(compiled_methods_lock_);
+  code_to_patch_.push_back(new PatchInformation(dex_cache, dex_file, referrer_method_idx,
+                                                target_method_idx, literal_offset));
+}
+void Compiler::AddMethodPatch(DexCache* dex_cache, const DexFile* dex_file,
+                              uint32_t referrer_method_idx, uint32_t target_method_idx,
+                              size_t literal_offset) {
+  MutexLock mu(compiled_methods_lock_);
+  methods_to_patch_.push_back(new PatchInformation(dex_cache, dex_file, referrer_method_idx,
+                                                   target_method_idx, literal_offset));
+}
+
 // Return true if the class should be skipped during compilation. We
 // never skip classes in the boot class loader. However, if we have a
 // non-boot class loader and we can resolve the class in the boot
diff --git a/src/compiler.h b/src/compiler.h
index f5f5f9f..b7a04bb 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -117,6 +117,14 @@
   bool ComputeInvokeInfo(uint32_t method_idx, OatCompilationUnit* mUnit, InvokeType& type,
                          int& vtable_idx, uintptr_t& direct_code, uintptr_t& direct_method);
 
+  // Record patch information for later fix up
+  void AddCodePatch(DexCache* dex_cache, const DexFile* dex_file,
+                    uint32_t referrer_method_idx, uint32_t target_method_idx,
+                    size_t literal_offset);
+  void AddMethodPatch(DexCache* dex_cache, const DexFile* dex_file,
+                      uint32_t referrer_method_idx, uint32_t target_method_idx,
+                      size_t literal_offset);
+
 #if defined(ART_USE_LLVM_COMPILER)
   void SetElfFileName(std::string const& filename);
   void SetBitcodeFileName(std::string const& filename);
@@ -173,6 +181,25 @@
   void InsertInvokeStub(bool is_static, const char* shorty,
                         const CompiledInvokeStub* compiled_invoke_stub);
 
+  class PatchInformation {
+   public:
+    PatchInformation(DexCache* dex_cache, const DexFile* dex_file,
+                     uint32_t referrer_method_idx, uint32_t target_method_idx,
+                     size_t literal_offset) :
+                       dex_cache_(dex_cache), dex_file_(dex_file),
+                       referrer_method_idx_(referrer_method_idx),
+                       target_method_idx_(target_method_idx),
+                       literal_offset_(literal_offset) {}
+   private:
+    DexCache* dex_cache_;
+    const DexFile* dex_file_;
+    uint32_t referrer_method_idx_;
+    uint32_t target_method_idx_;
+    size_t literal_offset_;
+  };
+  std::vector<PatchInformation*> code_to_patch_;
+  std::vector<PatchInformation*> methods_to_patch_;
+
   InstructionSet instruction_set_;
 
   typedef std::map<const ClassReference, CompiledClass*> ClassTable;
diff --git a/src/compiler/CompilerIR.h b/src/compiler/CompilerIR.h
index 54d9951..8a3fa09 100644
--- a/src/compiler/CompilerIR.h
+++ b/src/compiler/CompilerIR.h
@@ -298,6 +298,8 @@
     LIR* firstLIRInsn;
     LIR* lastLIRInsn;
     LIR* literalList;                   // Constants
+    LIR* methodLiteralList;             // Method literals requiring patching
+    LIR* codeLiteralList;               // Code literals requiring patching
     LIR* classPointerList;              // Relocatable
     int numClassPointers;
     LIR* chainCellOffsetLIR;
diff --git a/src/compiler/codegen/CodegenUtil.cc b/src/compiler/codegen/CodegenUtil.cc
index cc31b29..8b324ed 100644
--- a/src/compiler/codegen/CodegenUtil.cc
+++ b/src/compiler/codegen/CodegenUtil.cc
@@ -553,8 +553,7 @@
  */
 
 /* Add a 32-bit constant either in the constant pool */
-LIR* addWordData(CompilationUnit* cUnit, LIR* *constantListP,
-                           int value)
+LIR* addWordData(CompilationUnit* cUnit, LIR* *constantListP, int value)
 {
     /* Add the constant to the literal pool */
     if (constantListP) {
@@ -595,11 +594,33 @@
 void installLiteralPools(CompilationUnit* cUnit)
 {
     alignBuffer(cUnit->codeBuffer, cUnit->dataOffset);
-    LIR* dataLIR = (LIR*) cUnit->literalList;
+    LIR* dataLIR = cUnit->literalList;
     while (dataLIR != NULL) {
         pushWord(cUnit->codeBuffer, dataLIR->operands[0]);
         dataLIR = NEXT_LIR(dataLIR);
     }
+    // Push code and method literals, record offsets for the compiler to patch.
+    dataLIR = cUnit->codeLiteralList;
+    if (dataLIR != NULL) {
+        while (dataLIR != NULL) {
+            cUnit->compiler->AddCodePatch(cUnit->dex_cache, cUnit->dex_file,
+                                          cUnit->method_idx,
+                                          dataLIR->operands[0],
+                                          cUnit->codeBuffer.size());
+            pushWord(cUnit->codeBuffer, 0xEBAD9A7C); // value to be patched
+            dataLIR = NEXT_LIR(dataLIR);
+        }
+        dataLIR = cUnit->methodLiteralList;
+        while (dataLIR != NULL) {
+            cUnit->compiler->AddMethodPatch(cUnit->dex_cache, cUnit->dex_file,
+                                            cUnit->method_idx,
+                                            dataLIR->operands[0],
+                                            cUnit->codeBuffer.size());
+            pushWord(cUnit->codeBuffer, 0xEBAD9A7D);  // value to be patched
+            dataLIR = NEXT_LIR(dataLIR);
+        }
+    }
+
 }
 
 /* Write the switch tables to the output stream */
@@ -702,6 +723,8 @@
 int assignLiteralOffset(CompilationUnit* cUnit, int offset)
 {
     offset = assignLiteralOffsetCommon(cUnit->literalList, offset);
+    offset = assignLiteralOffsetCommon(cUnit->codeLiteralList, offset);
+    offset = assignLiteralOffsetCommon(cUnit->methodLiteralList, offset);
     return offset;
 }
 
diff --git a/src/compiler/codegen/GenInvoke.cc b/src/compiler/codegen/GenInvoke.cc
index 2ded800..90e2267 100644
--- a/src/compiler/codegen/GenInvoke.cc
+++ b/src/compiler/codegen/GenInvoke.cc
@@ -94,6 +94,25 @@
     }
 }
 
+void scanMethodLiteralPool(CompilationUnit* cUnit, LIR** methodTarget, LIR** codeTarget, const DexFile* dexFile, uint32_t dexMethodIdx)
+{
+    LIR* curTarget = cUnit->methodLiteralList;
+    LIR* nextTarget = curTarget != NULL ? curTarget->next : NULL;
+    while (curTarget != NULL && nextTarget != NULL) {
+      if (curTarget->operands[0] == (int)dexFile &&
+          nextTarget->operands[0] == (int)dexMethodIdx) {
+        *codeTarget = curTarget;
+        *methodTarget = nextTarget;
+        DCHECK((*codeTarget)->next == *methodTarget);
+        DCHECK_EQ((*codeTarget)->operands[0], (int)dexFile);
+        DCHECK_EQ((*methodTarget)->operands[0], (int)dexMethodIdx);
+        break;
+      }
+      curTarget = nextTarget->next;
+      nextTarget = curTarget != NULL ? curTarget->next : NULL;
+    }
+}
+
 /*
  * Bit of a hack here - in leiu of a real scheduling pass,
  * emit the next instruction in static & direct invoke sequences.
@@ -105,8 +124,36 @@
     if (directCode != 0 && directMethod != 0) {
         switch(state) {
         case 0:  // Get the current Method* [sets rARG0]
-            loadConstant(cUnit, rINVOKE_TGT, directCode);
-            loadConstant(cUnit, rARG0, directMethod);
+            if (directCode != (uintptr_t)-1) {
+                loadConstant(cUnit, rINVOKE_TGT, directCode);
+            } else {
+                LIR* dataTarget = scanLiteralPool(cUnit->codeLiteralList, dexIdx, 0);
+                if (dataTarget == NULL) {
+                    dataTarget = addWordData(cUnit, &cUnit->codeLiteralList, dexIdx);
+                }
+#if defined(TARGET_ARM)
+                LIR* loadPcRel = rawLIR(cUnit, cUnit->currentDalvikOffset,
+                                        kThumb2LdrPcRel12, rINVOKE_TGT, 0, 0, 0, 0, dataTarget);
+                oatAppendLIR(cUnit, loadPcRel);
+#else
+                UNIMPLEMENTED(FATAL) << (void*)dataTarget;
+#endif
+            }
+            if (directMethod != (uintptr_t)-1) {
+                loadConstant(cUnit, rARG0, directMethod);
+            } else {
+                LIR* dataTarget = scanLiteralPool(cUnit->methodLiteralList, dexIdx, 0);
+                if (dataTarget == NULL) {
+                    dataTarget = addWordData(cUnit, &cUnit->methodLiteralList, dexIdx);
+                }
+#if defined(TARGET_ARM)
+                LIR* loadPcRel = rawLIR(cUnit, cUnit->currentDalvikOffset,
+                                        kThumb2LdrPcRel12, rARG0, 0, 0, 0, 0, dataTarget);
+                oatAppendLIR(cUnit, loadPcRel);
+#else
+                UNIMPLEMENTED(FATAL) << (void*)dataTarget;
+#endif
+            }
             break;
         default:
             return -1;
@@ -122,7 +169,21 @@
                 rARG0);
             // Set up direct code if known.
             if (directCode != 0) {
-                loadConstant(cUnit, rINVOKE_TGT, directCode);
+                if (directCode != (uintptr_t)-1) {
+                    loadConstant(cUnit, rINVOKE_TGT, directCode);
+                } else {
+                    LIR* dataTarget = scanLiteralPool(cUnit->codeLiteralList, dexIdx, 0);
+                    if (dataTarget == NULL) {
+                        dataTarget = addWordData(cUnit, &cUnit->codeLiteralList, dexIdx);
+                    }
+#if defined(TARGET_ARM)
+                    LIR* loadPcRel = rawLIR(cUnit, cUnit->currentDalvikOffset,
+                                            kThumb2LdrPcRel12, rINVOKE_TGT, 0, 0, 0, 0, dataTarget);
+                    oatAppendLIR(cUnit, loadPcRel);
+#else
+                    UNIMPLEMENTED(FATAL) << (void*)dataTarget;
+#endif
+                }
             }
             break;
         case 2:  // Grab target method*