Merge iceland to greenland.
Change-Id: Ic4440a658bb2fccb558024a736d896baaf172f3c
diff --git a/src/compiler_llvm/compiler_llvm.cc b/src/compiler_llvm/compiler_llvm.cc
index dc79643..3a1bebc 100644
--- a/src/compiler_llvm/compiler_llvm.cc
+++ b/src/compiler_llvm/compiler_llvm.cc
@@ -116,7 +116,11 @@
CompilationUnit* CompilerLLVM::AllocateCompilationUnit() {
MutexLock GUARD(num_cunits_lock_);
- return new CompilationUnit(this, num_cunits_++);
+ CompilationUnit* cunit = new CompilationUnit(this, num_cunits_++);
+ if (!bitcode_filename_.empty()) {
+ cunit->SetBitcodeFileName(StringPrintf("%s-%zu", bitcode_filename_.c_str(), num_cunits_-1));
+ }
+ return cunit;
}
diff --git a/src/compiler_llvm/compiler_llvm.h b/src/compiler_llvm/compiler_llvm.h
index 24a766e..4680648 100644
--- a/src/compiler_llvm/compiler_llvm.h
+++ b/src/compiler_llvm/compiler_llvm.h
@@ -89,12 +89,6 @@
private:
CompilationUnit* AllocateCompilationUnit();
- void Materialize(CompilationUnit* cunit);
-
- bool IsBitcodeFileNameAvailable() const {
- return !bitcode_filename_.empty();
- }
-
Compiler* compiler_;
InstructionSet insn_set_;
diff --git a/src/compiler_llvm/gbc_expander.cc b/src/compiler_llvm/gbc_expander.cc
index e2b9834..77c1bf5 100644
--- a/src/compiler_llvm/gbc_expander.cc
+++ b/src/compiler_llvm/gbc_expander.cc
@@ -194,8 +194,13 @@
char GBCExpanderPass::ID = 0;
bool GBCExpanderPass::runOnFunction(llvm::Function& func) {
+ // Runtime support or stub
+ if (func.getName().startswith("art_") || func.getName().startswith("Art")) {
+ return false;
+ }
bool changed;
+ // TODO: Use intrinsic.
changed = InsertStackOverflowCheck(func);
std::list<std::pair<llvm::CallInst*,
@@ -962,7 +967,7 @@
switch (intr_id) {
//==- Thread -----------------------------------------------------------==//
case IntrinsicHelper::GetCurrentThread: {
- return ExpandToRuntime(runtime_support::GetCurrentThread, call_inst);
+ return irb_.Runtime().EmitGetCurrentThread();
}
case IntrinsicHelper::TestSuspend: {
Expand_TestSuspend(call_inst);
diff --git a/src/compiler_llvm/runtime_support_builder.cc b/src/compiler_llvm/runtime_support_builder.cc
index 8bbac94..7ef8917 100644
--- a/src/compiler_llvm/runtime_support_builder.cc
+++ b/src/compiler_llvm/runtime_support_builder.cc
@@ -235,7 +235,7 @@
Function* slow_func = GetRuntimeSupportFunction(runtime_support::TestSuspend);
Function* func = Function::Create(slow_func->getFunctionType(),
GlobalValue::LinkOnceODRLinkage,
- "test_suspend_fast",
+ "art_test_suspend_fast",
&module_);
MakeFunctionInline(func);
BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
diff --git a/src/greenland/dalvik_reg.cc b/src/greenland/dalvik_reg.cc
index 3155a8c..a97a646 100644
--- a/src/greenland/dalvik_reg.cc
+++ b/src/greenland/dalvik_reg.cc
@@ -28,24 +28,12 @@
DalvikReg::DalvikReg(DexLang& dex_lang, unsigned reg_idx)
: dex_lang_(dex_lang), irb_(dex_lang.GetIRBuilder()),
- reg_idx_(reg_idx), shadow_frame_entry_idx_(-1),
- reg_32_(NULL), reg_64_(NULL), reg_obj_(NULL) {
+ reg_idx_(reg_idx), reg_32_(NULL), reg_64_(NULL), reg_obj_(NULL) {
}
DalvikReg::~DalvikReg() {
}
-void DalvikReg::SetShadowEntry(llvm::Value* object) {
- if (shadow_frame_entry_idx_ < 0) {
- shadow_frame_entry_idx_ = dex_lang_.AllocShadowFrameEntry(reg_idx_);
- }
-
- irb_.CreateCall2(irb_.GetIntrinsics(IntrinsicHelper::SetShadowFrameEntry),
- object, irb_.getInt32(shadow_frame_entry_idx_));
-
- return;
-}
-
llvm::Type* DalvikReg::GetRegCategoryEquivSizeTy(IRBuilder& irb, RegCategory reg_cat) {
switch (reg_cat) {
case kRegCat1nr: return irb.GetJIntTy();
@@ -137,9 +125,7 @@
void DalvikReg::SetValue(JType jty, JTypeSpace space, llvm::Value* value) {
DCHECK_NE(jty, kVoid) << "Dalvik register will never be void type";
- if (jty == kObject) {
- SetShadowEntry(value);
- } else if (jty == kFloat || jty == kDouble) {
+ if (jty == kFloat || jty == kDouble) {
value = irb_.CreateBitCast(value, irb_.GetJType(jty, kReg));
}
diff --git a/src/greenland/dalvik_reg.h b/src/greenland/dalvik_reg.h
index 93524cc..b93ef7e 100644
--- a/src/greenland/dalvik_reg.h
+++ b/src/greenland/dalvik_reg.h
@@ -56,8 +56,6 @@
}
private:
- void SetShadowEntry(llvm::Value* object);
-
llvm::Value* GetAddr(JType jty);
llvm::Value* RegCat1SExt(llvm::Value* value);
@@ -70,8 +68,6 @@
unsigned reg_idx_;
- int shadow_frame_entry_idx_;
-
llvm::Value* reg_32_;
llvm::Value* reg_64_;
llvm::Value* reg_obj_;
diff --git a/src/greenland/dex_lang.cc b/src/greenland/dex_lang.cc
index 0e34492..0a5bc27 100644
--- a/src/greenland/dex_lang.cc
+++ b/src/greenland/dex_lang.cc
@@ -67,9 +67,11 @@
func_(NULL), reg_alloc_bb_(NULL), arg_reg_init_bb_(NULL),
basic_blocks_(cunit.GetCodeItem()->insns_size_in_code_units_),
retval_reg_(NULL),
+ num_shadow_frame_entries_(0),
+ reg_to_shadow_frame_index_(code_item_->registers_size_, -1),
landing_pads_bb_(cunit.GetCodeItem()->tries_size_, NULL),
- exception_unwind_bb_(NULL), cur_try_item_offset(-1),
- num_shadow_frame_entries_(0) {
+ exception_unwind_bb_(NULL), cur_try_item_offset(-1)
+{
if (cunit.GetCodeItem()->tries_size_ > 0) {
cur_try_item_offset = 0;
}
@@ -308,7 +310,7 @@
irb_.CreateCondBr(equal_zero, block_exception, block_continue);
irb_.SetInsertPoint(block_exception);
- EmitInvokeIntrinsic(dex_pc, IntrinsicHelper::ThrowDivZeroException);
+ EmitInvokeIntrinsic(dex_pc, false, IntrinsicHelper::ThrowDivZeroException);
irb_.SetInsertPoint(block_continue);
return;
@@ -328,7 +330,7 @@
irb_.SetInsertPoint(block_exception);
- EmitInvokeIntrinsic(dex_pc, IntrinsicHelper::ThrowNullPointerException,
+ EmitInvokeIntrinsic(dex_pc, false, IntrinsicHelper::ThrowNullPointerException,
irb_.getInt32(dex_pc));
irb_.SetInsertPoint(block_continue);
@@ -353,7 +355,7 @@
irb_.SetInsertPoint(block_exception);
- EmitInvokeIntrinsic2(dex_pc, IntrinsicHelper::ThrowIndexOutOfBounds,
+ EmitInvokeIntrinsic2(dex_pc, false, IntrinsicHelper::ThrowIndexOutOfBounds,
index, array_len);
irb_.SetInsertPoint(block_continue);
@@ -366,13 +368,20 @@
EmitGuard_ArrayIndexOutOfBoundsException(dex_pc, array, index);
}
-void DexLang::EmitGuard_ExceptionLandingPad(unsigned dex_pc) {
+void DexLang::EmitGuard_ExceptionLandingPad(unsigned dex_pc, bool can_skip_unwind) {
+ llvm::BasicBlock* lpad = GetLandingPadBasicBlock(dex_pc);
+ Instruction const* insn = Instruction::At(code_item_->insns_ + dex_pc);
+ if (lpad == NULL && can_skip_unwind &&
+ IsInstructionDirectToReturn(dex_pc + insn->SizeInCodeUnits())) {
+ return;
+ }
+
llvm::Value* exception_pending =
EmitInvokeIntrinsicNoThrow(IntrinsicHelper::IsExceptionPending);
llvm::BasicBlock* block_cont = CreateBasicBlockWithDexPC(dex_pc, "cont");
- if (llvm::BasicBlock* lpad = GetLandingPadBasicBlock(dex_pc)) {
+ if (lpad) {
irb_.CreateCondBr(exception_pending, lpad, block_cont);
} else {
irb_.CreateCondBr(exception_pending, GetUnwindBasicBlock(), block_cont);
@@ -386,35 +395,84 @@
// Garbage Collection Safe Point
//----------------------------------------------------------------------------
void DexLang::EmitGuard_GarbageCollectionSuspend() {
+ if (!method_info_.has_invoke) {
+ return;
+ }
+
llvm::Value* thread_object_addr = EmitGetCurrentThread();
EmitInvokeIntrinsicNoThrow(IntrinsicHelper::TestSuspend, thread_object_addr);
return;
}
//----------------------------------------------------------------------------
+// Register Helper Functions
+//----------------------------------------------------------------------------
+llvm::Value* DexLang::EmitLoadDalvikReg(unsigned reg_idx, JType jty, JTypeSpace space) {
+ return regs_[reg_idx]->GetValue(jty, space);
+}
+
+llvm::Value* DexLang::EmitLoadDalvikReg(unsigned reg_idx, char shorty, JTypeSpace space) {
+ return EmitLoadDalvikReg(reg_idx, GetJTypeFromShorty(shorty), space);
+}
+
+void DexLang::EmitStoreDalvikReg(unsigned reg_idx, JType jty,
+ JTypeSpace space, llvm::Value* new_value) {
+ regs_[reg_idx]->SetValue(jty, space, new_value);
+ if (jty == kObject && reg_to_shadow_frame_index_[reg_idx] != -1) {
+ EmitInvokeIntrinsic2NoThrow(IntrinsicHelper::SetShadowFrameEntry,
+ new_value, irb_.getInt32(reg_to_shadow_frame_index_[reg_idx]));
+ }
+}
+
+void DexLang::EmitStoreDalvikReg(unsigned reg_idx, char shorty,
+ JTypeSpace space, llvm::Value* new_value) {
+ EmitStoreDalvikReg(reg_idx, GetJTypeFromShorty(shorty), space, new_value);
+}
+
+llvm::Value* DexLang::EmitLoadDalvikRetValReg(JType jty, JTypeSpace space) {
+ return retval_reg_->GetValue(jty, space);
+}
+
+llvm::Value* DexLang::EmitLoadDalvikRetValReg(char shorty, JTypeSpace space) {
+ return EmitLoadDalvikRetValReg(GetJTypeFromShorty(shorty), space);
+}
+
+void DexLang::EmitStoreDalvikRetValReg(JType jty, JTypeSpace space,
+ llvm::Value* new_value) {
+ retval_reg_->SetValue(jty, space, new_value);
+}
+
+void DexLang::EmitStoreDalvikRetValReg(char shorty, JTypeSpace space,
+ llvm::Value* new_value) {
+ EmitStoreDalvikRetValReg(GetJTypeFromShorty(shorty), space, new_value);
+}
+
+//----------------------------------------------------------------------------
// Shadow Frame
//----------------------------------------------------------------------------
void DexLang::EmitUpdateDexPC(unsigned dex_pc) {
+ if (!method_info_.need_shadow_frame) {
+ return;
+ }
EmitInvokeIntrinsicNoThrow(IntrinsicHelper::UpdateDexPC,
irb_.getInt32(dex_pc));
return;
}
void DexLang::EmitPopShadowFrame() {
+ if (!method_info_.need_shadow_frame) {
+ return;
+ }
EmitInvokeIntrinsicNoThrow(IntrinsicHelper::PopShadowFrame);
return;
}
-unsigned DexLang::AllocShadowFrameEntry(unsigned reg_idx) {
- return num_shadow_frame_entries_++;
-}
-
//----------------------------------------------------------------------------
// Code Generation
//----------------------------------------------------------------------------
bool DexLang::CreateFunction() {
std::string func_name(PrettyMethod(method_idx_, *dex_file_,
- /* with_signature */false));
+ /* with_signature */true));
llvm::FunctionType* func_type = GetFunctionType();
if (func_type == NULL) {
@@ -475,6 +533,8 @@
arg_reg_init_bb_ =
llvm::BasicBlock::Create(context_, "prologue.arginit", func_);
+ ComputeMethodInfo();
+
// Create register array
const unsigned num_regs = code_item_->registers_size_;
for (unsigned i = 0; i < num_regs; i++) {
@@ -486,12 +546,32 @@
// Store argument to dalvik register
irb_.SetInsertPoint(arg_reg_init_bb_);
+ // TODO: Don't emit this at init_bb
+ // Garbage collection safe-point
+ EmitGuard_GarbageCollectionSuspend();
if (!EmitPrologueAssignArgRegister()) {
return false;
}
irb_.CreateBr(GetBasicBlock(0));
+ // DalvikReg index to shadow frame index
+ num_shadow_frame_entries_ = 0;
+ uint16_t arg_reg_start = code_item_->registers_size_ - code_item_->ins_size_;
+ if (method_info_.need_shadow_frame_entry) {
+ for (uint32_t i = 0, num_of_regs = code_item_->registers_size_; i < num_of_regs; ++i) {
+ if (i >= arg_reg_start && !method_info_.set_to_another_object[i]) {
+ // If we don't set argument registers to another object, we don't need the shadow frame
+ // entry for it. Because the arguments must have been in the caller's shadow frame.
+ continue;
+ }
+
+ if (IsRegCanBeObject(i)) {
+ reg_to_shadow_frame_index_[i] = num_shadow_frame_entries_++;
+ }
+ }
+ }
+
return true;
}
@@ -509,7 +589,7 @@
++arg_iter;
if (!cunit_.IsStatic()) {
- // The first argument to non-static method is "this" object pointer
+ // The first argument to non-static method is "this" object pointer.
EmitStoreDalvikReg(reg_idx, kObject, kAccurate, arg_iter);
arg_iter++;
reg_idx++;
@@ -533,6 +613,10 @@
}
bool DexLang::EmitPrologueAllcaShadowFrame() {
+ if (!method_info_.need_shadow_frame) {
+ return true;
+ }
+
// Save current IR builder insert point
llvm::IRBuilderBase::InsertPoint irb_ip_original = irb_.saveIP();
@@ -749,7 +833,7 @@
return ((args.empty()) ? irb_.CreateCall(intr) : irb_.CreateCall(intr, args));
}
-llvm::Value* DexLang::EmitInvokeIntrinsic(unsigned dex_pc,
+llvm::Value* DexLang::EmitInvokeIntrinsic(unsigned dex_pc, bool can_skip_unwind,
IntrinsicHelper::IntrinsicId intr_id,
llvm::ArrayRef<llvm::Value*> args) {
llvm::Function* intr = intrinsic_helper_.GetIntrinsicFunction(intr_id);
@@ -767,24 +851,36 @@
// throw exception always
EmitBranchExceptionLandingPad(dex_pc);
} else {
- EmitGuard_ExceptionLandingPad(dex_pc);
+ EmitGuard_ExceptionLandingPad(dex_pc, can_skip_unwind);
}
return ret_val;
}
-compiler_llvm::RegCategory DexLang::GetInferredRegCategory(unsigned dex_pc,
- unsigned reg_idx) {
+compiler_llvm::InferredRegCategoryMap const* DexLang::GetInferredRegCategoryMap() {
Compiler::MethodReference mref(dex_file_, method_idx_);
- const compiler_llvm::InferredRegCategoryMap* map =
+ compiler_llvm::InferredRegCategoryMap const* map =
verifier::MethodVerifier::GetInferredRegCategoryMap(mref);
CHECK_NE(map, static_cast<compiler_llvm::InferredRegCategoryMap*>(NULL));
+ return map;
+}
+
+compiler_llvm::RegCategory DexLang::GetInferredRegCategory(unsigned dex_pc,
+ unsigned reg_idx) {
+ compiler_llvm::InferredRegCategoryMap const* map = GetInferredRegCategoryMap();
+
return map->GetRegCategory(dex_pc, reg_idx);
}
+bool DexLang::IsRegCanBeObject(unsigned reg_idx) {
+ compiler_llvm::InferredRegCategoryMap const* map = GetInferredRegCategoryMap();
+
+ return map->IsRegCanBeObject(reg_idx);
+}
+
llvm::Value* DexLang::EmitLoadConstantClass(unsigned dex_pc,
uint32_t type_idx) {
llvm::Value* type_idx_value = irb_.getInt32(type_idx);
@@ -795,7 +891,7 @@
if (!compiler_.CanAccessTypeWithoutChecks(method_idx_, dex_cache_,
*dex_file_, type_idx)) {
- return EmitInvokeIntrinsic3(dex_pc, IntrinsicHelper::InitializeTypeAndVerifyAccess,
+ return EmitInvokeIntrinsic3(dex_pc, false, IntrinsicHelper::InitializeTypeAndVerifyAccess,
type_idx_value, method_object_addr,
thread_object_addr);
} else {
@@ -826,7 +922,7 @@
irb_.SetInsertPoint(block_load_class);
llvm::Value* loaded_type_object_addr =
- EmitInvokeIntrinsic3(dex_pc, IntrinsicHelper::InitializeType,
+ EmitInvokeIntrinsic3(dex_pc, false, IntrinsicHelper::InitializeType,
type_idx_value, method_object_addr,
thread_object_addr);
@@ -881,7 +977,7 @@
llvm::Value* thread_object_addr = EmitGetCurrentThread();
- llvm::Value* array_addr = EmitInvokeIntrinsic4(dex_pc, intrinsic,
+ llvm::Value* array_addr = EmitInvokeIntrinsic4(dex_pc, false, intrinsic,
type_index_value,
method_object_addr,
array_length_value,
@@ -933,7 +1029,7 @@
llvm::Value* thread_object_addr = EmitGetCurrentThread();
llvm::Value* loaded_storage_object_addr =
- EmitInvokeIntrinsic3(dex_pc, IntrinsicHelper::InitializeAndLoadClassSSB,
+ EmitInvokeIntrinsic3(dex_pc, false, IntrinsicHelper::InitializeAndLoadClassSSB,
type_idx_value, method_object_addr,
thread_object_addr);
@@ -1145,15 +1241,12 @@
llvm::Value* exception_addr =
EmitLoadDalvikReg(dec_insn.vA, kObject, kAccurate);
- EmitInvokeIntrinsic(dex_pc, IntrinsicHelper::ThrowException, exception_addr);
+ EmitInvokeIntrinsic(dex_pc, false, IntrinsicHelper::ThrowException, exception_addr);
return;
}
void DexLang::EmitInsn_ReturnVoid(unsigned dex_pc, const Instruction* insn) {
- // Garbage collection safe-point
- EmitGuard_GarbageCollectionSuspend();
-
// Pop the shadow frame
EmitPopShadowFrame();
@@ -1165,9 +1258,6 @@
void DexLang::EmitInsn_Return(unsigned dex_pc, const Instruction* insn) {
DecodedInstruction dec_insn(insn);
- // Garbage collection safe-point
- EmitGuard_GarbageCollectionSuspend();
-
// Pop the shadow frame
//
// NOTE: It is important to keep this AFTER the GC safe-point. Otherwise,
@@ -1272,7 +1362,7 @@
llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
- string_addr = EmitInvokeIntrinsic2(dex_pc, IntrinsicHelper::ResolveString,
+ string_addr = EmitInvokeIntrinsic2(dex_pc, true, IntrinsicHelper::ResolveString,
method_object_addr, string_idx_value);
}
@@ -1299,7 +1389,9 @@
llvm::Value* object_addr =
EmitLoadDalvikReg(dec_insn.vA, kObject, kAccurate);
- EmitGuard_NullPointerException(dex_pc, object_addr);
+ if (!(method_info_.this_will_not_be_null && dec_insn.vA == method_info_.this_reg_idx)) {
+ EmitGuard_NullPointerException(dex_pc, object_addr);
+ }
llvm::Value* thread_object_addr = EmitGetCurrentThread();
@@ -1316,11 +1408,13 @@
llvm::Value* object_addr =
EmitLoadDalvikReg(dec_insn.vA, kObject, kAccurate);
- EmitGuard_NullPointerException(dex_pc, object_addr);
+ if (!(method_info_.this_will_not_be_null && dec_insn.vA == method_info_.this_reg_idx)) {
+ EmitGuard_NullPointerException(dex_pc, object_addr);
+ }
llvm::Value* thread_object_addr = EmitGetCurrentThread();
- EmitInvokeIntrinsic2(dex_pc, IntrinsicHelper::UnlockObject,
+ EmitInvokeIntrinsic2(dex_pc, true, IntrinsicHelper::UnlockObject,
object_addr, thread_object_addr);
irb_.CreateBr(GetNextBasicBlock(dex_pc));
@@ -1369,7 +1463,7 @@
// Test: Is the object instantiated from the subclass of the given class?
irb_.SetInsertPoint(block_test_sub_class);
- EmitInvokeIntrinsic2(dex_pc, IntrinsicHelper::CheckCast,
+ EmitInvokeIntrinsic2(dex_pc, true, IntrinsicHelper::CheckCast,
type_object_addr, object_type_object_addr);
irb_.CreateBr(GetNextBasicBlock(dex_pc));
@@ -1463,7 +1557,7 @@
llvm::Value* thread_object_addr = EmitGetCurrentThread();
- llvm::Value* object_addr = EmitInvokeIntrinsic3(dex_pc, alloc_intrinsic,
+ llvm::Value* object_addr = EmitInvokeIntrinsic3(dex_pc, true, alloc_intrinsic,
type_index_value,
method_object_addr,
thread_object_addr);
@@ -1594,7 +1688,7 @@
// NOTE: We will check for the NullPointerException in the runtime.
llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
- EmitInvokeIntrinsic4(dex_pc, IntrinsicHelper::FillArrayData,
+ EmitInvokeIntrinsic4(dex_pc, true, IntrinsicHelper::FillArrayData,
method_object_addr, irb_.getInt32(dex_pc), array_addr,
irb_.getInt32(payload_offset));
}
@@ -1896,7 +1990,7 @@
// Check the type if an object is putting
if (elem_jty == kObject) {
- EmitInvokeIntrinsic2(dex_pc, IntrinsicHelper::CheckPutArrayElement,
+ EmitInvokeIntrinsic2(dex_pc, false, IntrinsicHelper::CheckPutArrayElement,
new_value, array_addr);
EmitMarkGCCard(new_value, array_addr);
@@ -1917,7 +2011,9 @@
llvm::Value* object_addr = EmitLoadDalvikReg(reg_idx, kObject, kAccurate);
- EmitGuard_NullPointerException(dex_pc, object_addr);
+ if (!(method_info_.this_will_not_be_null && reg_idx == method_info_.this_reg_idx)) {
+ EmitGuard_NullPointerException(dex_pc, object_addr);
+ }
int field_offset;
bool is_volatile;
@@ -1985,7 +2081,7 @@
llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
- instance_field_value = EmitInvokeIntrinsic3(dex_pc, iget_intrinsic,
+ instance_field_value = EmitInvokeIntrinsic3(dex_pc, true, iget_intrinsic,
field_idx_value,
method_object_addr,
object_addr);
@@ -2014,7 +2110,9 @@
llvm::Value* object_addr = EmitLoadDalvikReg(reg_idx, kObject, kAccurate);
- EmitGuard_NullPointerException(dex_pc, object_addr);
+ if (!(method_info_.this_will_not_be_null && reg_idx == method_info_.this_reg_idx)) {
+ EmitGuard_NullPointerException(dex_pc, object_addr);
+ }
llvm::Value* new_value = EmitLoadDalvikReg(dec_insn.vA, field_jty, kField);
@@ -2082,7 +2180,7 @@
llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
- EmitInvokeIntrinsic4(dex_pc, iput_intrinsic, field_idx_value,
+ EmitInvokeIntrinsic4(dex_pc, true, iput_intrinsic, field_idx_value,
method_object_addr, object_addr, new_value);
} else {
@@ -2116,7 +2214,7 @@
field_offset, ssb_index,
is_referrers_class,
is_volatile,
- /* is_put */true);
+ /* is_put */false);
// Select corresponding intrinsic accroding to the field type and is_fast_path
IntrinsicHelper::IntrinsicId sget_intrinsic = IntrinsicHelper::UnknownId;
@@ -2178,7 +2276,7 @@
llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
static_field_value =
- EmitInvokeIntrinsic2(dex_pc, sget_intrinsic,
+ EmitInvokeIntrinsic2(dex_pc, true, sget_intrinsic,
field_idx_value, method_object_addr);
} else {
DCHECK_GE(field_offset, 0);
@@ -2287,7 +2385,7 @@
llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
- EmitInvokeIntrinsic3(dex_pc, sput_intrinsic,
+ EmitInvokeIntrinsic3(dex_pc, true, sput_intrinsic,
field_idx_value, method_object_addr, new_value);
} else {
DCHECK_GE(field_offset, 0);
@@ -2338,17 +2436,14 @@
direct_code, direct_method);
// Load *this* actual parameter
+ uint32_t this_reg = -1u;
llvm::Value* this_addr = NULL;
if (is_static) {
this_addr = irb_.GetJNull();
} else {
- // Test: Is *this* parameter equal to null?
- this_addr = (arg_fmt == kArgReg) ?
- EmitLoadDalvikReg(dec_insn.arg[0], kObject, kAccurate):
- EmitLoadDalvikReg(dec_insn.vC + 0, kObject, kAccurate);
-
- EmitGuard_NullPointerException(dex_pc, this_addr);
+ this_reg = (arg_fmt == kArgReg) ? dec_insn.arg[0] : (dec_insn.vC + 0);
+ this_addr = EmitLoadDalvikReg(this_reg, kObject, kAccurate);
}
// Load the method object
@@ -2390,12 +2485,27 @@
}
callee_method_object_addr =
- EmitInvokeIntrinsic4(dex_pc, invoke_intr,
+ EmitInvokeIntrinsic4(dex_pc, false, invoke_intr,
callee_method_idx_value,
this_addr,
caller_method_object_addr,
thread_object_addr);
+
+ if (!is_static && (!method_info_.this_will_not_be_null ||
+ this_reg != method_info_.this_reg_idx)) {
+ // NOTE: The null pointer test should come after the method resolution.
+ // So that the "NoSuchMethodError" can be thrown before the
+ // "NullPointerException".
+ EmitGuard_NullPointerException(dex_pc, this_addr);
+ }
} else {
+ if (!is_static && (!method_info_.this_will_not_be_null ||
+ this_reg != method_info_.this_reg_idx)) {
+ // NOTE: In the fast path, we should do the null pointer check
+ // before the access to the class object and/or direct invocation.
+ EmitGuard_NullPointerException(dex_pc, this_addr);
+ }
+
switch (invoke_type) {
case kStatic:
case kDirect: {
@@ -2429,7 +2539,7 @@
llvm::Value* thread_object_addr = EmitGetCurrentThread();
callee_method_object_addr =
- EmitInvokeIntrinsic4(dex_pc,
+ EmitInvokeIntrinsic4(dex_pc, false,
IntrinsicHelper::GetInterfaceCalleeMethodObjAddrFast,
callee_method_idx_value,
this_addr,
@@ -2533,7 +2643,7 @@
<< "Actual argument mismatch for callee: "
<< PrettyMethod(callee_method_idx, *dex_file_);
- llvm::Value* retval = EmitInvokeIntrinsic(dex_pc, invoke_intrinsic, args);
+ llvm::Value* retval = EmitInvokeIntrinsic(dex_pc, true, invoke_intrinsic, args);
// Store the return value for the subsequent move-result
if (callee_shorty[0] != 'V') {
@@ -3723,5 +3833,525 @@
return true;
}
+
+bool DexLang::IsInstructionDirectToReturn(unsigned dex_pc) {
+ for (int i = 0; i < 8; ++i) { // Trace at most 8 instructions.
+ if (dex_pc >= code_item_->insns_size_in_code_units_) {
+ return false;
+ }
+
+ Instruction const* insn = Instruction::At(code_item_->insns_ + dex_pc);
+
+ if (insn->IsReturn()) {
+ return true;
+ }
+
+ // Is throw, switch, invoke or conditional branch.
+ if (insn->IsThrow() || insn->IsSwitch() || insn->IsInvoke() ||
+ (insn->IsBranch() && !insn->IsUnconditional())) {
+ return false;
+ }
+
+ switch (insn->Opcode()) {
+ default:
+ dex_pc += insn->SizeInCodeUnits();
+ break;
+
+ // This instruction will remove the exception. Consider as a side effect.
+ case Instruction::MOVE_EXCEPTION:
+ return false;
+ break;
+
+ case Instruction::GOTO:
+ case Instruction::GOTO_16:
+ case Instruction::GOTO_32:
+ {
+ DecodedInstruction dec_insn(insn);
+ int32_t branch_offset = dec_insn.vA;
+ dex_pc += branch_offset;
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+
+// TODO: Use high-level IR to do this
+void DexLang::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.
+ int64_t this_reg_idx = (cunit_.IsStatic()) ?
+ (-1) :
+ (code_item_->registers_size_ - code_item_->ins_size_);
+ bool has_invoke = false;
+ bool may_have_loop = false;
+ bool may_throw_exception = false;
+ bool assume_this_non_null = false;
+ std::vector<bool>& set_to_another_object = method_info_.set_to_another_object;
+ set_to_another_object.resize(code_item_->registers_size_, false);
+
+ Instruction const* insn;
+ for (uint32_t dex_pc = 0;
+ dex_pc < code_item_->insns_size_in_code_units_;
+ dex_pc += insn->SizeInCodeUnits()) {
+ insn = Instruction::At(code_item_->insns_ + dex_pc);
+ DecodedInstruction dec_insn(insn);
+
+ switch (insn->Opcode()) {
+ case Instruction::NOP:
+ break;
+
+ case Instruction::MOVE:
+ case Instruction::MOVE_FROM16:
+ case Instruction::MOVE_16:
+ case Instruction::MOVE_WIDE:
+ case Instruction::MOVE_WIDE_FROM16:
+ case Instruction::MOVE_WIDE_16:
+ case Instruction::MOVE_RESULT:
+ case Instruction::MOVE_RESULT_WIDE:
+ break;
+
+ case Instruction::MOVE_OBJECT:
+ case Instruction::MOVE_OBJECT_FROM16:
+ case Instruction::MOVE_OBJECT_16:
+ case Instruction::MOVE_RESULT_OBJECT:
+ case Instruction::MOVE_EXCEPTION:
+ set_to_another_object[dec_insn.vA] = true;
+ break;
+
+ case Instruction::RETURN_VOID:
+ case Instruction::RETURN:
+ case Instruction::RETURN_WIDE:
+ case Instruction::RETURN_OBJECT:
+ break;
+
+ case Instruction::CONST_4:
+ case Instruction::CONST_16:
+ case Instruction::CONST:
+ case Instruction::CONST_HIGH16:
+ set_to_another_object[dec_insn.vA] = true;
+ break;
+
+ case Instruction::CONST_WIDE_16:
+ case Instruction::CONST_WIDE_32:
+ case Instruction::CONST_WIDE:
+ case Instruction::CONST_WIDE_HIGH16:
+ break;
+
+ case Instruction::CONST_STRING:
+ case Instruction::CONST_STRING_JUMBO:
+ // TODO: Will the ResolveString throw exception?
+ if (!compiler_.CanAssumeStringIsPresentInDexCache(dex_cache_, dec_insn.vB)) {
+ may_throw_exception = true;
+ }
+ set_to_another_object[dec_insn.vA] = true;
+ break;
+
+ case Instruction::CONST_CLASS:
+ may_throw_exception = true;
+ set_to_another_object[dec_insn.vA] = true;
+ break;
+
+ case Instruction::MONITOR_ENTER:
+ case Instruction::MONITOR_EXIT:
+ case Instruction::CHECK_CAST:
+ may_throw_exception = true;
+ break;
+
+ case Instruction::ARRAY_LENGTH:
+ may_throw_exception = true;
+ break;
+
+ case Instruction::INSTANCE_OF:
+ case Instruction::NEW_INSTANCE:
+ case Instruction::NEW_ARRAY:
+ may_throw_exception = true;
+ set_to_another_object[dec_insn.vA] = true;
+ break;
+
+ case Instruction::FILLED_NEW_ARRAY:
+ case Instruction::FILLED_NEW_ARRAY_RANGE:
+ case Instruction::FILL_ARRAY_DATA:
+ case Instruction::THROW:
+ may_throw_exception = true;
+ break;
+
+ case Instruction::GOTO:
+ case Instruction::GOTO_16:
+ case Instruction::GOTO_32:
+ {
+ int32_t branch_offset = dec_insn.vA;
+ if (branch_offset <= 0 && !IsInstructionDirectToReturn(dex_pc + branch_offset)) {
+ may_have_loop = true;
+ }
+ }
+ break;
+
+ case Instruction::PACKED_SWITCH:
+ case Instruction::SPARSE_SWITCH:
+ case Instruction::CMPL_FLOAT:
+ case Instruction::CMPG_FLOAT:
+ case Instruction::CMPL_DOUBLE:
+ case Instruction::CMPG_DOUBLE:
+ case Instruction::CMP_LONG:
+ break;
+
+ case Instruction::IF_EQ:
+ case Instruction::IF_NE:
+ case Instruction::IF_LT:
+ case Instruction::IF_GE:
+ case Instruction::IF_GT:
+ case Instruction::IF_LE:
+ {
+ int32_t branch_offset = dec_insn.vC;
+ if (branch_offset <= 0 && !IsInstructionDirectToReturn(dex_pc + branch_offset)) {
+ may_have_loop = true;
+ }
+ }
+ break;
+
+ case Instruction::IF_EQZ:
+ case Instruction::IF_NEZ:
+ case Instruction::IF_LTZ:
+ case Instruction::IF_GEZ:
+ case Instruction::IF_GTZ:
+ case Instruction::IF_LEZ:
+ {
+ int32_t branch_offset = dec_insn.vB;
+ if (branch_offset <= 0 && !IsInstructionDirectToReturn(dex_pc + branch_offset)) {
+ may_have_loop = true;
+ }
+ }
+ break;
+
+ case Instruction::AGET:
+ case Instruction::AGET_WIDE:
+ case Instruction::AGET_OBJECT:
+ case Instruction::AGET_BOOLEAN:
+ case Instruction::AGET_BYTE:
+ case Instruction::AGET_CHAR:
+ case Instruction::AGET_SHORT:
+ may_throw_exception = true;
+ if (insn->Opcode() == Instruction::AGET_OBJECT) {
+ set_to_another_object[dec_insn.vA] = true;
+ }
+ break;
+
+ case Instruction::APUT:
+ case Instruction::APUT_WIDE:
+ case Instruction::APUT_OBJECT:
+ case Instruction::APUT_BOOLEAN:
+ case Instruction::APUT_BYTE:
+ case Instruction::APUT_CHAR:
+ case Instruction::APUT_SHORT:
+ may_throw_exception = true;
+ break;
+
+ case Instruction::IGET:
+ case Instruction::IGET_WIDE:
+ case Instruction::IGET_OBJECT:
+ case Instruction::IGET_BOOLEAN:
+ case Instruction::IGET_BYTE:
+ case Instruction::IGET_CHAR:
+ case Instruction::IGET_SHORT:
+ {
+ if (insn->Opcode() == Instruction::IGET_OBJECT) {
+ set_to_another_object[dec_insn.vA] = true;
+ }
+ uint32_t reg_idx = dec_insn.vB;
+ uint32_t field_idx = dec_insn.vC;
+ int field_offset;
+ bool is_volatile;
+ bool is_fast_path = compiler_.ComputeInstanceFieldInfo(
+ field_idx, &cunit_, field_offset, is_volatile, false);
+ if (!is_fast_path) {
+ may_throw_exception = true;
+ } else {
+ // Fast-path, may throw NullPointerException
+ if (reg_idx == this_reg_idx) {
+ // We assume "this" will not be null at first.
+ assume_this_non_null = true;
+ } else {
+ may_throw_exception = true;
+ }
+ }
+ }
+ break;
+
+ case Instruction::IPUT:
+ case Instruction::IPUT_WIDE:
+ case Instruction::IPUT_OBJECT:
+ case Instruction::IPUT_BOOLEAN:
+ case Instruction::IPUT_BYTE:
+ case Instruction::IPUT_CHAR:
+ case Instruction::IPUT_SHORT:
+ {
+ uint32_t reg_idx = dec_insn.vB;
+ uint32_t field_idx = dec_insn.vC;
+ int field_offset;
+ bool is_volatile;
+ bool is_fast_path = compiler_.ComputeInstanceFieldInfo(
+ field_idx, &cunit_, field_offset, is_volatile, true);
+ if (!is_fast_path) {
+ may_throw_exception = true;
+ } else {
+ // Fast-path, may throw NullPointerException
+ if (reg_idx == this_reg_idx) {
+ // We assume "this" will not be null at first.
+ assume_this_non_null = true;
+ } else {
+ may_throw_exception = true;
+ }
+ }
+ }
+ break;
+
+ case Instruction::SGET:
+ case Instruction::SGET_WIDE:
+ case Instruction::SGET_OBJECT:
+ case Instruction::SGET_BOOLEAN:
+ case Instruction::SGET_BYTE:
+ case Instruction::SGET_CHAR:
+ case Instruction::SGET_SHORT:
+ {
+ if (insn->Opcode() == Instruction::AGET_OBJECT) {
+ set_to_another_object[dec_insn.vA] = true;
+ }
+ uint32_t field_idx = dec_insn.vB;
+
+ int field_offset;
+ int ssb_index;
+ bool is_referrers_class;
+ bool is_volatile;
+
+ bool is_fast_path = compiler_.ComputeStaticFieldInfo(
+ field_idx, &cunit_, field_offset, ssb_index,
+ is_referrers_class, is_volatile, false);
+ if (!is_fast_path || !is_referrers_class) {
+ may_throw_exception = true;
+ }
+ }
+ break;
+
+ case Instruction::SPUT:
+ case Instruction::SPUT_WIDE:
+ case Instruction::SPUT_OBJECT:
+ case Instruction::SPUT_BOOLEAN:
+ case Instruction::SPUT_BYTE:
+ case Instruction::SPUT_CHAR:
+ case Instruction::SPUT_SHORT:
+ {
+ uint32_t field_idx = dec_insn.vB;
+
+ int field_offset;
+ int ssb_index;
+ bool is_referrers_class;
+ bool is_volatile;
+
+ bool is_fast_path = compiler_.ComputeStaticFieldInfo(
+ field_idx, &cunit_, field_offset, ssb_index,
+ is_referrers_class, is_volatile, true);
+ if (!is_fast_path || !is_referrers_class) {
+ may_throw_exception = true;
+ }
+ }
+ break;
+
+
+ case Instruction::INVOKE_VIRTUAL:
+ case Instruction::INVOKE_SUPER:
+ case Instruction::INVOKE_DIRECT:
+ case Instruction::INVOKE_STATIC:
+ case Instruction::INVOKE_INTERFACE:
+ case Instruction::INVOKE_VIRTUAL_RANGE:
+ case Instruction::INVOKE_SUPER_RANGE:
+ case Instruction::INVOKE_DIRECT_RANGE:
+ case Instruction::INVOKE_STATIC_RANGE:
+ case Instruction::INVOKE_INTERFACE_RANGE:
+ has_invoke = true;
+ may_throw_exception = true;
+ break;
+
+ case Instruction::NEG_INT:
+ case Instruction::NOT_INT:
+ case Instruction::NEG_LONG:
+ case Instruction::NOT_LONG:
+ case Instruction::NEG_FLOAT:
+ case Instruction::NEG_DOUBLE:
+ case Instruction::INT_TO_LONG:
+ case Instruction::INT_TO_FLOAT:
+ case Instruction::INT_TO_DOUBLE:
+ case Instruction::LONG_TO_INT:
+ case Instruction::LONG_TO_FLOAT:
+ case Instruction::LONG_TO_DOUBLE:
+ case Instruction::FLOAT_TO_INT:
+ case Instruction::FLOAT_TO_LONG:
+ case Instruction::FLOAT_TO_DOUBLE:
+ case Instruction::DOUBLE_TO_INT:
+ case Instruction::DOUBLE_TO_LONG:
+ case Instruction::DOUBLE_TO_FLOAT:
+ case Instruction::INT_TO_BYTE:
+ case Instruction::INT_TO_CHAR:
+ case Instruction::INT_TO_SHORT:
+ case Instruction::ADD_INT:
+ case Instruction::SUB_INT:
+ case Instruction::MUL_INT:
+ case Instruction::AND_INT:
+ case Instruction::OR_INT:
+ case Instruction::XOR_INT:
+ case Instruction::SHL_INT:
+ case Instruction::SHR_INT:
+ case Instruction::USHR_INT:
+ case Instruction::ADD_LONG:
+ case Instruction::SUB_LONG:
+ case Instruction::MUL_LONG:
+ case Instruction::AND_LONG:
+ case Instruction::OR_LONG:
+ case Instruction::XOR_LONG:
+ case Instruction::SHL_LONG:
+ case Instruction::SHR_LONG:
+ case Instruction::USHR_LONG:
+ case Instruction::ADD_INT_2ADDR:
+ case Instruction::SUB_INT_2ADDR:
+ case Instruction::MUL_INT_2ADDR:
+ case Instruction::AND_INT_2ADDR:
+ case Instruction::OR_INT_2ADDR:
+ case Instruction::XOR_INT_2ADDR:
+ case Instruction::SHL_INT_2ADDR:
+ case Instruction::SHR_INT_2ADDR:
+ case Instruction::USHR_INT_2ADDR:
+ case Instruction::ADD_LONG_2ADDR:
+ case Instruction::SUB_LONG_2ADDR:
+ case Instruction::MUL_LONG_2ADDR:
+ case Instruction::AND_LONG_2ADDR:
+ case Instruction::OR_LONG_2ADDR:
+ case Instruction::XOR_LONG_2ADDR:
+ case Instruction::SHL_LONG_2ADDR:
+ case Instruction::SHR_LONG_2ADDR:
+ case Instruction::USHR_LONG_2ADDR:
+ break;
+
+ case Instruction::DIV_INT:
+ case Instruction::REM_INT:
+ case Instruction::DIV_LONG:
+ case Instruction::REM_LONG:
+ case Instruction::DIV_INT_2ADDR:
+ case Instruction::REM_INT_2ADDR:
+ case Instruction::DIV_LONG_2ADDR:
+ case Instruction::REM_LONG_2ADDR:
+ may_throw_exception = true;
+ break;
+
+ case Instruction::ADD_FLOAT:
+ case Instruction::SUB_FLOAT:
+ case Instruction::MUL_FLOAT:
+ case Instruction::DIV_FLOAT:
+ case Instruction::REM_FLOAT:
+ case Instruction::ADD_DOUBLE:
+ case Instruction::SUB_DOUBLE:
+ case Instruction::MUL_DOUBLE:
+ case Instruction::DIV_DOUBLE:
+ case Instruction::REM_DOUBLE:
+ case Instruction::ADD_FLOAT_2ADDR:
+ case Instruction::SUB_FLOAT_2ADDR:
+ case Instruction::MUL_FLOAT_2ADDR:
+ case Instruction::DIV_FLOAT_2ADDR:
+ case Instruction::REM_FLOAT_2ADDR:
+ case Instruction::ADD_DOUBLE_2ADDR:
+ case Instruction::SUB_DOUBLE_2ADDR:
+ case Instruction::MUL_DOUBLE_2ADDR:
+ case Instruction::DIV_DOUBLE_2ADDR:
+ case Instruction::REM_DOUBLE_2ADDR:
+ break;
+
+ case Instruction::ADD_INT_LIT16:
+ case Instruction::ADD_INT_LIT8:
+ case Instruction::RSUB_INT:
+ case Instruction::RSUB_INT_LIT8:
+ case Instruction::MUL_INT_LIT16:
+ case Instruction::MUL_INT_LIT8:
+ case Instruction::AND_INT_LIT16:
+ case Instruction::AND_INT_LIT8:
+ case Instruction::OR_INT_LIT16:
+ case Instruction::OR_INT_LIT8:
+ case Instruction::XOR_INT_LIT16:
+ case Instruction::XOR_INT_LIT8:
+ case Instruction::SHL_INT_LIT8:
+ case Instruction::SHR_INT_LIT8:
+ case Instruction::USHR_INT_LIT8:
+ break;
+
+ case Instruction::DIV_INT_LIT16:
+ case Instruction::DIV_INT_LIT8:
+ case Instruction::REM_INT_LIT16:
+ case Instruction::REM_INT_LIT8:
+ if (dec_insn.vC == 0) {
+ may_throw_exception = true;
+ }
+ break;
+
+ case Instruction::UNUSED_3E:
+ case Instruction::UNUSED_3F:
+ case Instruction::UNUSED_40:
+ case Instruction::UNUSED_41:
+ case Instruction::UNUSED_42:
+ case Instruction::UNUSED_43:
+ case Instruction::UNUSED_73:
+ case Instruction::UNUSED_79:
+ case Instruction::UNUSED_7A:
+ case Instruction::UNUSED_E3:
+ case Instruction::UNUSED_E4:
+ case Instruction::UNUSED_E5:
+ case Instruction::UNUSED_E6:
+ case Instruction::UNUSED_E7:
+ case Instruction::UNUSED_E8:
+ case Instruction::UNUSED_E9:
+ case Instruction::UNUSED_EA:
+ case Instruction::UNUSED_EB:
+ case Instruction::UNUSED_EC:
+ case Instruction::UNUSED_ED:
+ case Instruction::UNUSED_EE:
+ case Instruction::UNUSED_EF:
+ case Instruction::UNUSED_F0:
+ case Instruction::UNUSED_F1:
+ case Instruction::UNUSED_F2:
+ case Instruction::UNUSED_F3:
+ case Instruction::UNUSED_F4:
+ case Instruction::UNUSED_F5:
+ case Instruction::UNUSED_F6:
+ case Instruction::UNUSED_F7:
+ case Instruction::UNUSED_F8:
+ case Instruction::UNUSED_F9:
+ case Instruction::UNUSED_FA:
+ case Instruction::UNUSED_FB:
+ case Instruction::UNUSED_FC:
+ case Instruction::UNUSED_FD:
+ case Instruction::UNUSED_FE:
+ case Instruction::UNUSED_FF:
+ LOG(FATAL) << "Dex file contains UNUSED bytecode: " << insn->Opcode();
+ break;
+ }
+ }
+
+ method_info_.this_reg_idx = this_reg_idx;
+ // According to the statistics, there are few methods that modify the "this" pointer. So this is a
+ // simple way to avoid data flow analysis. After we have a high-level IR before IRBuilder, we
+ // should remove this trick.
+ method_info_.this_will_not_be_null =
+ (cunit_.IsStatic()) ? (true) : (!set_to_another_object[this_reg_idx]);
+ method_info_.has_invoke = has_invoke;
+ // If this method has loop or invoke instruction, it may suspend. Thus we need a shadow frame entry
+ // for GC.
+ method_info_.need_shadow_frame_entry = has_invoke || may_have_loop;
+ // If this method may throw an exception, we need a shadow frame for stack trace (dexpc).
+ method_info_.need_shadow_frame = method_info_.need_shadow_frame_entry || may_throw_exception ||
+ (assume_this_non_null && !method_info_.this_will_not_be_null);
+ // If can only throw exception, but can't suspend check (no loop, no invoke),
+ // then there is no shadow frame entry. Only Shadow frame is needed.
+ method_info_.lazy_push_shadow_frame =
+ method_info_.need_shadow_frame && !method_info_.need_shadow_frame_entry;
+}
+
} // namespace greenland
} // namespace art
diff --git a/src/greenland/dex_lang.h b/src/greenland/dex_lang.h
index 6b212d0..059b972 100644
--- a/src/greenland/dex_lang.h
+++ b/src/greenland/dex_lang.h
@@ -42,6 +42,9 @@
namespace art {
class Compiler;
class OatCompilationUnit;
+ namespace compiler_llvm {
+ class InferredRegCategoryMap;
+ }
}
namespace art {
@@ -125,29 +128,15 @@
//----------------------------------------------------------------------------
std::vector<DalvikReg*> regs_;
- inline llvm::Value* EmitLoadDalvikReg(unsigned reg_idx, JType jty,
- JTypeSpace space) {
- DCHECK(regs_.at(reg_idx) != NULL);
- return regs_[reg_idx]->GetValue(jty, space);
- }
+ llvm::Value* EmitLoadDalvikReg(unsigned reg_idx, JType jty, JTypeSpace space);
- inline llvm::Value* EmitLoadDalvikReg(unsigned reg_idx, char shorty,
- JTypeSpace space) {
- DCHECK(regs_.at(reg_idx) != NULL);
- return EmitLoadDalvikReg(reg_idx, GetJTypeFromShorty(shorty), space);
- }
+ llvm::Value* EmitLoadDalvikReg(unsigned reg_idx, char shorty, JTypeSpace space);
- inline void EmitStoreDalvikReg(unsigned reg_idx, JType jty, JTypeSpace space,
- llvm::Value* new_value) {
- regs_[reg_idx]->SetValue(jty, space, new_value);
- return;
- }
+ void EmitStoreDalvikReg(unsigned reg_idx, JType jty,
+ JTypeSpace space, llvm::Value* new_value);
- inline void EmitStoreDalvikReg(unsigned reg_idx, char shorty,
- JTypeSpace space, llvm::Value* new_value) {
- EmitStoreDalvikReg(reg_idx, GetJTypeFromShorty(shorty), space, new_value);
- return;
- }
+ void EmitStoreDalvikReg(unsigned reg_idx, char shorty,
+ JTypeSpace space, llvm::Value* new_value);
private:
//----------------------------------------------------------------------------
@@ -156,25 +145,34 @@
// Hold the return value returned from the lastest invoke-* instruction
DalvikReg* retval_reg_;
- llvm::Value* EmitLoadDalvikRetValReg(JType jty, JTypeSpace space) {
- return retval_reg_->GetValue(jty, space);
- }
+ llvm::Value* EmitLoadDalvikRetValReg(JType jty, JTypeSpace space);
- llvm::Value* EmitLoadDalvikRetValReg(char shorty, JTypeSpace space) {
- return EmitLoadDalvikRetValReg(GetJTypeFromShorty(shorty), space);
- }
+ llvm::Value* EmitLoadDalvikRetValReg(char shorty, JTypeSpace space);
- void EmitStoreDalvikRetValReg(JType jty, JTypeSpace space,
- llvm::Value* new_value) {
- retval_reg_->SetValue(jty, space, new_value);
- return;
- }
+ void EmitStoreDalvikRetValReg(JType jty, JTypeSpace space, llvm::Value* new_value);
- void EmitStoreDalvikRetValReg(char shorty, JTypeSpace space,
- llvm::Value* new_value) {
- EmitStoreDalvikRetValReg(GetJTypeFromShorty(shorty), space, new_value);
- return;
- }
+ void EmitStoreDalvikRetValReg(char shorty, JTypeSpace space, llvm::Value* new_value);
+
+ private:
+ //----------------------------------------------------------------------------
+ // Shadow Frame
+ //----------------------------------------------------------------------------
+ unsigned num_shadow_frame_entries_;
+ std::vector<int32_t> reg_to_shadow_frame_index_;
+
+ void EmitUpdateDexPC(unsigned dex_pc);
+
+ void EmitPopShadowFrame();
+
+ private:
+ //----------------------------------------------------------------------------
+ // RegCategory
+ //----------------------------------------------------------------------------
+ compiler_llvm::RegCategory GetInferredRegCategory(unsigned dex_pc, unsigned reg_idx);
+
+ compiler_llvm::InferredRegCategoryMap const* GetInferredRegCategoryMap();
+
+ bool IsRegCanBeObject(unsigned reg_idx);
private:
//----------------------------------------------------------------------------
@@ -210,7 +208,7 @@
llvm::Value* array,
llvm::Value* index);
- void EmitGuard_ExceptionLandingPad(unsigned dex_pc);
+ void EmitGuard_ExceptionLandingPad(unsigned dex_pc, bool can_skip_unwind);
private:
//----------------------------------------------------------------------------
@@ -220,19 +218,6 @@
private:
//----------------------------------------------------------------------------
- // Shadow Frame
- //----------------------------------------------------------------------------
- unsigned num_shadow_frame_entries_;
-
- void EmitUpdateDexPC(unsigned dex_pc);
-
- void EmitPopShadowFrame();
-
- public:
- unsigned AllocShadowFrameEntry(unsigned reg_idx);
-
- private:
- //----------------------------------------------------------------------------
// Code Generation
//----------------------------------------------------------------------------
bool CreateFunction();
@@ -321,35 +306,35 @@
return EmitInvokeIntrinsicNoThrow(intr_id, args);
}
- llvm::Value* EmitInvokeIntrinsic(unsigned dex_pc,
+ llvm::Value* EmitInvokeIntrinsic(unsigned dex_pc, bool can_skip_unwind,
IntrinsicHelper::IntrinsicId intr_id,
llvm::ArrayRef<llvm::Value*> args
= llvm::ArrayRef<llvm::Value*>());
- llvm::Value* EmitInvokeIntrinsic2(unsigned dex_pc,
+ llvm::Value* EmitInvokeIntrinsic2(unsigned dex_pc, bool can_skip_unwind,
IntrinsicHelper::IntrinsicId intr_id,
llvm::Value* arg1,
llvm::Value* arg2) {
llvm::Value* args[] = { arg1, arg2 };
- return EmitInvokeIntrinsic(dex_pc, intr_id, args);
+ return EmitInvokeIntrinsic(dex_pc, can_skip_unwind, intr_id, args);
}
- llvm::Value* EmitInvokeIntrinsic3(unsigned dex_pc,
+ llvm::Value* EmitInvokeIntrinsic3(unsigned dex_pc, bool can_skip_unwind,
IntrinsicHelper::IntrinsicId intr_id,
llvm::Value* arg1,
llvm::Value* arg2,
llvm::Value* arg3) {
llvm::Value* args[] = { arg1, arg2, arg3 };
- return EmitInvokeIntrinsic(dex_pc, intr_id, args);
+ return EmitInvokeIntrinsic(dex_pc, can_skip_unwind, intr_id, args);
}
- llvm::Value* EmitInvokeIntrinsic4(unsigned dex_pc,
+ llvm::Value* EmitInvokeIntrinsic4(unsigned dex_pc, bool can_skip_unwind,
IntrinsicHelper::IntrinsicId intr_id,
llvm::Value* arg1,
llvm::Value* arg2,
llvm::Value* arg3,
llvm::Value* arg4) {
llvm::Value* args[] = { arg1, arg2, arg3, arg4 };
- return EmitInvokeIntrinsic(dex_pc, intr_id, args);
+ return EmitInvokeIntrinsic(dex_pc, can_skip_unwind, intr_id, args);
}
- llvm::Value* EmitInvokeIntrinsic5(unsigned dex_pc,
+ llvm::Value* EmitInvokeIntrinsic5(unsigned dex_pc, bool can_skip_unwind,
IntrinsicHelper::IntrinsicId intr_id,
llvm::Value* arg1,
llvm::Value* arg2,
@@ -357,12 +342,9 @@
llvm::Value* arg4,
llvm::Value* arg5) {
llvm::Value* args[] = { arg1, arg2, arg3, arg4, arg5 };
- return EmitInvokeIntrinsic(dex_pc, intr_id, args);
+ return EmitInvokeIntrinsic(dex_pc, can_skip_unwind, intr_id, args);
}
- compiler_llvm::RegCategory GetInferredRegCategory(unsigned dex_pc,
- unsigned reg_idx);
-
llvm::Value* EmitLoadConstantClass(unsigned dex_pc, uint32_t type_idx);
llvm::Value* EmitLoadArrayLength(llvm::Value* array);
@@ -501,6 +483,23 @@
bool EmitInstructions();
bool EmitInstruction(unsigned dex_pc, const Instruction* insn);
+
+ // TODO: Use high-level IR to do this
+ bool IsInstructionDirectToReturn(uint32_t dex_pc);
+
+ struct MethodInfo {
+ int64_t this_reg_idx;
+ bool this_will_not_be_null;
+ bool has_invoke;
+ bool need_shadow_frame_entry;
+ bool need_shadow_frame;
+ bool lazy_push_shadow_frame;
+ std::vector<bool> set_to_another_object;
+ };
+ MethodInfo method_info_;
+
+ void ComputeMethodInfo();
+
DISALLOW_COPY_AND_ASSIGN(DexLang);
};