Late method resolution.

Change-Id: Ic35348022391c3c11a1d4984b9add7b6ef53aa4c
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index 57dbf15..7c19774 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -2785,6 +2785,39 @@
     << PrettyMethod(callee_method_idx, *dex_file_);
 }
 
+llvm::Value* MethodCompiler::EmitEnsureInitialized(llvm::Value* callee_method_object_addr,
+                                                   uint32_t method_idx,
+                                                   bool is_static,
+                                                   llvm::Value* code_addr) {
+  llvm::FunctionType* method_type = GetFunctionType(method_idx, is_static);
+
+  // TODO: Inline check
+  llvm::Value* runtime_func = irb_.GetRuntime(EnsureInitialized);
+  llvm::Value* result = irb_.CreateCall2(runtime_func,
+                                         callee_method_object_addr,
+                                         irb_.CreatePointerCast(code_addr,
+                                                                irb_.getJObjectTy()));
+  return irb_.CreatePointerCast(result, method_type->getPointerTo());
+}
+
+llvm::Value* MethodCompiler::EmitEnsureResolved(llvm::Value* callee,
+                                                llvm::Value* caller,
+                                                uint32_t dex_method_idx,
+                                                Instruction::Code instr_code) {
+  // TODO: Inline check
+  llvm::Value* runtime_func = irb_.GetRuntime(EnsureResolved);
+  return irb_.CreateCall4(runtime_func,
+                          callee,
+                          caller,
+                          irb_.getInt32(dex_method_idx),
+                          irb_.getInt32(instr_code));
+}
+
+void MethodCompiler::EmitEnsureLink(llvm::Value* method_object_addr) {
+  // TODO: Inline check
+  llvm::Value* runtime_func = irb_.GetRuntime(EnsureLink);
+  irb_.CreateCall(runtime_func, method_object_addr);
+}
 
 void MethodCompiler::EmitInsn_InvokeVirtualSuperSlow(uint32_t dex_pc,
                                                      DecodedInstruction &dec_insn,
@@ -2812,14 +2845,28 @@
 
   EmitUpdateLineNumFromDexPC(dex_pc);
 
-  llvm::Value* callee_method_object_addr =
+  llvm::Value* callee_method_object_addr_ =
       irb_.CreateCall3(runtime_func,
                        callee_method_idx_value, this_addr, method_object_addr);
 
   EmitGuard_ExceptionLandingPad(dex_pc);
 
-  llvm::Value* code_addr =
+  llvm::Value* callee_method_object_addr = EmitEnsureResolved(callee_method_object_addr_,
+                                                              method_object_addr,
+                                                              callee_method_idx,
+                                                              (is_virtual ?
+                                                               Instruction::INVOKE_VIRTUAL :
+                                                               Instruction::INVOKE_SUPER));
+
+  EmitEnsureLink(callee_method_object_addr);
+
+  llvm::Value* code_addr_ =
       EmitLoadCodeAddr(callee_method_object_addr, callee_method_idx, false);
+
+  llvm::Value* code_addr = EmitEnsureInitialized(callee_method_object_addr,
+                                                 callee_method_idx,
+                                                 false,
+                                                 code_addr_);
   // Load the actual parameter
   std::vector<llvm::Value*> args;
   args.push_back(callee_method_object_addr);
@@ -2864,13 +2911,25 @@
     // Load callee method code address (branch destination)
     llvm::Value* vtable_addr = EmitLoadVTableAddr(class_object_addr);
 
-    llvm::Value* method_object_addr =
+    llvm::Value* method_object_addr_ =
       EmitLoadMethodObjectAddrFromVTable(vtable_addr,
                                          callee_method->GetMethodIndex());
 
-    llvm::Value* code_addr =
+    llvm::Value* method_object_addr = EmitEnsureResolved(method_object_addr_,
+                                                         EmitLoadMethodObjectAddr(),
+                                                         callee_method_idx,
+                                                         Instruction::INVOKE_VIRTUAL);
+
+    EmitEnsureLink(method_object_addr);
+
+    llvm::Value* code_addr_ =
       EmitLoadCodeAddr(method_object_addr, callee_method_idx, false);
 
+    llvm::Value* code_addr = EmitEnsureInitialized(method_object_addr,
+                                                   callee_method_idx,
+                                                   false,
+                                                   code_addr_);
+
     // Load actual parameters
     std::vector<llvm::Value*> args;
     args.push_back(method_object_addr);
@@ -2953,14 +3012,26 @@
     // Load method object from virtual table
     llvm::Value* vtable_addr = EmitLoadVTableAddr(super_class_addr);
 
-    llvm::Value* callee_method_object_addr =
+    llvm::Value* callee_method_object_addr_ =
       EmitLoadMethodObjectAddrFromVTable(vtable_addr,
                                          callee_method->GetMethodIndex());
 
-    llvm::Value* code_addr =
+    llvm::Value* callee_method_object_addr = EmitEnsureResolved(callee_method_object_addr_,
+                                                                method_object_addr,
+                                                                callee_method_idx,
+                                                                Instruction::INVOKE_SUPER);
+
+    EmitEnsureLink(callee_method_object_addr);
+
+    llvm::Value* code_addr_ =
       EmitLoadCodeAddr(callee_method_object_addr,
                        callee_method_idx, false);
 
+    llvm::Value* code_addr = EmitEnsureInitialized(callee_method_object_addr,
+                                                   callee_method_idx,
+                                                   false,
+                                                   code_addr_);
+
     // Load actual parameters
     std::vector<llvm::Value*> args;
     args.push_back(callee_method_object_addr);
@@ -3019,12 +3090,25 @@
   llvm::Value* callee_method_object_field_addr =
     EmitLoadDexCacheResolvedMethodFieldAddr(callee_method_idx);
 
-  llvm::Value* callee_method_object_addr =
+  llvm::Value* callee_method_object_addr_ =
     irb_.CreateLoad(callee_method_object_field_addr);
 
-  llvm::Value* code_addr =
+  llvm::Value* callee_method_object_addr = EmitEnsureResolved(callee_method_object_addr_,
+                                                              EmitLoadMethodObjectAddr(),
+                                                              callee_method_idx,
+                                                              Instruction::INVOKE_DIRECT);
+
+  EmitEnsureLink(callee_method_object_addr);
+
+  llvm::Value* code_addr_ =
     EmitLoadCodeAddr(callee_method_object_addr, callee_method_idx, is_static);
 
+  llvm::Value* code_addr = EmitEnsureInitialized(callee_method_object_addr,
+                                                 callee_method_idx,
+                                                 is_static,
+                                                 code_addr_);
+  EmitGuard_ExceptionLandingPad(dex_pc);
+
   // Load the actual parameter
   std::vector<llvm::Value*> args;
 
@@ -3075,15 +3159,27 @@
 
   EmitUpdateLineNumFromDexPC(dex_pc);
 
-  llvm::Value* callee_method_object_addr =
+  llvm::Value* callee_method_object_addr_ =
     irb_.CreateCall3(runtime_func,
                      callee_method_idx_value, this_addr, method_object_addr);
 
   EmitGuard_ExceptionLandingPad(dex_pc);
 
-  llvm::Value* code_addr =
+  llvm::Value* callee_method_object_addr = EmitEnsureResolved(callee_method_object_addr_,
+                                                              method_object_addr,
+                                                              callee_method_idx,
+                                                              Instruction::INVOKE_INTERFACE);
+
+  EmitEnsureLink(callee_method_object_addr);
+
+  llvm::Value* code_addr_ =
     EmitLoadCodeAddr(callee_method_object_addr, callee_method_idx, false);
 
+  llvm::Value* code_addr = EmitEnsureInitialized(callee_method_object_addr,
+                                                 callee_method_idx,
+                                                 false,
+                                                 code_addr_);
+
   // Load the actual parameter
   std::vector<llvm::Value*> args;
   args.push_back(callee_method_object_addr);