Merge "Fixed x86 compilation of filled-new-array/range." into ics-mr1-plus-art
diff --git a/src/compiler_llvm/ir_builder.h b/src/compiler_llvm/ir_builder.h
index 24a594d..e1a47c4 100644
--- a/src/compiler_llvm/ir_builder.h
+++ b/src/compiler_llvm/ir_builder.h
@@ -105,6 +105,21 @@
     StoreToObjectOffset(object_addr, offset, new_value, tbaa_.GetSpecialType(special_ty));
   }
 
+  llvm::LoadInst* LoadFromObjectOffset(llvm::Value* object_addr,
+                                       int64_t offset,
+                                       llvm::Type* type,
+                                       TBAASpecialType special_ty, JType j_ty) {
+    return LoadFromObjectOffset(object_addr, offset, type, tbaa_.GetMemoryJType(special_ty, j_ty));
+  }
+
+  void StoreToObjectOffset(llvm::Value* object_addr,
+                           int64_t offset,
+                           llvm::Value* new_value,
+                           TBAASpecialType special_ty, JType j_ty) {
+    DCHECK_NE(special_ty, kTBAAConstJObject) << "ConstJObject is read only!";
+    StoreToObjectOffset(object_addr, offset, new_value, tbaa_.GetMemoryJType(special_ty, j_ty));
+  }
+
   void SetTBAACall(llvm::CallInst* call_inst, TBAASpecialType special_ty) {
     call_inst->setMetadata(llvm::LLVMContext::MD_tbaa, tbaa_.GetSpecialType(special_ty));
   }
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index 3122712..c29e458 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -66,7 +66,7 @@
     reg_to_shadow_frame_index_(code_item_->registers_size_, -1),
     retval_reg_(NULL),
     basic_block_stack_overflow_(NULL),
-    basic_block_reg_alloca_(NULL), basic_block_shadow_frame_alloca_(NULL),
+    basic_block_alloca_(NULL), basic_block_shadow_frame_(NULL),
     basic_block_reg_arg_init_(NULL),
     basic_blocks_(code_item_->insns_size_in_code_units_),
     basic_block_landing_pads_(code_item_->tries_size_, NULL),
@@ -150,13 +150,13 @@
   llvm::BasicBlock* entry =
     llvm::BasicBlock::Create(*context_, PrettyMethod(method_idx_, *dex_file_), func_);
 #endif
-  basic_block_reg_alloca_ =
+  basic_block_alloca_ =
     llvm::BasicBlock::Create(*context_, "prologue.alloca", func_);
 
   basic_block_stack_overflow_ =
     llvm::BasicBlock::Create(*context_, "prologue.stack_overflow_check", func_);
 
-  basic_block_shadow_frame_alloca_ =
+  basic_block_shadow_frame_ =
     llvm::BasicBlock::Create(*context_, "prologue.shadowframe", func_);
 
   basic_block_reg_arg_init_ =
@@ -164,9 +164,12 @@
 
 #if !defined(NDEBUG)
   irb_.SetInsertPoint(entry);
-  irb_.CreateBr(basic_block_reg_alloca_);
+  irb_.CreateBr(basic_block_alloca_);
 #endif
 
+  irb_.SetInsertPoint(basic_block_alloca_);
+  jvalue_temp_ = irb_.CreateAlloca(irb_.getJValueTy());
+
   // Create register array
   for (uint16_t r = 0; r < code_item_->registers_size_; ++r) {
     regs_[r] = DalvikReg::CreateLocalVarReg(*this, r);
@@ -239,7 +242,7 @@
 
 
 void MethodCompiler::EmitPrologueLastBranch() {
-  irb_.SetInsertPoint(basic_block_reg_alloca_);
+  irb_.SetInsertPoint(basic_block_alloca_);
   irb_.CreateBr(basic_block_stack_overflow_);
 
   // If a method will not call to other method, and the method is small, we can avoid stack overflow
@@ -251,15 +254,15 @@
   }
 
   irb_.SetInsertPoint(basic_block_stack_overflow_);
-  irb_.CreateBr(basic_block_shadow_frame_alloca_);
+  irb_.CreateBr(basic_block_shadow_frame_);
 
-  irb_.SetInsertPoint(basic_block_shadow_frame_alloca_);
+  irb_.SetInsertPoint(basic_block_shadow_frame_);
   irb_.CreateBr(basic_block_reg_arg_init_);
 }
 
 
 void MethodCompiler::EmitPrologueAllocShadowFrame() {
-  irb_.SetInsertPoint(basic_block_shadow_frame_alloca_);
+  irb_.SetInsertPoint(basic_block_alloca_);
 
   // Allocate the shadow frame now!
   uint32_t sirt_size = 0;
@@ -274,11 +277,16 @@
   llvm::StructType* shadow_frame_type = irb_.getShadowFrameTy(sirt_size);
   shadow_frame_ = irb_.CreateAlloca(shadow_frame_type);
 
-  // Zero-initialization of the shadow frame
-  llvm::ConstantAggregateZero* zero_initializer =
-    llvm::ConstantAggregateZero::get(shadow_frame_type);
+  irb_.SetInsertPoint(basic_block_shadow_frame_);
 
-  irb_.CreateStore(zero_initializer, shadow_frame_, kTBAAShadowFrame);
+  // Zero-initialization of the shadow frame table
+  llvm::Value* shadow_frame_table = irb_.CreateConstGEP2_32(shadow_frame_, 0, 1);
+  llvm::Type* table_type = shadow_frame_type->getElementType(1);
+
+  llvm::ConstantAggregateZero* zero_initializer =
+    llvm::ConstantAggregateZero::get(table_type);
+
+  irb_.CreateStore(zero_initializer, shadow_frame_table, kTBAAShadowFrame);
 
   // Get method object
   llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
@@ -1834,11 +1842,14 @@
     EmitAllocNewArray(dex_pc, dec_insn.vA, dec_insn.vB, true);
 
   if (dec_insn.vA > 0) {
-    // Resolve the element type
-    Class* klass = dex_cache_->GetResolvedType(dec_insn.vB)->GetComponentType();
-    // TODO: Avoid the usage of the dex_cache_.  Try to figure out a better
-    // way to distinguish [I and [L.
-    CHECK_NE(klass, static_cast<Class*>(NULL));
+    // Check for the element type
+    uint32_t type_desc_len = 0;
+    const char* type_desc =
+      dex_file_->StringByTypeIdx(dec_insn.vB, &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;
@@ -1847,12 +1858,11 @@
     // 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 (klass->IsPrimitiveInt()) {
+    if (is_elem_int_ty) {
       alignment = sizeof(int32_t);
       elem_size = irb_.getPtrEquivInt(sizeof(int32_t));
       field_type = irb_.getJIntTy()->getPointerTo();
     } else {
-      CHECK(!klass->IsPrimitive());
       alignment = irb_.getSizeOfPtrEquivInt();
       elem_size = irb_.getSizeOfPtrEquivIntValue();
       field_type = irb_.getJObjectTy()->getPointerTo();
@@ -1877,7 +1887,7 @@
       }
 
       llvm::Value* reg_value;
-      if (klass->IsPrimitiveInt()) {
+      if (is_elem_int_ty) {
         reg_value = EmitLoadDalvikReg(reg_index, kInt, kAccurate);
       } else {
         reg_value = EmitLoadDalvikReg(reg_index, kObject, kAccurate);
@@ -2809,12 +2819,6 @@
     }
   }
 
-  llvm::Value* code_addr =
-    irb_.LoadFromObjectOffset(callee_method_object_addr,
-                              Method::GetCodeOffset().Int32Value(),
-                              GetFunctionType(callee_method_idx, is_static)->getPointerTo(),
-                              kTBAAJRuntime);
-
   // Load the actual parameter
   std::vector<llvm::Value*> args;
 
@@ -2828,6 +2832,21 @@
   EmitLoadActualParameters(args, callee_method_idx, dec_insn,
                            arg_fmt, is_static);
 
+  if (is_fast_path && (invoke_type == kDirect || invoke_type == kStatic)) {
+    bool need_retry = EmitInlineJavaIntrinsic(PrettyMethod(callee_method_idx, *dex_file_),
+                                              args,
+                                              GetNextBasicBlock(dex_pc));
+    if (!need_retry) {
+      return;
+    }
+  }
+
+  llvm::Value* code_addr =
+    irb_.LoadFromObjectOffset(callee_method_object_addr,
+                              Method::GetCodeOffset().Int32Value(),
+                              GetFunctionType(callee_method_idx, is_static)->getPointerTo(),
+                              kTBAAJRuntime);
+
 #if 0
   // Invoke callee
   EmitUpdateDexPC(dex_pc);
@@ -2899,17 +2918,15 @@
       irb_.SetInsertPoint(block_proxy_stub);
     }
     { // proxy stub
-      llvm::Value* temp_space_addr;
       if (ret_shorty != 'V') {
-        temp_space_addr = irb_.CreateAlloca(irb_.getJValueTy());
-        args.push_back(temp_space_addr);
+        args.push_back(jvalue_temp_);
       }
       // TODO: Remove this after we solve the proxy trampoline calling convention problem.
       irb_.CreateCall(irb_.GetRuntime(ProxyInvokeHandler), args);
       if (ret_shorty != 'V') {
         llvm::Type* accurate_ret_type = irb_.getJType(ret_shorty, kAccurate);
         llvm::Value* result_addr =
-            irb_.CreateBitCast(temp_space_addr, accurate_ret_type->getPointerTo());
+            irb_.CreateBitCast(jvalue_temp_, accurate_ret_type->getPointerTo());
         llvm::Value* retval = irb_.CreateLoad(result_addr, kTBAAStackTemp);
         EmitStoreDalvikRetValReg(ret_shorty, kAccurate, retval);
       }
@@ -3858,7 +3875,7 @@
 
   // Save current IR builder insert point
   llvm::IRBuilderBase::InsertPoint irb_ip_original = irb_.saveIP();
-  irb_.SetInsertPoint(basic_block_reg_alloca_);
+  irb_.SetInsertPoint(basic_block_alloca_);
 
   // Alloca
   llvm::Value* reg_addr = irb_.CreateAlloca(reg_type, 0, reg_name);
@@ -3890,7 +3907,7 @@
   // Save current IR builder insert point
   llvm::IRBuilderBase::InsertPoint irb_ip_original = irb_.saveIP();
 
-  irb_.SetInsertPoint(basic_block_shadow_frame_alloca_);
+  irb_.SetInsertPoint(basic_block_shadow_frame_);
 
   llvm::Value* gep_index[] = {
     irb_.getInt32(0), // No pointer displacement
@@ -3919,7 +3936,7 @@
 
   // Save current IR builder insert point
   llvm::IRBuilderBase::InsertPoint irb_ip_original = irb_.saveIP();
-  irb_.SetInsertPoint(basic_block_reg_alloca_);
+  irb_.SetInsertPoint(basic_block_alloca_);
 
   // Alloca
   llvm::Value* reg_addr = irb_.CreateAlloca(reg_type, 0, reg_name);
@@ -3952,6 +3969,79 @@
 
 
 // TODO: Use high-level IR to do this
+bool MethodCompiler::EmitInlineJavaIntrinsic(const std::string& callee_method_name,
+                                             const std::vector<llvm::Value*>& args,
+                                             llvm::BasicBlock* after_invoke) {
+  if (callee_method_name == "char java.lang.String.charAt(int)") {
+    return EmitInlinedStringCharAt(args, after_invoke);
+  }
+  if (callee_method_name == "int java.lang.String.length()") {
+    return EmitInlinedStringLength(args, after_invoke);
+  }
+  return true;
+}
+
+bool MethodCompiler::EmitInlinedStringCharAt(const std::vector<llvm::Value*>& args,
+                                             llvm::BasicBlock* after_invoke) {
+  DCHECK_EQ(args.size(), 3U) <<
+      "char java.lang.String.charAt(int) has 3 args: method, this, char_index";
+  llvm::Value* this_object = args[1];
+  llvm::Value* char_index = args[2];
+  llvm::BasicBlock* block_retry = llvm::BasicBlock::Create(*context_, "CharAtRetry", func_);
+  llvm::BasicBlock* block_cont = llvm::BasicBlock::Create(*context_, "CharAtCont", func_);
+
+  // TODO: Can we safely say the String.count is ConstJObject(constant memory)? (there are so many
+  // iput to String.count in the String.<init>(...))
+  llvm::Value* string_count = irb_.LoadFromObjectOffset(this_object,
+                                                        String::CountOffset().Int32Value(),
+                                                        irb_.getJIntTy(),
+                                                        kTBAAHeapInstance, kInt);
+  // Two's complement, so we can use only one "less than" to check "in bounds"
+  llvm::Value* in_bounds = irb_.CreateICmpULT(char_index, string_count);
+  irb_.CreateCondBr(in_bounds, block_cont, block_retry, kLikely);
+
+  irb_.SetInsertPoint(block_cont);
+  // TODO: Can we safely say the String.offset is ConstJObject(constant memory)?
+  llvm::Value* string_offset = irb_.LoadFromObjectOffset(this_object,
+                                                         String::OffsetOffset().Int32Value(),
+                                                         irb_.getJIntTy(),
+                                                         kTBAAHeapInstance, kInt);
+  llvm::Value* string_value = irb_.LoadFromObjectOffset(this_object,
+                                                        String::ValueOffset().Int32Value(),
+                                                        irb_.getJObjectTy(),
+                                                        kTBAAHeapInstance, kObject);
+
+  // index_value = string.offset + char_index
+  llvm::Value* index_value = irb_.CreateAdd(string_offset, char_index);
+
+  // array_elem_value = string.value[index_value]
+  llvm::Value* array_elem_addr = EmitArrayGEP(string_value, index_value, kChar);
+  llvm::Value* array_elem_value = irb_.CreateLoad(array_elem_addr, kTBAAHeapArray, kChar);
+
+  EmitStoreDalvikRetValReg(kChar, kArray, array_elem_value);
+  irb_.CreateBr(after_invoke);
+
+  irb_.SetInsertPoint(block_retry);
+  return true;
+}
+
+bool MethodCompiler::EmitInlinedStringLength(const std::vector<llvm::Value*>& args,
+                                             llvm::BasicBlock* after_invoke) {
+  DCHECK_EQ(args.size(), 2U) <<
+      "int java.lang.String.length() has 2 args: method, this";
+  llvm::Value* this_object = args[1];
+  // TODO: Can we safely say the String.count is ConstJObject(constant memory)?
+  llvm::Value* string_count = irb_.LoadFromObjectOffset(this_object,
+                                                        String::CountOffset().Int32Value(),
+                                                        irb_.getJIntTy(),
+                                                        kTBAAHeapInstance, kInt);
+  EmitStoreDalvikRetValReg(kInt, kAccurate, string_count);
+  irb_.CreateBr(after_invoke);
+  return false;
+}
+
+
+// TODO: Use high-level IR to do this
 void MethodCompiler::ComputeMethodInfo() {
   // If this method is static, we set the "this" register index to -1. So we don't worry about this
   // method is static or not in the following comparison.
diff --git a/src/compiler_llvm/method_compiler.h b/src/compiler_llvm/method_compiler.h
index 02a5b2e..50411a1 100644
--- a/src/compiler_llvm/method_compiler.h
+++ b/src/compiler_llvm/method_compiler.h
@@ -434,6 +434,15 @@
   }
 
   // TODO: Use high-level IR to do this
+  bool EmitInlineJavaIntrinsic(const std::string& callee_method_name,
+                               const std::vector<llvm::Value*>& args,
+                               llvm::BasicBlock* after_invoke);
+
+  bool EmitInlinedStringCharAt(const std::vector<llvm::Value*>& args,
+                               llvm::BasicBlock* after_invoke);
+
+  bool EmitInlinedStringLength(const std::vector<llvm::Value*>& args,
+                               llvm::BasicBlock* after_invoke);
 
   struct MethodInfo {
     int64_t this_reg_idx;
@@ -472,8 +481,8 @@
   UniquePtr<DalvikReg> retval_reg_;
 
   llvm::BasicBlock* basic_block_stack_overflow_;
-  llvm::BasicBlock* basic_block_reg_alloca_;
-  llvm::BasicBlock* basic_block_shadow_frame_alloca_;
+  llvm::BasicBlock* basic_block_alloca_;
+  llvm::BasicBlock* basic_block_shadow_frame_;
   llvm::BasicBlock* basic_block_reg_arg_init_;
   std::vector<llvm::BasicBlock*> basic_blocks_;
 
@@ -482,6 +491,7 @@
   llvm::BasicBlock* basic_block_unreachable_;
 
   llvm::AllocaInst* shadow_frame_;
+  llvm::AllocaInst* jvalue_temp_;
 
   uint16_t elf_func_idx_;
 };