Implement remaining intrinsics.

Change-Id: I75e769ae51acfdb94734a9d91fada9b49dcf2e88
diff --git a/src/compiler_llvm/gbc_expander.cc b/src/compiler_llvm/gbc_expander.cc
index f7b9cf2..8baa58f 100644
--- a/src/compiler_llvm/gbc_expander.cc
+++ b/src/compiler_llvm/gbc_expander.cc
@@ -251,6 +251,7 @@
     llvm::BasicBlock* begin_bb_;
   };
 
+  llvm::Value* EmitLoadConstantClass(uint32_t dex_pc, uint32_t type_idx);
   llvm::Value* EmitLoadStaticStorage(uint32_t dex_pc, uint32_t type_idx);
 
   llvm::Value* Expand_HLIGet(llvm::CallInst& call_inst, JType field_jty);
@@ -262,6 +263,35 @@
   llvm::Value* Expand_HLArrayGet(llvm::CallInst& call_inst, JType field_jty);
   void Expand_HLArrayPut(llvm::CallInst& call_inst, JType field_jty);
 
+  llvm::Value* Expand_ConstString(llvm::CallInst& call_inst);
+  llvm::Value* Expand_ConstClass(llvm::CallInst& call_inst);
+
+  void Expand_MonitorEnter(llvm::CallInst& call_inst);
+  void Expand_MonitorExit(llvm::CallInst& call_inst);
+
+  void Expand_HLCheckCast(llvm::CallInst& call_inst);
+  llvm::Value* Expand_InstanceOf(llvm::CallInst& call_inst);
+
+  llvm::Value* Expand_NewInstance(llvm::CallInst& call_inst);
+
+  llvm::Value* Expand_HLInvoke(llvm::CallInst& call_inst);
+
+  llvm::Value* Expand_OptArrayLength(llvm::CallInst& call_inst);
+  llvm::Value* Expand_NewArray(llvm::CallInst& call_inst);
+  llvm::Value* Expand_HLFilledNewArray(llvm::CallInst& call_inst);
+  void Expand_HLFillArrayData(llvm::CallInst& call_inst);
+
+  llvm::Value* EmitAllocNewArray(uint32_t dex_pc,
+                                 llvm::Value* array_length_value,
+                                 uint32_t type_idx,
+                                 bool is_filled_new_array);
+
+  llvm::Value* EmitCallRuntimeForCalleeMethodObjectAddr(uint32_t callee_method_idx,
+                                                        InvokeType invoke_type,
+                                                        llvm::Value* this_addr,
+                                                        uint32_t dex_pc,
+                                                        bool is_fast_path);
+
   void EmitMarkGCCard(llvm::Value* value, llvm::Value* target_addr);
 
   void EmitUpdateDexPC(uint32_t dex_pc);
@@ -1349,6 +1379,87 @@
   return;
 }
 
+llvm::Value* GBCExpanderPass::EmitLoadConstantClass(uint32_t dex_pc,
+                                                    uint32_t type_idx) {
+  if (!compiler_->CanAccessTypeWithoutChecks(method_idx_, dex_cache_,
+                                             *dex_file_, type_idx)) {
+    llvm::Value* type_idx_value = irb_.getInt32(type_idx);
+
+    llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+    llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
+
+    llvm::Function* runtime_func =
+      irb_.GetRuntime(runtime_support::InitializeTypeAndVerifyAccess);
+
+    EmitUpdateDexPC(dex_pc);
+
+    llvm::Value* type_object_addr =
+      irb_.CreateCall3(runtime_func, type_idx_value, method_object_addr, thread_object_addr);
+
+    EmitGuard_ExceptionLandingPad(dex_pc);
+
+    return type_object_addr;
+
+  } else {
+    // Try to load the class (type) object from the test cache.
+    llvm::Value* type_field_addr =
+      EmitLoadDexCacheResolvedTypeFieldAddr(type_idx);
+
+    llvm::Value* type_object_addr = irb_.CreateLoad(type_field_addr, kTBAAJRuntime);
+
+    if (compiler_->CanAssumeTypeIsPresentInDexCache(dex_cache_, type_idx)) {
+      return type_object_addr;
+    }
+
+    llvm::BasicBlock* block_original = irb_.GetInsertBlock();
+
+    // Test whether class (type) object is in the dex cache or not
+    llvm::Value* equal_null =
+      irb_.CreateICmpEQ(type_object_addr, irb_.getJNull());
+
+    llvm::BasicBlock* block_cont =
+      CreateBasicBlockWithDexPC(dex_pc, "cont");
+
+    llvm::BasicBlock* block_load_class =
+      CreateBasicBlockWithDexPC(dex_pc, "load_class");
+
+    irb_.CreateCondBr(equal_null, block_load_class, block_cont, kUnlikely);
+
+    // Failback routine to load the class object
+    irb_.SetInsertPoint(block_load_class);
+
+    llvm::Function* runtime_func = irb_.GetRuntime(runtime_support::InitializeType);
+
+    llvm::Constant* type_idx_value = irb_.getInt32(type_idx);
+
+    llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+    llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
+
+    EmitUpdateDexPC(dex_pc);
+
+    llvm::Value* loaded_type_object_addr =
+      irb_.CreateCall3(runtime_func, type_idx_value, method_object_addr, thread_object_addr);
+
+    EmitGuard_ExceptionLandingPad(dex_pc);
+
+    llvm::BasicBlock* block_after_load_class = irb_.GetInsertBlock();
+
+    irb_.CreateBr(block_cont);
+
+    // Now the class object must be loaded
+    irb_.SetInsertPoint(block_cont);
+
+    llvm::PHINode* phi = irb_.CreatePHI(irb_.getJObjectTy(), 2);
+
+    phi->addIncoming(type_object_addr, block_original);
+    phi->addIncoming(loaded_type_object_addr, block_after_load_class);
+
+    return phi;
+  }
+}
+
 llvm::Value* GBCExpanderPass::EmitLoadStaticStorage(uint32_t dex_pc,
                                                     uint32_t type_idx) {
   llvm::BasicBlock* block_load_static =
@@ -1565,6 +1676,600 @@
   return;
 }
 
+llvm::Value* GBCExpanderPass::Expand_ConstString(llvm::CallInst& call_inst) {
+  ScopedExpandToBasicBlock eb(irb_, &call_inst);
+
+  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
+  uint32_t string_idx = LV2UInt(call_inst.getArgOperand(0));
+
+  llvm::Value* string_field_addr = EmitLoadDexCacheStringFieldAddr(string_idx);
+
+  llvm::Value* string_addr = irb_.CreateLoad(string_field_addr, kTBAAJRuntime);
+
+  if (!compiler_->CanAssumeStringIsPresentInDexCache(dex_cache_, string_idx)) {
+    llvm::BasicBlock* block_str_exist =
+      CreateBasicBlockWithDexPC(dex_pc, "str_exist");
+
+    llvm::BasicBlock* block_str_resolve =
+      CreateBasicBlockWithDexPC(dex_pc, "str_resolve");
+
+    llvm::BasicBlock* block_cont =
+      CreateBasicBlockWithDexPC(dex_pc, "str_cont");
+
+    // Test: Is the string resolved and in the dex cache?
+    llvm::Value* equal_null = irb_.CreateICmpEQ(string_addr, irb_.getJNull());
+
+    irb_.CreateCondBr(equal_null, block_str_resolve, block_str_exist, kUnlikely);
+
+    // String is resolved, go to next basic block.
+    irb_.SetInsertPoint(block_str_exist);
+    irb_.CreateBr(block_cont);
+
+    // String is not resolved yet, resolve it now.
+    irb_.SetInsertPoint(block_str_resolve);
+
+    llvm::Function* runtime_func = irb_.GetRuntime(runtime_support::ResolveString);
+
+    llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+    llvm::Value* string_idx_value = irb_.getInt32(string_idx);
+
+    EmitUpdateDexPC(dex_pc);
+
+    llvm::Value* result = irb_.CreateCall2(runtime_func, method_object_addr,
+                                           string_idx_value);
+
+    EmitGuard_ExceptionLandingPad(dex_pc);
+
+    llvm::BasicBlock* block_pre_cont = irb_.GetInsertBlock();
+
+    irb_.SetInsertPoint(block_cont);
+
+    llvm::PHINode* phi = irb_.CreatePHI(irb_.getJObjectTy(), 2);
+
+    phi->addIncoming(string_addr, block_str_exist);
+    phi->addIncoming(result, block_pre_cont);
+
+    string_addr = phi;
+  }
+
+  return string_addr;
+}
+
+llvm::Value* GBCExpanderPass::Expand_ConstClass(llvm::CallInst& call_inst) {
+  ScopedExpandToBasicBlock eb(irb_, &call_inst);
+
+  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
+  uint32_t type_idx = LV2UInt(call_inst.getArgOperand(0));
+
+  llvm::Value* type_object_addr = EmitLoadConstantClass(dex_pc, type_idx);
+
+  return type_object_addr;
+}
+
+void GBCExpanderPass::Expand_MonitorEnter(llvm::CallInst& call_inst) {
+  ScopedExpandToBasicBlock eb(irb_, &call_inst);
+
+  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
+  llvm::Value* object_addr = call_inst.getArgOperand(1);
+
+  // TODO: opt_flags
+  EmitGuard_NullPointerException(dex_pc, object_addr);
+
+  irb_.Runtime().EmitLockObject(object_addr);
+
+  return;
+}
+
+void GBCExpanderPass::Expand_MonitorExit(llvm::CallInst& call_inst) {
+  ScopedExpandToBasicBlock eb(irb_, &call_inst);
+
+  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
+  llvm::Value* object_addr = call_inst.getArgOperand(1);
+
+  // TODO: opt_flags
+  EmitGuard_NullPointerException(dex_pc, object_addr);
+
+  EmitUpdateDexPC(dex_pc);
+
+  irb_.Runtime().EmitUnlockObject(object_addr);
+
+  EmitGuard_ExceptionLandingPad(dex_pc);
+
+  return;
+}
+
+void GBCExpanderPass::Expand_HLCheckCast(llvm::CallInst& call_inst) {
+  ScopedExpandToBasicBlock eb(irb_, &call_inst);
+
+  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
+  uint32_t type_idx = LV2UInt(call_inst.getArgOperand(0));
+  llvm::Value* object_addr = call_inst.getArgOperand(1);
+
+  llvm::BasicBlock* block_test_class =
+    CreateBasicBlockWithDexPC(dex_pc, "test_class");
+
+  llvm::BasicBlock* block_test_sub_class =
+    CreateBasicBlockWithDexPC(dex_pc, "test_sub_class");
+
+  llvm::BasicBlock* block_cont =
+    CreateBasicBlockWithDexPC(dex_pc, "checkcast_cont");
+
+  // Test: Is the reference equal to null?  Act as no-op when it is null.
+  llvm::Value* equal_null = irb_.CreateICmpEQ(object_addr, irb_.getJNull());
+
+  irb_.CreateCondBr(equal_null,
+                    block_cont,
+                    block_test_class);
+
+  // Test: Is the object instantiated from the given class?
+  irb_.SetInsertPoint(block_test_class);
+  llvm::Value* type_object_addr = EmitLoadConstantClass(dex_pc, type_idx);
+  DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
+
+  llvm::PointerType* jobject_ptr_ty = irb_.getJObjectTy();
+
+  llvm::Value* object_type_field_addr =
+    irb_.CreateBitCast(object_addr, jobject_ptr_ty->getPointerTo());
+
+  llvm::Value* object_type_object_addr =
+    irb_.CreateLoad(object_type_field_addr, kTBAAConstJObject);
+
+  llvm::Value* equal_class =
+    irb_.CreateICmpEQ(type_object_addr, object_type_object_addr);
+
+  irb_.CreateCondBr(equal_class,
+                    block_cont,
+                    block_test_sub_class);
+
+  // Test: Is the object instantiated from the subclass of the given class?
+  irb_.SetInsertPoint(block_test_sub_class);
+
+  EmitUpdateDexPC(dex_pc);
+
+  irb_.CreateCall2(irb_.GetRuntime(runtime_support::CheckCast),
+                   type_object_addr, object_type_object_addr);
+
+  EmitGuard_ExceptionLandingPad(dex_pc);
+
+  irb_.CreateBr(block_cont);
+
+  irb_.SetInsertPoint(block_cont);
+
+  return;
+}
+
+llvm::Value* GBCExpanderPass::Expand_InstanceOf(llvm::CallInst& call_inst) {
+  ScopedExpandToBasicBlock eb(irb_, &call_inst);
+
+  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
+  uint32_t type_idx = LV2UInt(call_inst.getArgOperand(0));
+  llvm::Value* object_addr = call_inst.getArgOperand(1);
+
+  llvm::BasicBlock* block_nullp =
+      CreateBasicBlockWithDexPC(dex_pc, "nullp");
+
+  llvm::BasicBlock* block_test_class =
+      CreateBasicBlockWithDexPC(dex_pc, "test_class");
+
+  llvm::BasicBlock* block_class_equals =
+      CreateBasicBlockWithDexPC(dex_pc, "class_eq");
+
+  llvm::BasicBlock* block_test_sub_class =
+      CreateBasicBlockWithDexPC(dex_pc, "test_sub_class");
+
+  llvm::BasicBlock* block_cont =
+      CreateBasicBlockWithDexPC(dex_pc, "instance_of_cont");
+
+  // Overview of the following code :
+  // We check for null, if so, then false, otherwise check for class == . If so
+  // then true, otherwise do callout slowpath.
+  //
+  // Test: Is the reference equal to null?  Set 0 when it is null.
+  llvm::Value* equal_null = irb_.CreateICmpEQ(object_addr, irb_.getJNull());
+
+  irb_.CreateCondBr(equal_null, block_nullp, block_test_class);
+
+  irb_.SetInsertPoint(block_nullp);
+  irb_.CreateBr(block_cont);
+
+  // Test: Is the object instantiated from the given class?
+  irb_.SetInsertPoint(block_test_class);
+  llvm::Value* type_object_addr = EmitLoadConstantClass(dex_pc, type_idx);
+  DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
+
+  llvm::PointerType* jobject_ptr_ty = irb_.getJObjectTy();
+
+  llvm::Value* object_type_field_addr =
+    irb_.CreateBitCast(object_addr, jobject_ptr_ty->getPointerTo());
+
+  llvm::Value* object_type_object_addr =
+    irb_.CreateLoad(object_type_field_addr, kTBAAConstJObject);
+
+  llvm::Value* equal_class =
+    irb_.CreateICmpEQ(type_object_addr, object_type_object_addr);
+
+  irb_.CreateCondBr(equal_class, block_class_equals, block_test_sub_class);
+
+  irb_.SetInsertPoint(block_class_equals);
+  irb_.CreateBr(block_cont);
+
+  // Test: Is the object instantiated from the subclass of the given class?
+  irb_.SetInsertPoint(block_test_sub_class);
+  llvm::Value* result =
+    irb_.CreateCall2(irb_.GetRuntime(runtime_support::IsAssignable),
+                     type_object_addr, object_type_object_addr);
+  irb_.CreateBr(block_cont);
+
+  irb_.SetInsertPoint(block_cont);
+
+  llvm::PHINode* phi = irb_.CreatePHI(irb_.getJIntTy(), 3);
+
+  phi->addIncoming(irb_.getJInt(0), block_nullp);
+  phi->addIncoming(irb_.getJInt(1), block_class_equals);
+  phi->addIncoming(result, block_test_sub_class);
+
+  return phi;
+}
+
+llvm::Value* GBCExpanderPass::Expand_NewInstance(llvm::CallInst& call_inst) {
+  ScopedExpandToBasicBlock eb(irb_, &call_inst);
+
+  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
+  uint32_t type_idx = LV2UInt(call_inst.getArgOperand(0));
+
+  llvm::Function* runtime_func;
+  if (compiler_->CanAccessInstantiableTypeWithoutChecks(
+        method_idx_, dex_cache_, *dex_file_, type_idx)) {
+    runtime_func = irb_.GetRuntime(runtime_support::AllocObject);
+  } else {
+    runtime_func = irb_.GetRuntime(runtime_support::AllocObjectWithAccessCheck);
+  }
+
+  llvm::Constant* type_index_value = irb_.getInt32(type_idx);
+
+  llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+  llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
+
+  EmitUpdateDexPC(dex_pc);
+
+  llvm::Value* object_addr =
+    irb_.CreateCall3(runtime_func, type_index_value, method_object_addr, thread_object_addr);
+
+  EmitGuard_ExceptionLandingPad(dex_pc);
+
+  return object_addr;
+}
+
+llvm::Value* GBCExpanderPass::Expand_HLInvoke(llvm::CallInst& call_inst) {
+  ScopedExpandToBasicBlock eb(irb_, &call_inst);
+
+  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
+  InvokeType invoke_type = static_cast<InvokeType>(LV2UInt(call_inst.getArgOperand(0)));
+  bool is_static = (invoke_type == kStatic);
+  uint32_t callee_method_idx = LV2UInt(call_inst.getArgOperand(1));
+
+  // Compute invoke related information for compiler decision
+  int vtable_idx = -1;
+  uintptr_t direct_code = 0;
+  uintptr_t direct_method = 0;
+  bool is_fast_path = compiler_->
+    ComputeInvokeInfo(callee_method_idx, oat_compilation_unit_,
+                      invoke_type, vtable_idx, direct_code, direct_method);
+
+  // Load *this* actual parameter
+  llvm::Value* this_addr = NULL;
+
+  if (!is_static) {
+    // Test: Is *this* parameter equal to null?
+    this_addr = call_inst.getArgOperand(3);
+  }
+
+  // Load the method object
+  llvm::Value* callee_method_object_addr = NULL;
+
+  if (!is_fast_path) {
+    callee_method_object_addr =
+      EmitCallRuntimeForCalleeMethodObjectAddr(callee_method_idx, invoke_type,
+                                               this_addr, dex_pc, is_fast_path);
+
+    // TODO: opt_flags
+    if (!is_static) {
+      EmitGuard_NullPointerException(dex_pc, this_addr);
+    }
+  } else {
+    // TODO: opt_flags
+    if (!is_static) {
+      EmitGuard_NullPointerException(dex_pc, this_addr);
+    }
+
+    switch (invoke_type) {
+    case kStatic:
+    case kDirect:
+      if (direct_method != 0u &&
+          direct_method != static_cast<uintptr_t>(-1)) {
+        callee_method_object_addr =
+          irb_.CreateIntToPtr(irb_.getPtrEquivInt(direct_method),
+                              irb_.getJObjectTy());
+      } else {
+        callee_method_object_addr =
+          EmitLoadSDCalleeMethodObjectAddr(callee_method_idx);
+      }
+      break;
+
+    case kVirtual:
+      DCHECK(vtable_idx != -1);
+      callee_method_object_addr =
+        EmitLoadVirtualCalleeMethodObjectAddr(vtable_idx, this_addr);
+      break;
+
+    case kSuper:
+      LOG(FATAL) << "invoke-super should be promoted to invoke-direct in "
+                    "the fast path.";
+      break;
+
+    case kInterface:
+      callee_method_object_addr =
+        EmitCallRuntimeForCalleeMethodObjectAddr(callee_method_idx,
+                                                 invoke_type, this_addr,
+                                                 dex_pc, is_fast_path);
+      break;
+    }
+  }
+
+  // Load the actual parameter
+  std::vector<llvm::Value*> args;
+
+  args.push_back(callee_method_object_addr); // method object for callee
+
+  for (uint32_t i = 3; i < call_inst.getNumArgOperands(); ++i) {
+    args.push_back(call_inst.getArgOperand(i));
+  }
+
+  llvm::Value* code_addr;
+  if (direct_code != 0u &&
+      direct_code != static_cast<uintptr_t>(-1)) {
+    code_addr =
+      irb_.CreateIntToPtr(irb_.getPtrEquivInt(direct_code),
+                          GetFunctionType(callee_method_idx, is_static)->getPointerTo());
+  } else {
+    code_addr =
+      irb_.LoadFromObjectOffset(callee_method_object_addr,
+                                Method::GetCodeOffset().Int32Value(),
+                                GetFunctionType(callee_method_idx, is_static)->getPointerTo(),
+                                kTBAAJRuntime);
+  }
+
+  // Invoke callee
+  EmitUpdateDexPC(dex_pc);
+  llvm::Value* retval = irb_.CreateCall(code_addr, args);
+  EmitGuard_ExceptionLandingPad(dex_pc);
+
+  return retval;
+}
+
+llvm::Value* GBCExpanderPass::Expand_OptArrayLength(llvm::CallInst& call_inst) {
+  ScopedExpandToBasicBlock eb(irb_, &call_inst);
+
+  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
+  // Get the array object address
+  llvm::Value* array_addr = call_inst.getArgOperand(1);
+
+  // TODO: opt_flags
+  EmitGuard_NullPointerException(dex_pc, array_addr);
+
+  // Get the array length and store it to the register
+  return EmitLoadArrayLength(array_addr);
+}
+
+llvm::Value* GBCExpanderPass::Expand_NewArray(llvm::CallInst& call_inst) {
+  ScopedExpandToBasicBlock eb(irb_, &call_inst);
+
+  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
+  uint32_t type_idx = LV2UInt(call_inst.getArgOperand(0));
+  llvm::Value* length = call_inst.getArgOperand(1);
+
+  return EmitAllocNewArray(dex_pc, length, type_idx, false);
+}
+
+llvm::Value* GBCExpanderPass::Expand_HLFilledNewArray(llvm::CallInst& call_inst) {
+  ScopedExpandToBasicBlock eb(irb_, &call_inst);
+
+  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
+  uint32_t type_idx = LV2UInt(call_inst.getArgOperand(1));
+  uint32_t length = call_inst.getNumArgOperands() - 3;
+
+  llvm::Value* object_addr =
+    EmitAllocNewArray(dex_pc, irb_.getInt32(length), type_idx, true);
+
+  if (length > 0) {
+    // Check for the element type
+    uint32_t type_desc_len = 0;
+    const char* type_desc =
+      dex_file_->StringByTypeIdx(type_idx, &type_desc_len);
+
+    DCHECK_GE(type_desc_len, 2u); // should be guaranteed by verifier
+    DCHECK_EQ(type_desc[0], '['); // should be guaranteed by verifier
+    bool is_elem_int_ty = (type_desc[1] == 'I');
+
+    uint32_t alignment;
+    llvm::Constant* elem_size;
+    llvm::PointerType* field_type;
+
+    // NOTE: Currently filled-new-array only supports 'L', '[', and 'I'
+    // as the element, thus we are only checking 2 cases: primitive int and
+    // non-primitive type.
+    if (is_elem_int_ty) {
+      alignment = sizeof(int32_t);
+      elem_size = irb_.getPtrEquivInt(sizeof(int32_t));
+      field_type = irb_.getJIntTy()->getPointerTo();
+    } else {
+      alignment = irb_.getSizeOfPtrEquivInt();
+      elem_size = irb_.getSizeOfPtrEquivIntValue();
+      field_type = irb_.getJObjectTy()->getPointerTo();
+    }
+
+    llvm::Value* data_field_offset =
+      irb_.getPtrEquivInt(Array::DataOffset(alignment).Int32Value());
+
+    llvm::Value* data_field_addr =
+      irb_.CreatePtrDisp(object_addr, data_field_offset, field_type);
+
+    // TODO: Tune this code.  Currently we are generating one instruction for
+    // one element which may be very space consuming.  Maybe changing to use
+    // memcpy may help; however, since we can't guarantee that the alloca of
+    // dalvik register are continuous, we can't perform such optimization yet.
+    for (uint32_t i = 0; i < length; ++i) {
+      llvm::Value* reg_value = call_inst.getArgOperand(i+3);
+
+      irb_.CreateStore(reg_value, data_field_addr, kTBAAHeapArray);
+
+      data_field_addr =
+        irb_.CreatePtrDisp(data_field_addr, elem_size, field_type);
+    }
+  }
+
+  return object_addr;
+}
+
+void GBCExpanderPass::Expand_HLFillArrayData(llvm::CallInst& call_inst) {
+  ScopedExpandToBasicBlock eb(irb_, &call_inst);
+
+  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
+  int32_t payload_offset = static_cast<int32_t>(dex_pc) +
+                           LV2SInt(call_inst.getArgOperand(0));
+  llvm::Value* array_addr = call_inst.getArgOperand(1);
+
+  const Instruction::ArrayDataPayload* payload =
+    reinterpret_cast<const Instruction::ArrayDataPayload*>(
+        code_item_->insns_ + payload_offset);
+
+  if (payload->element_count == 0) {
+    // When the number of the elements in the payload is zero, we don't have
+    // to copy any numbers.  However, we should check whether the array object
+    // address is equal to null or not.
+    EmitGuard_NullPointerException(dex_pc, array_addr);
+  } else {
+    // To save the code size, we are going to call the runtime function to
+    // copy the content from DexFile.
+
+    // NOTE: We will check for the NullPointerException in the runtime.
+
+    llvm::Function* runtime_func = irb_.GetRuntime(runtime_support::FillArrayData);
+
+    llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+    EmitUpdateDexPC(dex_pc);
+
+    irb_.CreateCall4(runtime_func,
+                     method_object_addr, irb_.getInt32(dex_pc),
+                     array_addr, irb_.getInt32(payload_offset));
+
+    EmitGuard_ExceptionLandingPad(dex_pc);
+  }
+
+  return;
+}
+
+llvm::Value* GBCExpanderPass::EmitAllocNewArray(uint32_t dex_pc,
+                                                llvm::Value* array_length_value,
+                                                uint32_t type_idx,
+                                                bool is_filled_new_array) {
+  llvm::Function* runtime_func;
+
+  bool skip_access_check =
+    compiler_->CanAccessTypeWithoutChecks(method_idx_, dex_cache_,
+                                          *dex_file_, type_idx);
+
+
+  if (is_filled_new_array) {
+    runtime_func = skip_access_check ?
+      irb_.GetRuntime(runtime_support::CheckAndAllocArray) :
+      irb_.GetRuntime(runtime_support::CheckAndAllocArrayWithAccessCheck);
+  } else {
+    runtime_func = skip_access_check ?
+      irb_.GetRuntime(runtime_support::AllocArray) :
+      irb_.GetRuntime(runtime_support::AllocArrayWithAccessCheck);
+  }
+
+  llvm::Constant* type_index_value = irb_.getInt32(type_idx);
+
+  llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+  llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
+
+  EmitUpdateDexPC(dex_pc);
+
+  llvm::Value* object_addr =
+    irb_.CreateCall4(runtime_func, type_index_value, method_object_addr,
+                     array_length_value, thread_object_addr);
+
+  EmitGuard_ExceptionLandingPad(dex_pc);
+
+  return object_addr;
+}
+
+llvm::Value* GBCExpanderPass::
+EmitCallRuntimeForCalleeMethodObjectAddr(uint32_t callee_method_idx,
+                                         InvokeType invoke_type,
+                                         llvm::Value* this_addr,
+                                         uint32_t dex_pc,
+                                         bool is_fast_path) {
+
+  llvm::Function* runtime_func = NULL;
+
+  switch (invoke_type) {
+  case kStatic:
+    runtime_func = irb_.GetRuntime(runtime_support::FindStaticMethodWithAccessCheck);
+    break;
+
+  case kDirect:
+    runtime_func = irb_.GetRuntime(runtime_support::FindDirectMethodWithAccessCheck);
+    break;
+
+  case kVirtual:
+    runtime_func = irb_.GetRuntime(runtime_support::FindVirtualMethodWithAccessCheck);
+    break;
+
+  case kSuper:
+    runtime_func = irb_.GetRuntime(runtime_support::FindSuperMethodWithAccessCheck);
+    break;
+
+  case kInterface:
+    if (is_fast_path) {
+      runtime_func = irb_.GetRuntime(runtime_support::FindInterfaceMethod);
+    } else {
+      runtime_func = irb_.GetRuntime(runtime_support::FindInterfaceMethodWithAccessCheck);
+    }
+    break;
+  }
+
+  llvm::Value* callee_method_idx_value = irb_.getInt32(callee_method_idx);
+
+  if (this_addr == NULL) {
+    DCHECK_EQ(invoke_type, kStatic);
+    this_addr = irb_.getJNull();
+  }
+
+  llvm::Value* caller_method_object_addr = EmitLoadMethodObjectAddr();
+
+  llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
+
+  EmitUpdateDexPC(dex_pc);
+
+  llvm::Value* callee_method_object_addr =
+    irb_.CreateCall4(runtime_func,
+                     callee_method_idx_value,
+                     this_addr,
+                     caller_method_object_addr,
+                     thread_object_addr);
+
+  EmitGuard_ExceptionLandingPad(dex_pc);
+
+  return callee_method_object_addr;
+}
+
 void GBCExpanderPass::EmitMarkGCCard(llvm::Value* value, llvm::Value* target_addr) {
   // Using runtime support, let the target can override by InlineAssembly.
   irb_.Runtime().EmitMarkGCCard(value, target_addr);
@@ -1675,7 +2380,19 @@
   }
 
   for (uint32_t i = 1; i < shorty_size; ++i) {
+#if defined(ART_USE_QUICK_COMPILER)
+    char shorty_type = shorty[i];
+    switch(shorty_type) {
+      case 'Z' : shorty_type = 'I'; break;
+      case 'B' : shorty_type = 'I'; break;
+      case 'S' : shorty_type = 'I'; break;
+      case 'C' : shorty_type = 'I'; break;
+      default: break;
+    }
+    args_type.push_back(irb_.getJType(shorty_type, kAccurate));
+#else
     args_type.push_back(irb_.getJType(shorty[i], kAccurate));
+#endif
   }
 
   return llvm::FunctionType::get(ret_type, args_type, false);
@@ -1861,6 +2578,19 @@
     case IntrinsicHelper::ThrowException: {
       return ExpandToRuntime(runtime_support::ThrowException, call_inst);
     }
+    case IntrinsicHelper::HLThrowException: {
+      ScopedExpandToBasicBlock eb(irb_, &call_inst);
+
+      uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
+
+      EmitUpdateDexPC(dex_pc);
+
+      irb_.CreateCall(irb_.GetRuntime(runtime_support::ThrowException),
+                      call_inst.getArgOperand(0));
+
+      EmitGuard_ExceptionLandingPad(dex_pc);
+      return NULL;
+    }
     case IntrinsicHelper::GetException: {
       return Expand_GetException();
     }
@@ -1882,8 +2612,7 @@
 
     //==- Const String -----------------------------------------------------==//
     case IntrinsicHelper::ConstString: {
-      UNIMPLEMENTED(FATAL);
-      return NULL;
+      return Expand_ConstString(call_inst);
     }
     case IntrinsicHelper::LoadStringFromDexCache: {
       return Expand_LoadStringFromDexCache(call_inst.getArgOperand(0));
@@ -1894,8 +2623,7 @@
 
     //==- Const Class ------------------------------------------------------==//
     case IntrinsicHelper::ConstClass: {
-      UNIMPLEMENTED(FATAL);
-      return NULL;
+      return Expand_ConstClass(call_inst);
     }
     case IntrinsicHelper::InitializeTypeAndVerifyAccess: {
       return ExpandToRuntime(runtime_support::InitializeTypeAndVerifyAccess, call_inst);
@@ -1922,7 +2650,7 @@
       return ExpandToRuntime(runtime_support::CheckCast, call_inst);
     }
     case IntrinsicHelper::HLCheckCast: {
-      UNIMPLEMENTED(FATAL);
+      Expand_HLCheckCast(call_inst);
       return NULL;
     }
     case IntrinsicHelper::IsAssignable: {
@@ -1939,22 +2667,18 @@
 
     //==- Instance ---------------------------------------------------------==//
     case IntrinsicHelper::NewInstance: {
-      UNIMPLEMENTED(FATAL);
-      return NULL;
+      return Expand_NewInstance(call_inst);
     }
     case IntrinsicHelper::InstanceOf: {
-      UNIMPLEMENTED(FATAL);
-      return NULL;
+      return Expand_InstanceOf(call_inst);
     }
 
     //==- Array ------------------------------------------------------------==//
     case IntrinsicHelper::NewArray: {
-      UNIMPLEMENTED(FATAL);
-      return NULL;
+      return Expand_NewArray(call_inst);
     }
     case IntrinsicHelper::OptArrayLength: {
-      UNIMPLEMENTED(FATAL);
-      return NULL;
+      return Expand_OptArrayLength(call_inst);
     }
     case IntrinsicHelper::ArrayLength: {
       return EmitLoadArrayLength(call_inst.getArgOperand(0));
@@ -2068,12 +2792,11 @@
       return ExpandToRuntime(runtime_support::FillArrayData, call_inst);
     }
     case IntrinsicHelper::HLFillArrayData: {
-      UNIMPLEMENTED(FATAL);
+      Expand_HLFillArrayData(call_inst);
       return NULL;
     }
     case IntrinsicHelper::HLFilledNewArray: {
-      UNIMPLEMENTED(FATAL);
-      return NULL;
+      return Expand_HLFilledNewArray(call_inst);
     }
 
     //==- Instance Field ---------------------------------------------------==//
@@ -2468,29 +3191,13 @@
     }
 
     //==- High-level Invoke ------------------------------------------------==//
-    case IntrinsicHelper::HLInvokeVoid: {
-      UNIMPLEMENTED(FATAL);
-      return NULL;
-    }
-    case IntrinsicHelper::HLInvokeObj: {
-      UNIMPLEMENTED(FATAL);
-      return NULL;
-    }
-    case IntrinsicHelper::HLInvokeInt: {
-      UNIMPLEMENTED(FATAL);
-      return NULL;
-    }
-    case IntrinsicHelper::HLInvokeFloat: {
-      UNIMPLEMENTED(FATAL);
-      return NULL;
-    }
-    case IntrinsicHelper::HLInvokeLong: {
-      UNIMPLEMENTED(FATAL);
-      return NULL;
-    }
+    case IntrinsicHelper::HLInvokeVoid:
+    case IntrinsicHelper::HLInvokeObj:
+    case IntrinsicHelper::HLInvokeInt:
+    case IntrinsicHelper::HLInvokeFloat:
+    case IntrinsicHelper::HLInvokeLong:
     case IntrinsicHelper::HLInvokeDouble: {
-      UNIMPLEMENTED(FATAL);
-      return NULL;
+      return Expand_HLInvoke(call_inst);
     }
 
     //==- Invoke -----------------------------------------------------------==//
@@ -2633,11 +3340,11 @@
 
     //==- High-level Monitor -----------------------------------------------==//
     case IntrinsicHelper::MonitorEnter: {
-      UNIMPLEMENTED(FATAL);
+      Expand_MonitorEnter(call_inst);
       return NULL;
     }
     case IntrinsicHelper::MonitorExit: {
-      UNIMPLEMENTED(FATAL);
+      Expand_MonitorExit(call_inst);
       return NULL;
     }