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_;
};