oat file patching

Change-Id: Idbbdf19f3a77498d79d043fd33ca12ce39cafbb7
diff --git a/src/class_linker.cc b/src/class_linker.cc
index f15d46f..c65cf7d 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1339,9 +1339,6 @@
 
 const OatFile::OatClass* ClassLinker::GetOatClass(const DexFile& dex_file, const char* descriptor) {
   DCHECK(descriptor != NULL);
-  if (!Runtime::Current()->IsStarted() || Runtime::Current()->UseCompileTimeClassPath()) {
-    return NULL;
-  }
   const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file);
   CHECK(oat_file != NULL) << dex_file.GetLocation() << " " << descriptor;
   const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
@@ -1354,9 +1351,9 @@
   return oat_class;
 }
 
+// Special case to get oat code without overwriting a trampoline.
 const void* ClassLinker::GetOatCodeFor(const Method* method) {
-  // Special case to get oat code without overwriting a trampoline.
-  CHECK(method->GetDeclaringClass()->IsInitializing());
+  CHECK(Runtime::Current()->IsCompiler() || method->GetDeclaringClass()->IsInitializing());
   // Although we overwrite the trampoline of non-static methods, we may get here via the resolution
   // method for direct methods (or virtual methods made direct).
   Class* declaring_class = method->GetDeclaringClass();
@@ -1381,6 +1378,7 @@
   }
   ClassHelper kh(declaring_class);
   UniquePtr<const OatFile::OatClass> oat_class(GetOatClass(kh.GetDexFile(), kh.GetDescriptor()));
+  CHECK(oat_class.get() != NULL);
   return oat_class->GetOatMethod(oat_method_index).GetCode();
 }
 
@@ -1393,11 +1391,12 @@
   if (class_data == NULL) {
     return;  // no fields or methods - for example a marker interface
   }
-  UniquePtr<const OatFile::OatClass> oat_class(GetOatClass(dex_file, kh.GetDescriptor()));
-  if (oat_class.get() == NULL) {
+  if (!Runtime::Current()->IsStarted() || Runtime::Current()->UseCompileTimeClassPath()) {
     // OAT file unavailable
     return;
   }
+  UniquePtr<const OatFile::OatClass> oat_class(GetOatClass(dex_file, kh.GetDescriptor()));
+  CHECK(oat_class.get() != NULL);
   ClassDataItemIterator it(dex_file, class_data);
   // Skip fields
   while (it.HasNextStaticField()) {
@@ -1499,7 +1498,10 @@
     LoadField(dex_file, it, klass, ifield);
   }
 
-  UniquePtr<const OatFile::OatClass> oat_class(GetOatClass(dex_file, descriptor));
+  UniquePtr<const OatFile::OatClass> oat_class;
+  if (Runtime::Current()->IsStarted() && !Runtime::Current()->UseCompileTimeClassPath()) {
+    oat_class.reset(GetOatClass(dex_file, descriptor));
+  }
 
   // Load methods.
   if (it.NumDirectMethods() != 0) {
diff --git a/src/compiler.cc b/src/compiler.cc
index 6a65b69..f066b0a 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -355,6 +355,14 @@
     MutexLock mu(compiled_invoke_stubs_lock_);
     STLDeleteValues(&compiled_invoke_stubs_);
   }
+  {
+    MutexLock mu(compiled_methods_lock_);
+    STLDeleteElements(&code_to_patch_);
+  }
+  {
+    MutexLock mu(compiled_methods_lock_);
+    STLDeleteElements(&methods_to_patch_);
+  }
 #if defined(ART_USE_LLVM_COMPILER)
   CompilerCallbackFn f = FindFunction<CompilerCallbackFn>(MakeCompilerSoName(instruction_set_),
                                                           compiler_library_,
@@ -793,19 +801,37 @@
   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,
+void Compiler::AddCodePatch(DexCache* dex_cache,
+                            const DexFile* dex_file,
+                            uint32_t referrer_method_idx,
+                            uint32_t referrer_access_flags,
+                            uint32_t target_method_idx,
+                            bool target_is_direct,
                             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));
+  code_to_patch_.push_back(new PatchInformation(dex_cache,
+                                                dex_file,
+                                                referrer_method_idx,
+                                                referrer_access_flags,
+                                                target_method_idx,
+                                                target_is_direct,
+                                                literal_offset));
 }
-void Compiler::AddMethodPatch(DexCache* dex_cache, const DexFile* dex_file,
-                              uint32_t referrer_method_idx, uint32_t target_method_idx,
+void Compiler::AddMethodPatch(DexCache* dex_cache,
+                              const DexFile* dex_file,
+                              uint32_t referrer_method_idx,
+                              uint32_t referrer_access_flags,
+                              uint32_t target_method_idx,
+                              bool target_is_direct,
                               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));
+  methods_to_patch_.push_back(new PatchInformation(dex_cache,
+                                                   dex_file,
+                                                   referrer_method_idx,
+                                                   referrer_access_flags,
+                                                   target_method_idx,
+                                                   target_is_direct,
+                                                   literal_offset));
 }
 
 // Return true if the class should be skipped during compilation. We
diff --git a/src/compiler.h b/src/compiler.h
index b7a04bb..cd2b2c8 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -118,11 +118,19 @@
                          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,
+  void AddCodePatch(DexCache* dex_cache,
+                    const DexFile* dex_file,
+                    uint32_t referrer_method_idx,
+                    uint32_t referrer_access_flags,
+                    uint32_t target_method_idx,
+                    bool target_is_direct,
                     size_t literal_offset);
-  void AddMethodPatch(DexCache* dex_cache, const DexFile* dex_file,
-                      uint32_t referrer_method_idx, uint32_t target_method_idx,
+  void AddMethodPatch(DexCache* dex_cache,
+                      const DexFile* dex_file,
+                      uint32_t referrer_method_idx,
+                      uint32_t referrer_access_flags,
+                      uint32_t target_method_idx,
+                      bool target_is_direct,
                       size_t literal_offset);
 
 #if defined(ART_USE_LLVM_COMPILER)
@@ -140,6 +148,66 @@
     return compiler_context_;
   }
 
+  class PatchInformation {
+   public:
+    DexCache* GetDexCache() const {
+      return dex_cache_;
+    }
+    const DexFile& GetDexFile() const {
+      return *dex_file_;
+    }
+    uint32_t GetReferrerMethodIdx() const {
+      return referrer_method_idx_;
+    }
+    bool GetReferrerIsDirect() const {
+      return referrer_is_direct_;
+    }
+    uint32_t GetTargetMethodIdx() const {
+      return target_method_idx_;
+    }
+    bool GetTargetIsDirect() const {
+      return target_is_direct_;
+    }
+    size_t GetLiteralOffset() const {;
+      return literal_offset_;
+    }
+
+   private:
+    PatchInformation(DexCache* dex_cache,
+                     const DexFile* dex_file,
+                     uint32_t referrer_method_idx,
+                     uint32_t referrer_access_flags,
+                     uint32_t target_method_idx,
+                     uint32_t target_is_direct,
+                     size_t literal_offset)
+      : dex_cache_(dex_cache),
+        dex_file_(dex_file),
+        referrer_method_idx_(referrer_method_idx),
+        referrer_is_direct_(Method::IsDirect(referrer_access_flags)),
+        target_method_idx_(target_method_idx),
+        target_is_direct_(target_is_direct),
+        literal_offset_(literal_offset) {
+      CHECK(dex_file_ != NULL);
+    }
+
+    DexCache* dex_cache_;
+    const DexFile* dex_file_;
+    uint32_t referrer_method_idx_;
+    bool referrer_is_direct_;
+    uint32_t target_method_idx_;
+    bool target_is_direct_;
+    size_t literal_offset_;
+
+    friend class Compiler;
+  };
+
+  const std::vector<const PatchInformation*>& GetCodeToPatch() const {
+    return code_to_patch_;
+  }
+  const std::vector<const PatchInformation*>& GetMethodsToPatch() const {
+    return methods_to_patch_;
+  }
+
  private:
 
   // Compute constant code and method pointers when possible
@@ -181,24 +249,8 @@
   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_;
+  std::vector<const PatchInformation*> code_to_patch_;
+  std::vector<const PatchInformation*> methods_to_patch_;
 
   InstructionSet instruction_set_;
 
diff --git a/src/compiler/codegen/CodegenUtil.cc b/src/compiler/codegen/CodegenUtil.cc
index 0226fac..c9c9c5e 100644
--- a/src/compiler/codegen/CodegenUtil.cc
+++ b/src/compiler/codegen/CodegenUtil.cc
@@ -590,6 +590,11 @@
     }
 }
 
+bool IsDirect(int invokeType) {
+  InvokeType type = static_cast<InvokeType>(invokeType);
+  return type == kStatic || type == kDirect;
+}
+
 /* Write the literal pool to the output stream */
 void installLiteralPools(CompilationUnit* cUnit)
 {
@@ -603,20 +608,32 @@
     dataLIR = cUnit->codeLiteralList;
     if (dataLIR != NULL) {
         while (dataLIR != NULL) {
+            uint32_t target = dataLIR->operands[0];
             cUnit->compiler->AddCodePatch(cUnit->dex_cache, cUnit->dex_file,
                                           cUnit->method_idx,
-                                          dataLIR->operands[0],
+                                          cUnit->access_flags,
+                                          target,
+                                          IsDirect(dataLIR->operands[1]),
                                           cUnit->codeBuffer.size());
-            pushWord(cUnit->codeBuffer, 0xEBAD9A7C); // value to be patched
+            const DexFile::MethodId& id = cUnit->dex_file->GetMethodId(target);
+            // unique based on target to ensure code deduplication works
+            uint32_t unique_patch_value = reinterpret_cast<uint32_t>(&id);
+            pushWord(cUnit->codeBuffer, unique_patch_value);
             dataLIR = NEXT_LIR(dataLIR);
         }
         dataLIR = cUnit->methodLiteralList;
         while (dataLIR != NULL) {
+            uint32_t target = dataLIR->operands[0];
             cUnit->compiler->AddMethodPatch(cUnit->dex_cache, cUnit->dex_file,
                                             cUnit->method_idx,
-                                            dataLIR->operands[0],
+                                            cUnit->access_flags,
+                                            target,
+                                            IsDirect(dataLIR->operands[1]),
                                             cUnit->codeBuffer.size());
-            pushWord(cUnit->codeBuffer, 0xEBAD9A7D);  // value to be patched
+            const DexFile::MethodId& id = cUnit->dex_file->GetMethodId(target);
+            // unique based on target to ensure code deduplication works
+            uint32_t unique_patch_value = reinterpret_cast<uint32_t>(&id);
+            pushWord(cUnit->codeBuffer, unique_patch_value);
             dataLIR = NEXT_LIR(dataLIR);
         }
     }
diff --git a/src/compiler/codegen/GenInvoke.cc b/src/compiler/codegen/GenInvoke.cc
index 2810936..4847ef8 100644
--- a/src/compiler/codegen/GenInvoke.cc
+++ b/src/compiler/codegen/GenInvoke.cc
@@ -22,10 +22,9 @@
  * and "op" calls may be used here.
  */
 
-
 typedef int (*NextCallInsn)(CompilationUnit*, MIR*, int, uint32_t dexIdx,
                             uint32_t methodIdx, uintptr_t directCode,
-                            uintptr_t directMethod);
+                            uintptr_t directMethod, InvokeType type);
 /*
  * If there are any ins passed in registers that have not been promoted
  * to a callee-save register, flush them to the frame.  Perform intial
@@ -137,8 +136,13 @@
  */
 int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
                    int state, uint32_t dexIdx, uint32_t unused,
-                   uintptr_t directCode, uintptr_t directMethod)
+                   uintptr_t directCode, uintptr_t directMethod,
+                   InvokeType type)
 {
+#if !defined(TARGET_ARM)
+    directCode = 0;
+    directMethod = 0;
+#endif
     if (directCode != 0 && directMethod != 0) {
         switch(state) {
         case 0:  // Get the current Method* [sets rARG0]
@@ -148,6 +152,7 @@
                 LIR* dataTarget = scanLiteralPool(cUnit->codeLiteralList, dexIdx, 0);
                 if (dataTarget == NULL) {
                     dataTarget = addWordData(cUnit, &cUnit->codeLiteralList, dexIdx);
+                    dataTarget->operands[1] = type;
                 }
 #if defined(TARGET_ARM)
                 LIR* loadPcRel = rawLIR(cUnit, cUnit->currentDalvikOffset,
@@ -163,6 +168,7 @@
                 LIR* dataTarget = scanLiteralPool(cUnit->methodLiteralList, dexIdx, 0);
                 if (dataTarget == NULL) {
                     dataTarget = addWordData(cUnit, &cUnit->methodLiteralList, dexIdx);
+                    dataTarget->operands[1] = type;
                 }
 #if defined(TARGET_ARM)
                 LIR* loadPcRel = rawLIR(cUnit, cUnit->currentDalvikOffset,
@@ -194,6 +200,7 @@
                     LIR* dataTarget = scanLiteralPool(cUnit->codeLiteralList, dexIdx, 0);
                     if (dataTarget == NULL) {
                         dataTarget = addWordData(cUnit, &cUnit->codeLiteralList, dexIdx);
+                        dataTarget->operands[1] = type;
                     }
 #if defined(TARGET_ARM)
                     LIR* loadPcRel = rawLIR(cUnit, cUnit->currentDalvikOffset,
@@ -234,7 +241,7 @@
  */
 int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
                   int state, uint32_t dexIdx, uint32_t methodIdx,
-                  uintptr_t unused, uintptr_t unused2)
+                  uintptr_t unused, uintptr_t unused2, InvokeType unused3)
 {
     RegLocation rlArg;
     /*
@@ -294,7 +301,8 @@
 
 int nextStaticCallInsnSP(CompilationUnit* cUnit, MIR* mir,
                          int state, uint32_t dexIdx, uint32_t methodIdx,
-                         uintptr_t unused, uintptr_t unused2)
+                         uintptr_t unused, uintptr_t unused2,
+                         InvokeType unused3)
 {
   int trampoline = OFFSETOF_MEMBER(Thread, pInvokeStaticTrampolineWithAccessCheck);
   return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
@@ -302,7 +310,7 @@
 
 int nextDirectCallInsnSP(CompilationUnit* cUnit, MIR* mir, int state,
                          uint32_t dexIdx, uint32_t methodIdx, uintptr_t unused,
-                         uintptr_t unused2)
+                         uintptr_t unused2, InvokeType unused3)
 {
   int trampoline = OFFSETOF_MEMBER(Thread, pInvokeDirectTrampolineWithAccessCheck);
   return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
@@ -310,7 +318,7 @@
 
 int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir, int state,
                         uint32_t dexIdx, uint32_t methodIdx, uintptr_t unused,
-                        uintptr_t unused2)
+                        uintptr_t unused2, InvokeType unused3)
 {
   int trampoline = OFFSETOF_MEMBER(Thread, pInvokeSuperTrampolineWithAccessCheck);
   return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
@@ -318,7 +326,7 @@
 
 int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir, int state,
                     uint32_t dexIdx, uint32_t methodIdx, uintptr_t unused,
-                    uintptr_t unused2)
+                    uintptr_t unused2, InvokeType unused3)
 {
   int trampoline = OFFSETOF_MEMBER(Thread, pInvokeVirtualTrampolineWithAccessCheck);
   return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
@@ -330,7 +338,7 @@
  */
 int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir, int state,
                           uint32_t dexIdx, uint32_t unused, uintptr_t unused2,
-                          uintptr_t unused3)
+                          uintptr_t unused3, InvokeType unused4)
 {
   int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline);
   return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
@@ -339,7 +347,7 @@
 int nextInterfaceCallInsnWithAccessCheck(CompilationUnit* cUnit, MIR* mir,
                                          int state, uint32_t dexIdx,
                                          uint32_t unused, uintptr_t unused2,
-                                         uintptr_t unused3)
+                                         uintptr_t unused3, InvokeType unused4)
 {
   int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampolineWithAccessCheck);
   return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
@@ -348,7 +356,7 @@
 int loadArgRegs(CompilationUnit* cUnit, MIR* mir, DecodedInstruction* dInsn,
                 int callState, NextCallInsn nextCallInsn, uint32_t dexIdx,
                 uint32_t methodIdx, uintptr_t directCode,
-                uintptr_t directMethod, bool skipThis)
+                uintptr_t directMethod, InvokeType type, bool skipThis)
 {
 #if !defined(TARGET_X86)
     int lastArgReg = rARG3;
@@ -373,7 +381,7 @@
             loadValueDirectFixed(cUnit, rlArg, nextReg);
         }
         callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
-                                 directCode, directMethod);
+                                 directCode, directMethod, type);
     }
     return callState;
 }
@@ -390,7 +398,7 @@
                          LIR** pcrLabel, NextCallInsn nextCallInsn,
                          uint32_t dexIdx, uint32_t methodIdx,
                          uintptr_t directCode, uintptr_t directMethod,
-                         bool skipThis)
+                         InvokeType type, bool skipThis)
 {
     RegLocation rlArg;
 
@@ -399,7 +407,7 @@
         return callState;
 
     callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
-                             directCode, directMethod);
+                             directCode, directMethod, type);
 
     DCHECK_LE(dInsn->vA, 5U);
     if (dInsn->vA > 3) {
@@ -425,12 +433,13 @@
                 loadWordDisp(cUnit, rSP,
                              oatSRegOffset(cUnit, rlArg.sRegLow) + 4, reg);
                 callState = nextCallInsn(cUnit, mir, callState, dexIdx,
-                                         methodIdx, directCode, directMethod);
+                                         methodIdx, directCode, directMethod,
+                                         type);
             }
             storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
             storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
             callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
-                                     directCode, directMethod);
+                                     directCode, directMethod, type);
             nextUse++;
         }
         // Loop through the rest
@@ -455,7 +464,8 @@
                     loadValueDirectFixed(cUnit, rlArg, lowReg);
                 }
                 callState = nextCallInsn(cUnit, mir, callState, dexIdx,
-                                         methodIdx, directCode, directMethod);
+                                         methodIdx, directCode, directMethod,
+                                         type);
             }
             int outsOffset = (nextUse + 1) * 4;
             if (rlArg.wide) {
@@ -466,13 +476,13 @@
                 nextUse++;
             }
             callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
-                                     directCode, directMethod);
+                                     directCode, directMethod, type);
         }
     }
 
     callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
                             dexIdx, methodIdx, directCode, directMethod,
-                            skipThis);
+                            type, skipThis);
 
     if (pcrLabel) {
         *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), rARG1, mir);
@@ -500,7 +510,7 @@
                        LIR** pcrLabel, NextCallInsn nextCallInsn,
                        uint32_t dexIdx, uint32_t methodIdx,
                        uintptr_t directCode, uintptr_t directMethod,
-                       bool skipThis)
+                       InvokeType type, bool skipThis)
 {
     int firstArg = dInsn->vC;
     int numArgs = dInsn->vA;
@@ -509,7 +519,7 @@
     if (numArgs <= 5)
         return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
                                     nextCallInsn, dexIdx, methodIdx,
-                                    directCode, directMethod, skipThis);
+                                    directCode, directMethod, type, skipThis);
     /*
      * Make sure range list doesn't span the break between in normal
      * Dalvik vRegs and the ins.
@@ -567,32 +577,32 @@
         // Use vldm/vstm pair using rARG3 as a temp
         int regsLeft = std::min(numArgs - 3, 16);
         callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
-                                 directCode, directMethod);
+                                 directCode, directMethod, type);
         opRegRegImm(cUnit, kOpAdd, rARG3, rSP, startOffset);
         LIR* ld = newLIR3(cUnit, kThumb2Vldms, rARG3, fr0, regsLeft);
         //TUNING: loosen barrier
         ld->defMask = ENCODE_ALL;
         setMemRefType(ld, true /* isLoad */, kDalvikReg);
         callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
-                                 directCode, directMethod);
+                                 directCode, directMethod, type);
         opRegRegImm(cUnit, kOpAdd, rARG3, rSP, 4 /* Method* */ + (3 * 4));
         callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
-                                 directCode, directMethod);
+                                 directCode, directMethod, type);
         LIR* st = newLIR3(cUnit, kThumb2Vstms, rARG3, fr0, regsLeft);
         setMemRefType(st, false /* isLoad */, kDalvikReg);
         st->defMask = ENCODE_ALL;
         callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
-                                 directCode, directMethod);
+                                 directCode, directMethod, type);
 
     }
 #endif
 
     callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
                             dexIdx, methodIdx, directCode, directMethod,
-                            skipThis);
+                            type, skipThis);
 
     callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
-                             directCode, directMethod);
+                             directCode, directMethod, type);
     if (pcrLabel) {
         *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), rARG1, mir);
     }
diff --git a/src/compiler/codegen/MethodCodegenDriver.cc b/src/compiler/codegen/MethodCodegenDriver.cc
index 59aa4ca..8f4df47 100644
--- a/src/compiler/codegen/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/MethodCodegenDriver.cc
@@ -55,6 +55,7 @@
 void genInvoke(CompilationUnit* cUnit, MIR* mir, InvokeType type, bool isRange)
 {
     DecodedInstruction* dInsn = &mir->dalvikInsn;
+    InvokeType originalType = type;  // avoiding mutation by ComputeInvokeInfo
     int callState = 0;
     LIR* nullCk;
     LIR** pNullCk = NULL;
@@ -103,16 +104,19 @@
     if (!isRange) {
         callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
                                          nextCallInsn, dexMethodIdx,
-                                         vtableIdx, directCode, directMethod, skipThis);
+                                         vtableIdx, directCode, directMethod,
+                                         originalType, skipThis);
     } else {
         callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
                                        nextCallInsn, dexMethodIdx, vtableIdx,
-                                       directCode, directMethod, skipThis);
+                                       directCode, directMethod, originalType,
+                                       skipThis);
     }
     // Finish up any of the call sequence not interleaved in arg loading
     while (callState >= 0) {
         callState = nextCallInsn(cUnit, mir, callState, dexMethodIdx,
-                                 vtableIdx, directCode, directMethod);
+                                 vtableIdx, directCode, directMethod,
+                                 originalType);
     }
     if (DISPLAY_MISSING_TARGETS) {
         genShowTarget(cUnit);
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index f75aeb7..794c6d2 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -198,16 +198,16 @@
     return image_classes.release();
   }
 
-  bool CreateOatFile(const std::string& boot_image_option,
-                     const std::string& host_prefix,
-                     const std::vector<const DexFile*>& dex_files,
-                     File* oat_file,
+  const Compiler* CreateOatFile(const std::string& boot_image_option,
+                                const std::string& host_prefix,
+                                const std::vector<const DexFile*>& dex_files,
+                                File* oat_file,
 #if defined(ART_USE_LLVM_COMPILER)
-                     std::string const& elf_filename,
-                     std::string const& bitcode_filename,
+                                std::string const& elf_filename,
+                                std::string const& bitcode_filename,
 #endif
-                     bool image,
-                     const std::set<std::string>* image_classes) {
+                                bool image,
+                                const std::set<std::string>* image_classes) {
     // SirtRef and ClassLoader creation needs to come after Runtime::Create
     UniquePtr<SirtRef<ClassLoader> > class_loader(new SirtRef<ClassLoader>(NULL));
     if (class_loader.get() == NULL) {
@@ -225,14 +225,18 @@
       class_loader.get()->reset(PathClassLoader::AllocCompileTime(class_path_files));
     }
 
-    Compiler compiler(instruction_set_, image, thread_count_, support_debugging_, image_classes);
+    UniquePtr<Compiler> compiler(new Compiler(instruction_set_,
+                                              image,
+                                              thread_count_,
+                                              support_debugging_,
+                                              image_classes));
 
 #if defined(ART_USE_LLVM_COMPILER)
-    compiler.SetElfFileName(elf_filename);
-    compiler.SetBitcodeFileName(bitcode_filename);
+    compiler->SetElfFileName(elf_filename);
+    compiler->SetBitcodeFileName(bitcode_filename);
 #endif
 
-    compiler.CompileAll(class_loader->get(), dex_files);
+    compiler->CompileAll(class_loader->get(), dex_files);
 
     std::string image_file_location;
     uint32_t image_file_location_checksum = 0;
@@ -251,20 +255,21 @@
                            dex_files,
                            image_file_location_checksum,
                            image_file_location,
-                           compiler)) {
+                           *compiler.get())) {
       LOG(ERROR) << "Failed to create oat file " << oat_file->name();
-      return false;
+      return NULL;
     }
-    return true;
+    return compiler.release();
   }
 
   bool CreateImageFile(const std::string& image_filename,
                        uintptr_t image_base,
                        const std::set<std::string>* image_classes,
                        const std::string& oat_filename,
-                       const std::string& oat_location) {
+                       const std::string& oat_location,
+                       const Compiler& compiler) {
     ImageWriter image_writer(image_classes);
-    if (!image_writer.Write(image_filename, image_base, oat_filename, oat_location)) {
+    if (!image_writer.Write(image_filename, image_base, oat_filename, oat_location, compiler)) {
       LOG(ERROR) << "Failed to create image file " << image_filename;
       return false;
     }
@@ -704,16 +709,18 @@
     }
   }
 
-  if (!dex2oat->CreateOatFile(boot_image_option,
-                              host_prefix,
-                              dex_files,
-                              oat_file.get(),
+  UniquePtr<const Compiler> compiler(dex2oat->CreateOatFile(boot_image_option,
+                                                            host_prefix,
+                                                            dex_files,
+                                                            oat_file.get(),
 #if defined(ART_USE_LLVM_COMPILER)
-                              elf_filename,
-                              bitcode_filename,
+                                                            elf_filename,
+                                                            bitcode_filename,
 #endif
-                              image,
-                              image_classes.get())) {
+                                                            image,
+                                                            image_classes.get()));
+
+  if (compiler.get() == NULL) {
     LOG(ERROR) << "Failed to create oat file: " << oat_location;
     return EXIT_FAILURE;
   }
@@ -730,7 +737,8 @@
                                 image_base,
                                 image_classes.get(),
                                 oat_filename,
-                                oat_location)) {
+                                oat_location,
+                                *compiler.get())) {
     return EXIT_FAILURE;
   }
 
diff --git a/src/image_test.cc b/src/image_test.cc
index cf7c876..5662239 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -49,7 +49,8 @@
   ScratchFile tmp_image;
   const uintptr_t requested_image_base = 0x60000000;
   bool success_image = writer.Write(tmp_image.GetFilename(), requested_image_base,
-                                    tmp_oat.GetFilename(), tmp_oat.GetFilename());
+                                    tmp_oat.GetFilename(), tmp_oat.GetFilename(),
+                                    *compiler_.get());
   ASSERT_TRUE(success_image);
 
   {
diff --git a/src/image_writer.cc b/src/image_writer.cc
index 40f5d5f..fdee834 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -24,6 +24,7 @@
 #include "class_linker.h"
 #include "class_loader.h"
 #include "compiled_method.h"
+#include "compiler.h"
 #include "dex_cache.h"
 #include "file.h"
 #include "globals.h"
@@ -42,7 +43,8 @@
 bool ImageWriter::Write(const std::string& image_filename,
                         uintptr_t image_begin,
                         const std::string& oat_filename,
-                        const std::string& oat_location) {
+                        const std::string& oat_location,
+                        const Compiler& compiler) {
   CHECK(!image_filename.empty());
 
   CHECK_NE(image_begin, 0U);
@@ -60,11 +62,12 @@
     }
   }
 
-  oat_file_.reset(OatFile::Open(oat_filename, oat_location, NULL));
-  if (oat_file_.get() == NULL) {
+  oat_file_ = OatFile::Open(oat_filename, oat_location, NULL, true);
+  if (oat_file_ == NULL) {
     LOG(ERROR) << "Failed to open oat file " << oat_filename;
     return false;
   }
+   class_linker->RegisterOatFile(*oat_file_);
 
   PruneNonImageClasses();  // Remove junk
   ComputeLazyFieldsForImageClasses();  // Add useful information
@@ -80,6 +83,7 @@
   heap->DisableCardMarking();
   CalculateNewObjectOffsets();
   CopyAndFixupObjects();
+  PatchOatCodeAndMethods(compiler);
 
   UniquePtr<File> file(OS::OpenFile(image_filename.c_str(), true));
   if (file.get() == NULL) {
@@ -529,4 +533,70 @@
   }
 }
 
+static Method* GetReferrerMethod(const Compiler::PatchInformation* patch) {
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  Method* method = class_linker->ResolveMethod(patch->GetDexFile(),
+                                               patch->GetReferrerMethodIdx(),
+                                               patch->GetDexCache(),
+                                               NULL,
+                                               patch->GetReferrerIsDirect());
+  CHECK(method != NULL)
+    << patch->GetDexFile().GetLocation() << " " << patch->GetReferrerMethodIdx();
+  return method;
+}
+
+static Method* GetTargetMethod(const Compiler::PatchInformation* patch) {
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  Method* method = class_linker->ResolveMethod(patch->GetDexFile(),
+                                               patch->GetTargetMethodIdx(),
+                                               patch->GetDexCache(),
+                                               NULL,
+                                               patch->GetTargetIsDirect());
+  CHECK(method != NULL)
+    << patch->GetDexFile().GetLocation() << " " << patch->GetTargetMethodIdx();
+  return method;
+}
+
+void ImageWriter::PatchOatCodeAndMethods(const Compiler& compiler) {
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+
+  const std::vector<const Compiler::PatchInformation*>& code_to_patch = compiler.GetCodeToPatch();
+  for (size_t i = 0; i < code_to_patch.size(); i++) {
+    const Compiler::PatchInformation* patch = code_to_patch[i];
+    Method* target = GetTargetMethod(patch);
+    uint32_t code = reinterpret_cast<uint32_t>(class_linker->GetOatCodeFor(target));
+    uint32_t code_base = reinterpret_cast<uint32_t>(&oat_file_->GetOatHeader());
+    uint32_t code_offset = code - code_base;
+    SetPatchLocation(patch, reinterpret_cast<uint32_t>(GetOatAddress(code_offset)));
+  }
+
+  const std::vector<const Compiler::PatchInformation*>& methods_to_patch
+      = compiler.GetMethodsToPatch();
+  for (size_t i = 0; i < methods_to_patch.size(); i++) {
+    const Compiler::PatchInformation* patch = methods_to_patch[i];
+    Method* target = GetTargetMethod(patch);
+    SetPatchLocation(patch, reinterpret_cast<uint32_t>(GetImageAddress(target)));
+  }
+}
+
+void ImageWriter::SetPatchLocation(const Compiler::PatchInformation* patch, uint32_t value) {
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  Method* method = GetReferrerMethod(patch);
+  // Goodbye const, we are about to modify some code.
+  void* code = const_cast<void*>(class_linker->GetOatCodeFor(method));
+  // TODO: make this Thumb2 specific
+  uint8_t* base = reinterpret_cast<uint8_t*>(reinterpret_cast<uint32_t>(code) & ~0x1);
+  uint32_t* patch_location = reinterpret_cast<uint32_t*>(base + patch->GetLiteralOffset());
+#ifndef NDEBUG
+  const DexFile::MethodId& id = patch->GetDexFile().GetMethodId(patch->GetTargetMethodIdx());
+  uint32_t expected = reinterpret_cast<uint32_t>(&id);
+  uint32_t actual = *patch_location;
+  CHECK(actual == expected || actual == value) << std::hex
+    << "actual=" << actual
+    << "expected=" << expected
+    << "value=" << value;
+#endif
+   *patch_location = value;
+}
+
 }  // namespace art
diff --git a/src/image_writer.h b/src/image_writer.h
index 35a3c02..f62bea1 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -24,6 +24,7 @@
 #include <set>
 #include <string>
 
+#include "compiler.h"
 #include "dex_cache.h"
 #include "mem_map.h"
 #include "oat_file.h"
@@ -46,7 +47,8 @@
   bool Write(const std::string& image_filename,
              uintptr_t image_begin,
              const std::string& oat_filename,
-             const std::string& oat_location);
+             const std::string& oat_location,
+             const Compiler& compiler);
  private:
 
   bool AllocMemory();
@@ -137,10 +139,13 @@
   void FixupStaticFields(const Class* orig, Class* copy);
   void FixupFields(const Object* orig, Object* copy, uint32_t ref_offsets, bool is_static);
 
+  void PatchOatCodeAndMethods(const Compiler& compiler);
+  void SetPatchLocation(const Compiler::PatchInformation* patch, uint32_t value);
+
   std::map<const Object*, size_t> offsets_;
 
   // oat file with code for this image
-  UniquePtr<OatFile> oat_file_;
+  OatFile* oat_file_;
 
   // Space we are writing objects from
   const Space* source_space_;
diff --git a/src/oat_file.cc b/src/oat_file.cc
index e72944e..6ae502c 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -33,20 +33,22 @@
 
 OatFile* OatFile::Open(const std::string& filename,
                        const std::string& location,
-                       byte* requested_base) {
+                       byte* requested_base,
+                       bool writable) {
   CHECK(!location.empty()) << filename;
-  UniquePtr<File> file(OS::OpenFile(filename.c_str(), false));
+  UniquePtr<File> file(OS::OpenFile(filename.c_str(), writable, false));
   if (file.get() == NULL) {
-    return false;
+    return NULL;
   }
-  return Open(*file.get(), location, requested_base);
+  return Open(*file.get(), location, requested_base, writable);
 }
 
 OatFile* OatFile::Open(File& file,
                        const std::string& location,
-                       byte* requested_base) {
+                       byte* requested_base,
+                       bool writable) {
   UniquePtr<OatFile> oat_file(new OatFile(location));
-  bool success = oat_file->Read(file, requested_base);
+  bool success = oat_file->Map(file, requested_base, writable);
   if (!success) {
     return NULL;
   }
@@ -61,7 +63,7 @@
   STLDeleteValues(&oat_dex_files_);
 }
 
-bool OatFile::Read(File& file, byte* requested_base) {
+bool OatFile::Map(File& file, byte* requested_base, bool writable) {
 
   OatHeader oat_header;
   bool success = file.ReadFully(&oat_header, sizeof(oat_header));
@@ -70,10 +72,21 @@
     return false;
   }
 
-  int flags = MAP_PRIVATE | ((requested_base != NULL) ? MAP_FIXED : 0);
+  int flags = 0;
+  int prot = 0;
+  if (writable) {
+    flags |= MAP_SHARED;  // So changes will write through to file
+    prot |= (PROT_READ | PROT_WRITE);
+  } else {
+    flags |= MAP_PRIVATE;
+    prot |= PROT_READ;
+  }
+  if (requested_base != NULL) {
+    flags |= MAP_FIXED;
+  }
   UniquePtr<MemMap> map(MemMap::MapFileAtAddress(requested_base,
                                                  file.Length(),
-                                                 PROT_READ,
+                                                 prot,
                                                  flags,
                                                  file.Fd(),
                                                  0));
@@ -89,7 +102,7 @@
   if (code_offset < file.Length()) {
     byte* code_address = map->Begin() + code_offset;
     size_t code_length = file.Length() - code_offset;
-    if (mprotect(code_address, code_length, PROT_READ | PROT_EXEC) != 0) {
+    if (mprotect(code_address, code_length, prot | PROT_EXEC) != 0) {
       PLOG(ERROR) << "Failed to make oat code executable in " << GetLocation();
       return false;
     }
diff --git a/src/oat_file.h b/src/oat_file.h
index 9fcba2f..d75c7c7 100644
--- a/src/oat_file.h
+++ b/src/oat_file.h
@@ -37,12 +37,14 @@
   // optionally be used to request where the file should be loaded.
   static OatFile* Open(const std::string& filename,
                        const std::string& location,
-                       byte* requested_base);
+                       byte* requested_base,
+                       bool writable=false);
 
   // Open an oat file from an already opened File with the given location.
   static OatFile* Open(File& file,
                        const std::string& location,
-                       byte* requested_base);
+                       byte* requested_base,
+                       bool writable=false);
 
   ~OatFile();
 
@@ -219,7 +221,7 @@
 
  private:
   explicit OatFile(const std::string& filename);
-  bool Read(File& file, byte* requested_base);
+  bool Map(File& file, byte* requested_base, bool writable);
 
   const byte* Begin() const;
   const byte* End() const;
diff --git a/src/object.h b/src/object.h
index a609433..62d5fed 100644
--- a/src/object.h
+++ b/src/object.h
@@ -529,7 +529,11 @@
 
   // Returns true if the method is static, private, or a constructor.
   bool IsDirect() const {
-    return IsStatic() || IsPrivate() || IsConstructor();
+    return IsDirect(GetAccessFlags());
+  }
+
+  static bool IsDirect(uint32_t access_flags) {
+    return (access_flags & (kAccStatic | kAccPrivate | kAccConstructor)) != 0;
   }
 
   // Returns true if the method is declared synchronized.
diff --git a/src/os.h b/src/os.h
index e73d9ff..3d7c0fa 100644
--- a/src/os.h
+++ b/src/os.h
@@ -27,7 +27,7 @@
  public:
 
   // Open a file. The returned file must be deleted by the caller.
-  static File* OpenFile(const char* name, bool writable);
+  static File* OpenFile(const char* name, bool writable, bool create=true);
 
   // Create a file from an already open file descriptor
   static File* FileFromFd(const char* name, int fd);
diff --git a/src/os_linux.cc b/src/os_linux.cc
index 5974c00..b91f1ff 100644
--- a/src/os_linux.cc
+++ b/src/os_linux.cc
@@ -25,10 +25,15 @@
 
 namespace art {
 
-File* OS::OpenFile(const char* name, bool writable) {
-  int flags = O_RDONLY;
+File* OS::OpenFile(const char* name, bool writable, bool create) {
+  int flags = 0;
   if (writable) {
-    flags = (O_RDWR | O_CREAT | O_TRUNC);
+    flags |= O_RDWR;
+    if (create) {
+      flags |= (O_CREAT | O_TRUNC);
+    }
+  } else {
+    flags |= O_RDONLY;
   }
   int fd = open(name, flags, 0666);
   if (fd < 0) {