diff options
author | Shih-wei Liao <sliao@google.com> | 2012-06-12 05:55:00 -0700 |
---|---|---|
committer | Shih-wei Liao <sliao@google.com> | 2012-09-15 04:15:17 -0700 |
commit | 21d28f510eb590f52810c83f1f3f37fe5f4adf46 (patch) | |
tree | f937b4d39aab322541b9b83cc5dd59d8e3f2fddd /src/greenland | |
parent | 0967a25d1482d8f7b4a26c5926263e7ffa63189f (diff) | |
download | art-21d28f510eb590f52810c83f1f3f37fe5f4adf46.zip art-21d28f510eb590f52810c83f1f3f37fe5f4adf46.tar.gz art-21d28f510eb590f52810c83f1f3f37fe5f4adf46.tar.bz2 |
GBC Expander. Removed lir.
Change-Id: If8d13e36f1e6d82c2a7f7bfec62b8fb41fd8cdaa
Diffstat (limited to 'src/greenland')
43 files changed, 4098 insertions, 2183 deletions
diff --git a/src/greenland/arm/arm_codegen_machine.h b/src/greenland/arm/arm_codegen_machine.h index c78ddf8..8639417 100644 --- a/src/greenland/arm/arm_codegen_machine.h +++ b/src/greenland/arm/arm_codegen_machine.h @@ -29,9 +29,27 @@ class ARMCodeGenMachine : public TargetCodeGenMachine { ARMCodeGenMachine(); virtual ~ARMCodeGenMachine(); - virtual TargetLIREmitter* CreateLIREmitter(const llvm::Function& func, - const OatCompilationUnit& cunit, - DexLang::Context& dex_lang_ctx) { + virtual TargetLIREmitter* CreateLIREmitter() { + return NULL; + } + + virtual const TargetDataLayout* GetDataLayout() const { + return NULL; + } + + virtual const TargetLIRInfo* GetLIRInfo() const { + return NULL; + } + + virtual const TargetRegisterInfo* GetRegisterInfo() const { + return NULL; + } + + virtual const char* GetConditionCodeName(unsigned cond) const { + return NULL; + } + + virtual TargetLIRBuilder* CreateLIRBuilder() { return NULL; } @@ -42,6 +60,10 @@ class ARMCodeGenMachine : public TargetCodeGenMachine { virtual TargetAssembler* GetAssembler() { return NULL; } + + virtual std::string PrettyTargeteLIR(const LIR& lir) const { + return ""; + } }; } // namespace greenland diff --git a/src/greenland/dalvik_reg.cc b/src/greenland/dalvik_reg.cc index eb4a89c..3155a8c 100644 --- a/src/greenland/dalvik_reg.cc +++ b/src/greenland/dalvik_reg.cc @@ -16,350 +16,201 @@ #include "dalvik_reg.h" -#include "dex_lang.h" #include "ir_builder.h" -#include "intrinsic_helper.h" - -#include <llvm/Function.h> - -using namespace art; -using namespace art::greenland; - -namespace { - - class DalvikArgReg : public DalvikReg { - public: - DalvikArgReg(DexLang& dex_lang, unsigned reg_idx, JType jty); - - virtual llvm::Value* GetValue(JType jty, JTypeSpace space); - virtual void SetValue(JType jty, JTypeSpace space, llvm::Value* value); - - private: - llvm::Value* reg_addr_; - JType jty_; - - inline void CheckJType(JType jty) const { - CHECK_EQ(jty, jty_) << "Get value of type " << jty << " from Dalvik " - "argument register v" << reg_idx_ << "(type: " - << jty_ << ") without type coercion!"; - return; - } - }; - - class DalvikLocalVarReg : public DalvikReg { - public: - DalvikLocalVarReg(DexLang& dex_lang, unsigned reg_idx); - - virtual llvm::Value* GetValue(JType jty, JTypeSpace space); - virtual void SetValue(JType jty, JTypeSpace space, llvm::Value* value); - - private: - llvm::Value* GetRawAddr(RegCategory cat); - - private: - llvm::Value* reg_32_; - llvm::Value* reg_64_; - llvm::Value* reg_obj_; - }; -} // anonymous namespace +#include "dex_lang.h" +namespace art { +namespace greenland { //---------------------------------------------------------------------------- // Dalvik Register //---------------------------------------------------------------------------- -DalvikReg* DalvikReg::CreateArgReg(DexLang& dex_lang, unsigned reg_idx, - JType jty) { - return new DalvikArgReg(dex_lang, reg_idx, jty); -} - -DalvikReg* DalvikReg::CreateLocalVarReg(DexLang& dex_lang, unsigned reg_idx) { - return new DalvikLocalVarReg(dex_lang, reg_idx); +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) { } -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) { +DalvikReg::~DalvikReg() { } -void DalvikReg::SetShadowEntry(llvm::Value* root_object) { +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), - root_object, irb_.getInt32(shadow_frame_entry_idx_)); + object, irb_.getInt32(shadow_frame_entry_idx_)); return; } -//---------------------------------------------------------------------------- -// Dalvik Argument Register -//---------------------------------------------------------------------------- -DalvikArgReg::DalvikArgReg(DexLang& dex_lang, unsigned reg_idx, JType jty) - : DalvikReg(dex_lang, reg_idx), jty_(jty) { - reg_addr_ = dex_lang_.AllocateDalvikReg(jty, reg_idx); - DCHECK(reg_addr_ != NULL); -} - -llvm::Value* DalvikArgReg::GetValue(JType jty, JTypeSpace space) { - DCHECK_NE(jty, kVoid) << "Dalvik register will never be void type"; - - switch (space) { - case kReg: - case kField: { - // Currently, kField is almost the same with kReg. - RegCategory cat = GetRegCategoryFromJType(jty_); - CHECK_EQ(cat, GetRegCategoryFromJType(jty)) << "Get value of type " << jty - << "has different register " - "category from the value " - "contained in the register" - << reg_idx_ << "(type: " - << jty_ << ")"; - switch (jty_) { - case kVoid: { - break; - } - case kBoolean: - case kChar: { - return irb_.CreateZExt(irb_.CreateLoad(reg_addr_), irb_.GetJIntTy()); - } - case kByte: - case kShort: { - return irb_.CreateSExt(irb_.CreateLoad(reg_addr_), irb_.GetJIntTy()); - } - case kFloat: { - return irb_.CreateBitCast(irb_.CreateLoad(reg_addr_), - irb_.GetJIntTy()); - } - case kDouble: { - return irb_.CreateBitCast(irb_.CreateLoad(reg_addr_), - irb_.GetJLongTy()); - } - case kInt: - case kLong: - case kObject: { - return irb_.CreateLoad(reg_addr_); - } - default: { - LOG(FATAL) << "Unexpected register type: " << jty; - break; - } - } - break; - } - case kArray: { - switch (jty) { - case kVoid: { - LOG(FATAL) << "Dalvik register with void type has no value"; - return NULL; - } - case kBoolean: { - CheckJType(jty); - // NOTE: In array type space, boolean is i8, while in accurate type - // space, boolean is i1. For the other cases, array type space is - // equal to accurate type space. - return irb_.CreateZExt(irb_.CreateLoad(reg_addr_), irb_.GetJByteTy()); - } - case kByte: - case kChar: - case kShort: - case kInt: - case kLong: - case kFloat: - case kDouble: - case kObject: { - CheckJType(jty); - return irb_.CreateLoad(reg_addr_); - } - default: { - LOG(FATAL) << "Unexpected register type: " << jty; - break; - } - } - } - case kAccurate: { - CheckJType(jty); - return irb_.CreateLoad(reg_addr_); - } +llvm::Type* DalvikReg::GetRegCategoryEquivSizeTy(IRBuilder& irb, RegCategory reg_cat) { + switch (reg_cat) { + case kRegCat1nr: return irb.GetJIntTy(); + case kRegCat2: return irb.GetJLongTy(); + case kRegObject: return irb.GetJObjectTy(); + default: + LOG(FATAL) << "Unknown register category: " << reg_cat; + return NULL; } - return NULL; } -void DalvikArgReg::SetValue(JType jty, JTypeSpace space, llvm::Value* value) { - if ((jty == jty_) && (space == kAccurate)) { - irb_.CreateStore(value, reg_addr_); - if (jty == kObject) { - SetShadowEntry(value); - } - } else { - LOG(FATAL) << "Normal .dex file doesn't use argument register for method-" - "local variable!"; +char DalvikReg::GetRegCategoryNamePrefix(RegCategory reg_cat) { + switch (reg_cat) { + case kRegCat1nr: return 'r'; + case kRegCat2: return 'w'; + case kRegObject: return 'p'; + default: + LOG(FATAL) << "Unknown register category: " << reg_cat; + return '\0'; } - return; } -//---------------------------------------------------------------------------- -// Dalvik Local Variable Register -//---------------------------------------------------------------------------- +inline llvm::Value* DalvikReg::RegCat1SExt(llvm::Value* value) { + return irb_.CreateSExt(value, irb_.GetJIntTy()); +} -DalvikLocalVarReg::DalvikLocalVarReg(DexLang& dex_lang, unsigned reg_idx) - : DalvikReg(dex_lang, reg_idx), reg_32_(NULL), reg_64_(NULL), - reg_obj_(NULL) { +inline llvm::Value* DalvikReg::RegCat1ZExt(llvm::Value* value) { + return irb_.CreateZExt(value, irb_.GetJIntTy()); } -llvm::Value* DalvikLocalVarReg::GetRawAddr(RegCategory cat) { - switch (cat) { - case kRegCat1nr: { - if (reg_32_ == NULL) { - reg_32_ = dex_lang_.AllocateDalvikReg(kInt, reg_idx_); - } - return reg_32_; - } - case kRegCat2: { - if (reg_64_ == NULL) { - reg_64_ = dex_lang_.AllocateDalvikReg(kLong, reg_idx_); - } - return reg_64_; - } - case kRegObject: { - if (reg_obj_ == NULL) { - reg_obj_ = dex_lang_.AllocateDalvikReg(kObject, reg_idx_); - } - return reg_obj_; - } - default: { - LOG(FATAL) << "Unexpected register category: " << cat; - return NULL; - } - } - return NULL; +inline llvm::Value* DalvikReg::RegCat1Trunc(llvm::Value* value, + llvm::Type* ty) { + return irb_.CreateTrunc(value, ty); } -llvm::Value* DalvikLocalVarReg::GetValue(JType jty, JTypeSpace space) { +llvm::Value* DalvikReg::GetValue(JType jty, JTypeSpace space) { DCHECK_NE(jty, kVoid) << "Dalvik register will never be void type"; + llvm::Value* value = NULL; switch (space) { - case kReg: - case kField: { - // float and double require bitcast to get their value from the integer - // register. - DCHECK((jty != kFloat) && (jty != kDouble)); - return irb_.CreateLoad(GetRawAddr(GetRegCategoryFromJType(jty))); - } - case kAccurate: - case kArray: { - switch (jty) { - case kVoid: { - LOG(FATAL) << "Dalvik register with void type has no value"; - return NULL; - } - case kBoolean: - case kChar: - case kByte: - case kShort: { - // NOTE: In array type space, boolean is truncated from i32 to i8, - // while in accurate type space, boolean is truncated from i32 to i1. - // For the other cases, array type space is equal to accurate type - // space. - return irb_.CreateTrunc(irb_.CreateLoad(GetRawAddr(kRegCat1nr)), - irb_.GetJType(jty, space)); - } - case kFloat: { - return irb_.CreateBitCast(irb_.CreateLoad(GetRawAddr(kRegCat1nr)), - irb_.GetJType(jty, space)); - } - case kDouble: { - return irb_.CreateBitCast(irb_.CreateLoad(GetRawAddr(kRegCat2)), - irb_.GetJType(jty, space)); - } - case kInt: - case kLong: - case kObject: { - return irb_.CreateLoad(GetRawAddr(GetRegCategoryFromJType(jty))); - } - default: { - LOG(FATAL) << "Unexpected register type: " << jty; - break; - } - } - } - default: { - LOG(FATAL) << "Unexpected register space: " << space; + case kReg: + case kField: + value = irb_.CreateLoad(GetAddr(jty)); + break; + + case kAccurate: + case kArray: + switch (jty) { + case kVoid: + LOG(FATAL) << "Dalvik register with void type has no value"; + return NULL; + + case kBoolean: + case kChar: + case kByte: + case kShort: + // NOTE: In array type space, boolean is truncated from i32 to i8, while + // in accurate type space, boolean is truncated from i32 to i1. + // For the other cases, array type space is equal to accurate type space. + value = RegCat1Trunc(irb_.CreateLoad(GetAddr(jty)), + irb_.GetJType(jty, space)); + break; + + case kInt: + case kLong: + case kFloat: + case kDouble: + case kObject: + value = irb_.CreateLoad(GetAddr(jty)); break; + + default: + LOG(FATAL) << "Unknown java type: " << jty; + return NULL; } + break; + + default: + LOG(FATAL) << "Couldn't GetValue of JType " << jty; + return NULL; + } + + if (jty == kFloat || jty == kDouble) { + value = irb_.CreateBitCast(value, irb_.GetJType(jty, space)); } - return NULL; + return value; } -void DalvikLocalVarReg::SetValue(JType jty, JTypeSpace space, - llvm::Value* value) { - DCHECK_NE(jty, kVoid) << "Dalvik register should never hold void type"; +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) { + value = irb_.CreateBitCast(value, irb_.GetJType(jty, kReg)); } switch (space) { - case kReg: - case kField: { - // float and double require bitcast to get their value from the integer - // register. - DCHECK((jty != kFloat) && (jty != kDouble)); - irb_.CreateStore(value, GetRawAddr(GetRegCategoryFromJType(jty))); - return; + case kReg: + case kField: + irb_.CreateStore(value, GetAddr(jty)); + return; + + case kAccurate: + case kArray: + switch (jty) { + case kVoid: + break; + + case kBoolean: + case kChar: + // NOTE: In accurate type space, we have to zero extend boolean from + // i1 to i32, and char from i16 to i32. In array type space, we have + // to zero extend boolean from i8 to i32, and char from i16 to i32. + irb_.CreateStore(RegCat1ZExt(value), GetAddr(jty)); + break; + + case kByte: + case kShort: + // NOTE: In accurate type space, we have to signed extend byte from + // i8 to i32, and short from i16 to i32. In array type space, we have + // to sign extend byte from i8 to i32, and short from i16 to i32. + irb_.CreateStore(RegCat1SExt(value), GetAddr(jty)); + break; + + case kInt: + case kLong: + case kFloat: + case kDouble: + case kObject: + irb_.CreateStore(value, GetAddr(jty)); + break; + + default: + LOG(FATAL) << "Unknown java type: " << jty; + } + } +} + +llvm::Value* DalvikReg::GetAddr(JType jty) { + switch (GetRegCategoryFromJType(jty)) { + case kRegCat1nr: + if (reg_32_ == NULL) { + reg_32_ = dex_lang_.AllocateDalvikReg(kRegCat1nr, reg_idx_); } - case kAccurate: - case kArray: { - switch (jty) { - case kVoid: { - break; - } - case kBoolean: - case kChar: { - // NOTE: In accurate type space, we have to zero extend boolean from - // i1 to i32, and char from i16 to i32. In array type space, we have - // to zero extend boolean from i8 to i32, and char from i16 to i32. - value = irb_.CreateZExt(value, irb_.GetJIntTy()); - irb_.CreateStore(value, GetRawAddr(kRegCat1nr)); - break; - } - case kByte: - case kShort: { - // NOTE: In accurate type space, we have to signed extend byte from - // i8 to i32, and short from i16 to i32. In array type space, we have - // to sign extend byte from i8 to i32, and short from i16 to i32. - value = irb_.CreateSExt(value, irb_.GetJIntTy()); - irb_.CreateStore(value, GetRawAddr(kRegCat1nr)); - break; - } - case kFloat: { - value = irb_.CreateBitCast(value, irb_.GetJIntTy()); - irb_.CreateStore(value, GetRawAddr(kRegCat1nr)); - break; - } - case kDouble: { - value = irb_.CreateBitCast(value, irb_.GetJLongTy()); - irb_.CreateStore(value, GetRawAddr(kRegCat2)); - break; - } - case kInt: - case kLong: - case kObject: { - irb_.CreateStore(value, GetRawAddr(GetRegCategoryFromJType(jty))); - break; - } - default: { - LOG(FATAL) << "Unexpected register type: " << jty; - return; - } - } - return; + return reg_32_; + + case kRegCat2: + if (reg_64_ == NULL) { + reg_64_ = dex_lang_.AllocateDalvikReg(kRegCat2, reg_idx_); } - default: { - LOG(FATAL) << "Unexpected register space: " << space; - return; + return reg_64_; + + case kRegObject: + if (reg_obj_ == NULL) { + reg_obj_ = dex_lang_.AllocateDalvikReg(kRegObject, reg_idx_); } + return reg_obj_; + + default: + LOG(FATAL) << "Unexpected register category: " + << GetRegCategoryFromJType(jty); + return NULL; } } +} // namespace greenland +} // namespace art diff --git a/src/greenland/dalvik_reg.h b/src/greenland/dalvik_reg.h index 78247cc..93524cc 100644 --- a/src/greenland/dalvik_reg.h +++ b/src/greenland/dalvik_reg.h @@ -14,11 +14,14 @@ * limitations under the License. */ -#ifndef ART_SRC_GREENLAND_DALVIK_REG_H_ -#define ART_SRC_GREENLAND_DALVIK_REG_H_ +#ifndef ART_SRC_COMPILER_LLVM_DALVIK_REG_H_ +#define ART_SRC_COMPILER_LLVM_DALVIK_REG_H_ #include "backend_types.h" +#include <stdint.h> +#include <string> + namespace llvm { class Type; class Value; @@ -27,41 +30,54 @@ namespace llvm { namespace art { namespace greenland { -class DexLang; class IRBuilder; +class DexLang; class DalvikReg { public: - static DalvikReg* CreateArgReg(DexLang& dex_lang, unsigned reg_idx, - JType jty); + static llvm::Type* GetRegCategoryEquivSizeTy(IRBuilder& irb, RegCategory reg_cat); - static DalvikReg* CreateLocalVarReg(DexLang& dex_lang, unsigned reg_idx); + static char GetRegCategoryNamePrefix(RegCategory reg_cat); - virtual ~DalvikReg() { } + DalvikReg(DexLang& dex_lang, unsigned reg_idx); + + ~DalvikReg(); + + llvm::Value* GetValue(JType jty, JTypeSpace space); - virtual llvm::Value* GetValue(JType jty, JTypeSpace space) = 0; llvm::Value* GetValue(char shorty, JTypeSpace space) { return GetValue(GetJTypeFromShorty(shorty), space); } - virtual void SetValue(JType jty, JTypeSpace space, llvm::Value* value) = 0; + void SetValue(JType jty, JTypeSpace space, llvm::Value* value); + void SetValue(char shorty, JTypeSpace space, llvm::Value* value) { return SetValue(GetJTypeFromShorty(shorty), space, value); } - protected: - DalvikReg(DexLang& dex_lang, unsigned reg_idx); + private: + void SetShadowEntry(llvm::Value* object); + + llvm::Value* GetAddr(JType jty); + + llvm::Value* RegCat1SExt(llvm::Value* value); + llvm::Value* RegCat1ZExt(llvm::Value* value); - void SetShadowEntry(llvm::Value* root_object); + llvm::Value* RegCat1Trunc(llvm::Value* value, llvm::Type* ty); - protected: DexLang& dex_lang_; IRBuilder& irb_; + unsigned reg_idx_; + int shadow_frame_entry_idx_; + + llvm::Value* reg_32_; + llvm::Value* reg_64_; + llvm::Value* reg_obj_; }; } // namespace greenland } // namespace art -#endif // ART_SRC_GREENLAND_DALVIK_REG_H_ +#endif // ART_SRC_COMPILER_LLVM_DALVIK_REG_H_ diff --git a/src/greenland/dex_lang.cc b/src/greenland/dex_lang.cc index 135cbd7..0e34492 100644 --- a/src/greenland/dex_lang.cc +++ b/src/greenland/dex_lang.cc @@ -18,8 +18,7 @@ #include "intrinsic_helper.h" -#include "atomic.h" -#include "inferred_reg_category_map.h" +#include "compiler_llvm/inferred_reg_category_map.h" #include "object.h" // FIXME: include this in oat_compilation_unit.h #include "oat_compilation_unit.h" #include "stl_util.h" @@ -41,21 +40,10 @@ namespace greenland { //---------------------------------------------------------------------------- // DexLang::Context //---------------------------------------------------------------------------- -DexLang::Context::Context() - : context_(), module_(NULL), ref_count_(1), mem_usage_(0) { - module_ = new llvm::Module("art", context_); - - // Initialize the contents of an empty module - // Type of "JavaObject" - llvm::StructType::create(context_, "JavaObject"); - // Type of "Method" - llvm::StructType::create(context_, "Method"); - // Type of "Thread" - llvm::StructType::create(context_, "Thread"); - +DexLang::Context::Context(llvm::Module& module) + : module_(module), intrinsic_helper_(NULL) { // Initalize the DexLang intrinsics - intrinsic_helper_ = new IntrinsicHelper(context_, *module_); - + intrinsic_helper_ = new IntrinsicHelper(GetLLVMContext(), module_); return; } @@ -64,42 +52,24 @@ DexLang::Context::~Context() { return; } -DexLang::Context& DexLang::Context::IncRef() { - android_atomic_inc(&ref_count_); - return *this; -} - -void DexLang::Context::DecRef() { - int32_t old_ref_count = android_atomic_dec(&ref_count_); - if (old_ref_count <= 1) { - delete this; - } - return; -} - -void DexLang::Context::AddMemUsageApproximation(size_t usage) { - android_atomic_add(static_cast<int32_t>(usage), &mem_usage_); - return; -} - //---------------------------------------------------------------------------- // Constructor, Destructor and APIs //---------------------------------------------------------------------------- DexLang::DexLang(DexLang::Context& context, Compiler& compiler, OatCompilationUnit& cunit) - : dex_lang_ctx_(context.IncRef()), compiler_(compiler), cunit_(cunit), + : dex_lang_ctx_(context), compiler_(compiler), cunit_(cunit), dex_file_(cunit.GetDexFile()), code_item_(cunit.GetCodeItem()), - dex_cache_(cunit.GetDexCache()), + dex_cache_(cunit.GetDexCache()), method_idx_(cunit.GetDexMethodIndex()), context_(context.GetLLVMContext()), module_(context.GetOutputModule()), intrinsic_helper_(context.GetIntrinsicHelper()), irb_(context.GetLLVMContext(), context.GetOutputModule(), context.GetIntrinsicHelper()), func_(NULL), reg_alloc_bb_(NULL), arg_reg_init_bb_(NULL), basic_blocks_(cunit.GetCodeItem()->insns_size_in_code_units_), - retval_(NULL), retval_jty_(kVoid), + retval_reg_(NULL), landing_pads_bb_(cunit.GetCodeItem()->tries_size_, NULL), exception_unwind_bb_(NULL), cur_try_item_offset(-1), - require_shadow_frame(false), num_shadow_frame_entries_(0) { + num_shadow_frame_entries_(0) { if (cunit.GetCodeItem()->tries_size_ > 0) { cur_try_item_offset = 0; } @@ -107,7 +77,7 @@ DexLang::DexLang(DexLang::Context& context, Compiler& compiler, } DexLang::~DexLang() { - dex_lang_ctx_.DecRef(); + delete retval_reg_; return; } @@ -119,44 +89,27 @@ llvm::Function* DexLang::Build() { !EmitPrologueLinkBasicBlocks() || !PrettyLayoutExceptionBasicBlocks() || !VerifyFunction() || + // CompilerLLVM has its own optimizer +#ifndef ART_USE_LLVM_COMPILER !OptimizeFunction() || - !RemoveRedundantPendingExceptionChecks()) { + !RemoveRedundantPendingExceptionChecks() || +#endif + 0) { return NULL; } - // NOTE: From statistic, the bitcode size is 4.5 times bigger than the - // Dex file. Besides, we have to convert the code unit into bytes. - // Thus, we got our magic number 9. - dex_lang_ctx_.AddMemUsageApproximation( - code_item_->insns_size_in_code_units_ * 900); - return func_; } -llvm::Value* DexLang::AllocateDalvikReg(JType jty, unsigned reg_idx) { - RegCategory cat = GetRegCategoryFromJType(jty); - llvm::Type* type = irb_.GetJType(jty, kAccurate); - - DCHECK_NE(type, static_cast<llvm::Type*>(NULL)); - +llvm::Value* DexLang::AllocateDalvikReg(RegCategory cat, unsigned reg_idx) { + // Get reg_type and reg_name from DalvikReg + llvm::Type* reg_type = DalvikReg::GetRegCategoryEquivSizeTy(irb_, cat); std::string reg_name; - switch (cat) { - case kRegCat1nr: { - reg_name = StringPrintf("r%u", reg_idx); - break; - } - case kRegCat2: { - reg_name = StringPrintf("w%u", reg_idx); - break; - } - case kRegObject: { - reg_name = StringPrintf("p%u", reg_idx); - break; - } - default: { - LOG(FATAL) << "Unknown register category for allocation: " << cat; - } - } + +#if !defined(NDEBUG) + StringAppendF(®_name, "%c%u", + DalvikReg::GetRegCategoryNamePrefix(cat), reg_idx); +#endif // Save current IR builder insert point DCHECK(reg_alloc_bb_ != NULL); @@ -164,13 +117,12 @@ llvm::Value* DexLang::AllocateDalvikReg(JType jty, unsigned reg_idx) { irb_.SetInsertPoint(reg_alloc_bb_); // Alloca - llvm::Value* reg_addr = irb_.CreateAlloca(type, 0, reg_name); + llvm::Value* reg_addr = irb_.CreateAlloca(reg_type, 0, reg_name); // Restore IRBuilder insert point irb_.restoreIP(irb_ip_original); DCHECK_NE(reg_addr, static_cast<llvm::Value*>(NULL)); - return reg_addr; } @@ -278,8 +230,8 @@ llvm::BasicBlock* DexLang::GetLandingPadBasicBlock(unsigned dex_pc) { llvm::Value* ti_offset_value = irb_.getInt32(ti_offset); llvm::Value* catch_handler_index_value = - EmitInvokeIntrinsic2(dex_pc, IntrinsicHelper::FindCatchBlock, - method_object_addr, ti_offset_value); + EmitInvokeIntrinsic2NoThrow(IntrinsicHelper::FindCatchBlock, + method_object_addr, ti_offset_value); // Switch instruction (Go to unwind basic block by default) llvm::SwitchInst* sw = @@ -356,11 +308,10 @@ void DexLang::EmitGuard_DivZeroException(unsigned dex_pc, irb_.CreateCondBr(equal_zero, block_exception, block_continue); irb_.SetInsertPoint(block_exception); - EmitUpdateDexPC(dex_pc); EmitInvokeIntrinsic(dex_pc, IntrinsicHelper::ThrowDivZeroException); - EmitBranchExceptionLandingPad(dex_pc); irb_.SetInsertPoint(block_continue); + return; } void DexLang::EmitGuard_NullPointerException(unsigned dex_pc, @@ -377,12 +328,11 @@ void DexLang::EmitGuard_NullPointerException(unsigned dex_pc, irb_.SetInsertPoint(block_exception); - EmitUpdateDexPC(dex_pc); EmitInvokeIntrinsic(dex_pc, IntrinsicHelper::ThrowNullPointerException, irb_.getInt32(dex_pc)); - EmitBranchExceptionLandingPad(dex_pc); irb_.SetInsertPoint(block_continue); + return; } void @@ -403,10 +353,8 @@ DexLang::EmitGuard_ArrayIndexOutOfBoundsException(unsigned dex_pc, irb_.SetInsertPoint(block_exception); - EmitUpdateDexPC(dex_pc); EmitInvokeIntrinsic2(dex_pc, IntrinsicHelper::ThrowIndexOutOfBounds, index, array_len); - EmitBranchExceptionLandingPad(dex_pc); irb_.SetInsertPoint(block_continue); return; @@ -420,7 +368,7 @@ void DexLang::EmitGuard_ArrayException(unsigned dex_pc, void DexLang::EmitGuard_ExceptionLandingPad(unsigned dex_pc) { llvm::Value* exception_pending = - EmitInvokeIntrinsic(dex_pc, IntrinsicHelper::IsExceptionPending); + EmitInvokeIntrinsicNoThrow(IntrinsicHelper::IsExceptionPending); llvm::BasicBlock* block_cont = CreateBasicBlockWithDexPC(dex_pc, "cont"); @@ -431,6 +379,7 @@ void DexLang::EmitGuard_ExceptionLandingPad(unsigned dex_pc) { } irb_.SetInsertPoint(block_cont); + return; } //---------------------------------------------------------------------------- @@ -446,7 +395,6 @@ void DexLang::EmitGuard_GarbageCollectionSuspend() { // Shadow Frame //---------------------------------------------------------------------------- void DexLang::EmitUpdateDexPC(unsigned dex_pc) { - require_shadow_frame = true; EmitInvokeIntrinsicNoThrow(IntrinsicHelper::UpdateDexPC, irb_.getInt32(dex_pc)); return; @@ -465,7 +413,7 @@ unsigned DexLang::AllocShadowFrameEntry(unsigned reg_idx) { // Code Generation //---------------------------------------------------------------------------- bool DexLang::CreateFunction() { - std::string func_name(PrettyMethod(cunit_.GetDexMethodIndex(), *dex_file_, + std::string func_name(PrettyMethod(method_idx_, *dex_file_, /* with_signature */false)); llvm::FunctionType* func_type = GetFunctionType(); @@ -521,54 +469,22 @@ llvm::FunctionType* DexLang::GetFunctionType() { return llvm::FunctionType::get(ret_type, args_type, false); } -bool DexLang::PrepareDalvikRegs() { - const unsigned num_regs = code_item_->registers_size_; - const unsigned num_ins = code_item_->ins_size_; - unsigned reg_idx = 0; - - // Registers v[0..(num_regs - num_ins - 1)] are used for local variable - for (; reg_idx < (num_regs - num_ins); reg_idx++) { - regs_.push_back(DalvikReg::CreateLocalVarReg(*this, reg_idx)); - } - - // Registers v[(num_regs - num_ins)..(num_regs - 1)] are used for input - // argument - uint32_t shorty_size; - const char* shorty = cunit_.GetShorty(&shorty_size); - - if (!cunit_.IsStatic()) { - // The first argument to non-static method is "this" object pointer - regs_.push_back(DalvikReg::CreateArgReg(*this, reg_idx++, kObject)); - } - - for (unsigned i = 1; i < shorty_size; i++) { - JType jty = GetJTypeFromShorty(shorty[i]); - regs_.push_back(DalvikReg::CreateArgReg(*this, reg_idx++, jty)); - reg_idx++; - - if (GetRegCategoryFromJType(jty) == kRegCat2) { - // Need a register pair to hold the value - regs_.push_back(NULL); - reg_idx++; - } - } - - CHECK_EQ(num_regs, regs_.size()); - - return true; -} - bool DexLang::EmitPrologue() { reg_alloc_bb_ = llvm::BasicBlock::Create(context_, "prologue.alloca", func_); arg_reg_init_bb_ = llvm::BasicBlock::Create(context_, "prologue.arginit", func_); - if (!PrepareDalvikRegs()) { - return false; + // Create register array + const unsigned num_regs = code_item_->registers_size_; + for (unsigned i = 0; i < num_regs; i++) { + regs_.push_back(new DalvikReg(*this, i)); } - //Store argument to dalvik register + // Register hold return value from invoke and filled-new-array + retval_reg_ = new DalvikReg(*this, num_regs); + + // Store argument to dalvik register irb_.SetInsertPoint(arg_reg_init_bb_); if (!EmitPrologueAssignArgRegister()) { return false; @@ -617,10 +533,6 @@ bool DexLang::EmitPrologueAssignArgRegister() { } bool DexLang::EmitPrologueAllcaShadowFrame() { - if (!require_shadow_frame) { - return true; - } - // Save current IR builder insert point llvm::IRBuilderBase::InsertPoint irb_ip_original = irb_.saveIP(); @@ -644,7 +556,13 @@ bool DexLang::PrettyLayoutExceptionBasicBlocks() { llvm::BasicBlock* last_non_exception_bb = &func_->back(); DCHECK(last_non_exception_bb != NULL); - DCHECK_NE(last_non_exception_bb, exception_unwind_bb_); + if (last_non_exception_bb == exception_unwind_bb_) { + // There's no other expcetion landing pads therefore the only exception + // basic blocks is for exception unwinding which is already the tail basic + // block of the function + return true; + } + if (exception_unwind_bb_ != NULL) { exception_unwind_bb_->moveAfter(last_non_exception_bb); } @@ -654,9 +572,14 @@ bool DexLang::PrettyLayoutExceptionBasicBlocks() { landing_pads_bb_end = landing_pads_bb_.rend(); landing_pads_bb_iter != landing_pads_bb_end; landing_pads_bb_iter++) { llvm::BasicBlock* landing_pads_bb = *landing_pads_bb_iter; + if (landing_pads_bb == NULL) { + continue; + } + // Move the successors (the cache handlers) first llvm::TerminatorInst* inst = landing_pads_bb->getTerminator(); CHECK(inst != NULL); + for (unsigned i = 0, e = inst->getNumSuccessors(); i != e; i++) { llvm::BasicBlock* catch_handler = inst->getSuccessor(i); // One of the catch handler is the unwind basic block which is settled @@ -665,8 +588,7 @@ bool DexLang::PrettyLayoutExceptionBasicBlocks() { catch_handler->moveAfter(last_non_exception_bb); } } - if (landing_pads_bb != NULL) { - DCHECK_NE(last_non_exception_bb, landing_pads_bb); + if (last_non_exception_bb != landing_pads_bb) { landing_pads_bb->moveAfter(last_non_exception_bb); } } @@ -677,7 +599,7 @@ bool DexLang::PrettyLayoutExceptionBasicBlocks() { bool DexLang::VerifyFunction() { if (llvm::verifyFunction(*func_, llvm::PrintMessageAction)) { LOG(INFO) << "Verification failed on function: " - << PrettyMethod(cunit_.GetDexMethodIndex(), *dex_file_); + << PrettyMethod(method_idx_, *dex_file_); return false; } return true; @@ -813,39 +735,18 @@ llvm::Value* DexLang::EmitGetCurrentThread() { return EmitInvokeIntrinsicNoThrow(IntrinsicHelper::GetCurrentThread); } -llvm::Value* -DexLang::EmitInvokeIntrinsicNoThrow(IntrinsicHelper::IntrinsicId intr_id) { - DCHECK(IntrinsicHelper::GetAttr(intr_id) & IntrinsicHelper::kAttrNoThrow); - return irb_.CreateCall(intrinsic_helper_.GetIntrinsicFunction(intr_id)); +void DexLang::EmitMarkGCCard(llvm::Value* value, llvm::Value* target_addr) { + EmitInvokeIntrinsic2NoThrow(IntrinsicHelper::MarkGCCard, value, target_addr); + return; } llvm::Value* DexLang::EmitInvokeIntrinsicNoThrow(IntrinsicHelper::IntrinsicId intr_id, llvm::ArrayRef<llvm::Value*> args) { - llvm::Function* intr = intrinsic_helper_.GetIntrinsicFunction(intr_id); DCHECK(IntrinsicHelper::GetAttr(intr_id) & IntrinsicHelper::kAttrNoThrow); - return irb_.CreateCall(intr, args); -} -llvm::Value* -DexLang::EmitInvokeIntrinsic(unsigned dex_pc, - IntrinsicHelper::IntrinsicId intr_id) { llvm::Function* intr = intrinsic_helper_.GetIntrinsicFunction(intr_id); - unsigned intr_attr = IntrinsicHelper::GetAttr(intr_id); - bool may_throw = !(intr_attr & IntrinsicHelper::kAttrNoThrow); - - // Setup PC before invocation when the intrinsics may generate the exception - if (may_throw) { - EmitUpdateDexPC(dex_pc); - } - - llvm::Value* ret_val = irb_.CreateCall(intr); - - if (may_throw) { - EmitGuard_ExceptionLandingPad(dex_pc); - } - - return ret_val; + return ((args.empty()) ? irb_.CreateCall(intr) : irb_.CreateCall(intr, args)); } llvm::Value* DexLang::EmitInvokeIntrinsic(unsigned dex_pc, @@ -853,38 +754,155 @@ llvm::Value* DexLang::EmitInvokeIntrinsic(unsigned dex_pc, llvm::ArrayRef<llvm::Value*> args) { llvm::Function* intr = intrinsic_helper_.GetIntrinsicFunction(intr_id); unsigned intr_attr = IntrinsicHelper::GetAttr(intr_id); - bool may_throw = !(intr_attr & IntrinsicHelper::kAttrNoThrow); + DCHECK(!(intr_attr & IntrinsicHelper::kAttrNoThrow)); // Setup PC before invocation when the intrinsics may generate the exception - if (may_throw) { - EmitUpdateDexPC(dex_pc); - } + EmitUpdateDexPC(dex_pc); - llvm::Value* ret_val = irb_.CreateCall(intr, args); + llvm::Value* ret_val = ((args.empty()) ? irb_.CreateCall(intr) : + irb_.CreateCall(intr, args)); - if (may_throw) { + if (intr_attr & IntrinsicHelper::kAttrDoThrow) { + // Directly branch to exception landingpad when the intrinsic is known to + // throw exception always + EmitBranchExceptionLandingPad(dex_pc); + } else { EmitGuard_ExceptionLandingPad(dex_pc); } return ret_val; } -RegCategory DexLang::GetInferredRegCategory(unsigned dex_pc, unsigned reg_idx) { - Compiler::MethodReference mref(dex_file_, cunit_.GetDexMethodIndex()); +compiler_llvm::RegCategory DexLang::GetInferredRegCategory(unsigned dex_pc, + unsigned reg_idx) { + Compiler::MethodReference mref(dex_file_, method_idx_); - const InferredRegCategoryMap* map = + const compiler_llvm::InferredRegCategoryMap* map = verifier::MethodVerifier::GetInferredRegCategoryMap(mref); - CHECK_NE(map, static_cast<InferredRegCategoryMap*>(NULL)); + CHECK_NE(map, static_cast<compiler_llvm::InferredRegCategoryMap*>(NULL)); return map->GetRegCategory(dex_pc, reg_idx); } +llvm::Value* DexLang::EmitLoadConstantClass(unsigned dex_pc, + uint32_t type_idx) { + llvm::Value* type_idx_value = irb_.getInt32(type_idx); + + llvm::Value* method_object_addr = EmitLoadMethodObjectAddr(); + + llvm::Value* thread_object_addr = EmitGetCurrentThread(); + + if (!compiler_.CanAccessTypeWithoutChecks(method_idx_, dex_cache_, + *dex_file_, type_idx)) { + return EmitInvokeIntrinsic3(dex_pc, IntrinsicHelper::InitializeTypeAndVerifyAccess, + type_idx_value, method_object_addr, + thread_object_addr); + } else { + // Try to load the class (type) object from the dex cache + llvm::Value* type_object_addr = + EmitInvokeIntrinsicNoThrow(IntrinsicHelper::LoadTypeFromDexCache, + type_idx_value); + + 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); + + // Failback routine to load the class object + irb_.SetInsertPoint(block_load_class); + + llvm::Value* loaded_type_object_addr = + EmitInvokeIntrinsic3(dex_pc, IntrinsicHelper::InitializeType, + type_idx_value, method_object_addr, + thread_object_addr); + + 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* DexLang::EmitLoadArrayLength(llvm::Value* array) { // Load array length return EmitInvokeIntrinsicNoThrow(IntrinsicHelper::ArrayLength, array); } +llvm::Value* DexLang::EmitAllocNewArray(unsigned dex_pc, int32_t length, + uint32_t type_idx, + bool is_filled_new_array) { + bool skip_access_check = compiler_.CanAccessTypeWithoutChecks(method_idx_, + dex_cache_, + *dex_file_, + type_idx); + + llvm::Value* array_length_value; + IntrinsicHelper::IntrinsicId intrinsic; + + // Select intrinsic and load the array length + if (is_filled_new_array) { + intrinsic = + skip_access_check ? IntrinsicHelper::CheckAndAllocArray : + IntrinsicHelper::CheckAndAllocArrayWithAccessCheck; + array_length_value = irb_.getInt32(length); + } else { + intrinsic = + skip_access_check ? IntrinsicHelper::AllocArray : + IntrinsicHelper::AllocArrayWithAccessCheck; + array_length_value = EmitLoadDalvikReg(length, kInt, kAccurate); + } + + llvm::Constant* type_index_value = irb_.getInt32(type_idx); + + llvm::Value* method_object_addr = EmitLoadMethodObjectAddr(); + + llvm::Value* thread_object_addr = EmitGetCurrentThread(); + + llvm::Value* array_addr = EmitInvokeIntrinsic4(dex_pc, intrinsic, + type_index_value, + method_object_addr, + array_length_value, + thread_object_addr); + + return array_addr; +} + +llvm::Value* DexLang::EmitCompareResultSelection(llvm::Value* cmp_eq, + llvm::Value* cmp_lt) { + + llvm::Constant* zero = irb_.GetJInt(0); + llvm::Constant* pos1 = irb_.GetJInt(1); + llvm::Constant* neg1 = irb_.GetJInt(-1); + + llvm::Value* result_lt = irb_.CreateSelect(cmp_lt, neg1, pos1); + llvm::Value* result_eq = irb_.CreateSelect(cmp_eq, zero, result_lt); + + return result_eq; +} + llvm::Value* DexLang::EmitLoadStaticStorage(unsigned dex_pc, unsigned type_idx) { llvm::BasicBlock* block_load_static = @@ -896,8 +914,8 @@ DexLang::EmitLoadStaticStorage(unsigned dex_pc, unsigned type_idx) { // Load static storage from dex cache llvm::Value* storage_object_addr = - EmitInvokeIntrinsic(dex_pc, IntrinsicHelper::LoadClassSSBFromDexCache, - type_idx_value); + EmitInvokeIntrinsicNoThrow(IntrinsicHelper::LoadClassSSBFromDexCache, + type_idx_value); llvm::BasicBlock* block_original = irb_.GetInsertBlock(); @@ -1002,6 +1020,38 @@ llvm::Value* DexLang::EmitIntArithmResultComputation(unsigned dex_pc, return NULL; } +llvm::Value* +DexLang::EmitIntShiftArithmResultComputation(uint32_t dex_pc, + llvm::Value* lhs, + llvm::Value* rhs, + IntShiftArithmKind arithm, + JType op_jty) { + DCHECK(op_jty == kInt || op_jty == kLong) << op_jty; + + if (op_jty == kInt) { + rhs = irb_.CreateAnd(rhs, 0x1f); + } else { + llvm::Value* masked_rhs = irb_.CreateAnd(rhs, 0x3f); + rhs = irb_.CreateZExt(masked_rhs, irb_.GetJLongTy()); + } + + switch (arithm) { + case kIntArithm_Shl: { + return irb_.CreateShl(lhs, rhs); + } + case kIntArithm_Shr: { + return irb_.CreateAShr(lhs, rhs); + } + case kIntArithm_UShr: { + return irb_.CreateLShr(lhs, rhs); + } + default: { + LOG(FATAL) << "Unknown integer shift arithmetic kind: " << arithm; + return NULL; + } + } +} + llvm::Value* DexLang::EmitIntDivRemResultComputation(unsigned dex_pc, llvm::Value* dividend, llvm::Value* divisor, @@ -1035,7 +1085,7 @@ llvm::Value* DexLang::EmitIntDivRemResultComputation(unsigned dex_pc, } } - return EmitInvokeIntrinsic2(dex_pc, arithm_intrinsic, dividend, divisor); + return EmitInvokeIntrinsic2NoThrow(arithm_intrinsic, dividend, divisor); } //---------------------------------------------------------------------------- @@ -1069,17 +1119,8 @@ void DexLang::EmitInsn_MoveResult(unsigned dex_pc, const Instruction* insn, JType jty) { DecodedInstruction dec_insn(insn); - CHECK(retval_ != NULL) << "move-result must immediately after an invoke-kind " - "instruction"; - // Check the type - CHECK_EQ(irb_.GetJType(jty, kReg), irb_.GetJType(retval_jty_, kReg)) - << "Mismatch type between the value from the most recent invoke-kind " - "instruction (" << retval_jty_ << ") and the kind of move-result " - "used! (" << jty << ")"; - - EmitStoreDalvikReg(dec_insn.vA, retval_jty_, kReg, retval_); - - retval_ = NULL; + llvm::Value* src_value = EmitLoadDalvikRetValReg(jty, kReg); + EmitStoreDalvikReg(dec_insn.vA, jty, kReg, src_value); irb_.CreateBr(GetNextBasicBlock(dex_pc)); return; @@ -1097,6 +1138,18 @@ void DexLang::EmitInsn_MoveException(unsigned dex_pc, const Instruction* insn) { return; } +void DexLang::EmitInsn_ThrowException(unsigned dex_pc, + const Instruction* insn) { + DecodedInstruction dec_insn(insn); + + llvm::Value* exception_addr = + EmitLoadDalvikReg(dec_insn.vA, kObject, kAccurate); + + EmitInvokeIntrinsic(dex_pc, IntrinsicHelper::ThrowException, exception_addr); + + return; +} + void DexLang::EmitInsn_ReturnVoid(unsigned dex_pc, const Instruction* insn) { // Garbage collection safe-point EmitGuard_GarbageCollectionSuspend(); @@ -1192,18 +1245,230 @@ void DexLang::EmitInsn_LoadConstantString(unsigned dex_pc, uint32_t string_idx = dec_insn.vB; llvm::Value* string_idx_value = irb_.getInt32(string_idx); - IntrinsicHelper::IntrinsicId intrinsic = IntrinsicHelper::UnknownId; - if (compiler_.CanAssumeStringIsPresentInDexCache(dex_cache_, string_idx)) { - intrinsic = IntrinsicHelper::ConstStringFast; + llvm::Value* string_addr = + EmitInvokeIntrinsicNoThrow(IntrinsicHelper::LoadStringFromDexCache, + string_idx_value); + + 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"); + + // 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); + + // String is resolved, go to next basic block. + irb_.SetInsertPoint(block_str_exist); + EmitStoreDalvikReg(dec_insn.vA, kObject, kAccurate, string_addr); + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + + // String is not resolved yet, resolve it now. + irb_.SetInsertPoint(block_str_resolve); + + llvm::Value* method_object_addr = EmitLoadMethodObjectAddr(); + + string_addr = EmitInvokeIntrinsic2(dex_pc, IntrinsicHelper::ResolveString, + method_object_addr, string_idx_value); + } + + EmitStoreDalvikReg(dec_insn.vA, kObject, kAccurate, string_addr); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + +void DexLang::EmitInsn_LoadConstantClass(unsigned dex_pc, + const Instruction* insn) { + DecodedInstruction dec_insn(insn); + + llvm::Value* type_object_addr = EmitLoadConstantClass(dex_pc, dec_insn.vB); + EmitStoreDalvikReg(dec_insn.vA, kObject, kAccurate, type_object_addr); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + +void DexLang::EmitInsn_MonitorEnter(unsigned dex_pc, const Instruction* insn) { + DecodedInstruction dec_insn(insn); + + llvm::Value* object_addr = + EmitLoadDalvikReg(dec_insn.vA, kObject, kAccurate); + + EmitGuard_NullPointerException(dex_pc, object_addr); + + llvm::Value* thread_object_addr = EmitGetCurrentThread(); + + EmitInvokeIntrinsic2NoThrow(IntrinsicHelper::LockObject, + object_addr, thread_object_addr); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + +void DexLang::EmitInsn_MonitorExit(unsigned dex_pc, const Instruction* insn) { + DecodedInstruction dec_insn(insn); + + llvm::Value* object_addr = + EmitLoadDalvikReg(dec_insn.vA, kObject, kAccurate); + + EmitGuard_NullPointerException(dex_pc, object_addr); + + llvm::Value* thread_object_addr = EmitGetCurrentThread(); + + EmitInvokeIntrinsic2(dex_pc, IntrinsicHelper::UnlockObject, + object_addr, thread_object_addr); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + +void DexLang::EmitInsn_CheckCast(unsigned dex_pc, const Instruction* insn) { + DecodedInstruction dec_insn(insn); + + llvm::BasicBlock* block_test_class = + CreateBasicBlockWithDexPC(dex_pc, "test_class"); + + llvm::BasicBlock* block_test_sub_class = + CreateBasicBlockWithDexPC(dex_pc, "test_sub_class"); + + llvm::Value* object_addr = + EmitLoadDalvikReg(dec_insn.vA, kObject, kAccurate); + + // 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, + GetNextBasicBlock(dex_pc), + 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, dec_insn.vB); + 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); + + llvm::Value* equal_class = + irb_.CreateICmpEQ(type_object_addr, object_type_object_addr); + + irb_.CreateCondBr(equal_class, + GetNextBasicBlock(dex_pc), + block_test_sub_class); + + // Test: Is the object instantiated from the subclass of the given class? + irb_.SetInsertPoint(block_test_sub_class); + + EmitInvokeIntrinsic2(dex_pc, IntrinsicHelper::CheckCast, + type_object_addr, object_type_object_addr); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + +void DexLang::EmitInsn_InstanceOf(unsigned dex_pc, const Instruction* insn) { + DecodedInstruction dec_insn(insn); + + llvm::Constant* zero = irb_.GetJInt(0); + llvm::Constant* one = irb_.GetJInt(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::Value* object_addr = + EmitLoadDalvikReg(dec_insn.vB, kObject, kAccurate); + + // 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); + EmitStoreDalvikReg(dec_insn.vA, kInt, kAccurate, zero); + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + + // Test: Is the object instantiated from the given class? + irb_.SetInsertPoint(block_test_class); + llvm::Value* type_object_addr = EmitLoadConstantClass(dex_pc, dec_insn.vC); + 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); + + 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); + EmitStoreDalvikReg(dec_insn.vA, kInt, kAccurate, one); + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + + // Test: Is the object instantiated from the subclass of the given class? + irb_.SetInsertPoint(block_test_sub_class); + + llvm::Value* result = + EmitInvokeIntrinsic2NoThrow(IntrinsicHelper::IsAssignable, + type_object_addr, object_type_object_addr); + + EmitStoreDalvikReg(dec_insn.vA, kInt, kAccurate, result); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + +void DexLang::EmitInsn_NewInstance(unsigned dex_pc, const Instruction* insn) { + DecodedInstruction dec_insn(insn); + + IntrinsicHelper::IntrinsicId alloc_intrinsic; + if (compiler_.CanAccessInstantiableTypeWithoutChecks(method_idx_, + dex_cache_, + *dex_file_, + dec_insn.vB)) { + alloc_intrinsic = IntrinsicHelper::AllocObject; } else { - intrinsic = IntrinsicHelper::ConstString; + alloc_intrinsic = IntrinsicHelper::AllocObjectWithAccessCheck; } - llvm::Value* string_addr = - EmitInvokeIntrinsic(dex_pc, intrinsic, string_idx_value); + llvm::Constant* type_index_value = irb_.getInt32(dec_insn.vB); - EmitStoreDalvikReg(dec_insn.vA, kObject, kAccurate, string_addr); + llvm::Value* method_object_addr = EmitLoadMethodObjectAddr(); + + llvm::Value* thread_object_addr = EmitGetCurrentThread(); + + llvm::Value* object_addr = EmitInvokeIntrinsic3(dex_pc, alloc_intrinsic, + type_index_value, + method_object_addr, + thread_object_addr); + + EmitStoreDalvikReg(dec_insn.vA, kObject, kAccurate, object_addr); irb_.CreateBr(GetNextBasicBlock(dex_pc)); return; @@ -1239,13 +1504,8 @@ void DexLang::EmitInsn_ArrayLength(unsigned dex_pc, const Instruction* insn) { void DexLang::EmitInsn_NewArray(unsigned dex_pc, const Instruction* insn) { DecodedInstruction dec_insn(insn); - // Prepare argument to intrinsic - llvm::Value* array_length = EmitLoadDalvikReg(dec_insn.vB, kInt, kAccurate); - llvm::Value* type_idx = irb_.getInt32(dec_insn.vC); - - llvm::Value* array_addr = - EmitInvokeIntrinsic2(dex_pc, IntrinsicHelper::NewArray, - array_length, type_idx); + llvm::Value* array_addr = EmitAllocNewArray(dex_pc, dec_insn.vB, dec_insn.vC, + /* is_filled_new_array */false); EmitStoreDalvikReg(dec_insn.vA, kObject, kAccurate, array_addr); @@ -1253,25 +1513,116 @@ void DexLang::EmitInsn_NewArray(unsigned dex_pc, const Instruction* insn) { return; } +void DexLang::EmitInsn_FilledNewArray(unsigned dex_pc, const Instruction* insn, + bool is_range) { + DecodedInstruction dec_insn(insn); + + llvm::Value* object_addr = EmitAllocNewArray(dex_pc, dec_insn.vA, dec_insn.vB, + /* is_filled_new_array */true); + + if (dec_insn.vA > 0) { + // 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 + + // NOTE: Currently filled-new-array only supports 'L', '[', and 'I' as the + // element, therefore the element is either a primitive int or a reference + JType element_jty = ((type_desc[1] == 'I') ? kInt : kObject); + + std::vector<llvm::Value*> args; + // Destination array object + args.push_back(object_addr); + // Type of the array element + // + // FIXME: Actually, dec_insn.vB (type_idx of the element) should be here to + // the intrinsic instead of element_jty. However, since GBCExpander cannot + // know which dex_file this filled-new-array instruction associated with, it + // is unable to know the exact type of the type_idx is. In the near future, + // metadata will be used to record the type information (i.e., type_desc) + args.push_back(irb_.getInt32(element_jty)); + + for (uint32_t i = 0; i < dec_insn.vA; ++i) { + int reg_index; + if (is_range) { + reg_index = dec_insn.vC + i; + } else { + reg_index = dec_insn.arg[i]; + } + + llvm::Value* reg_value = + EmitLoadDalvikReg(reg_index, element_jty, kAccurate); + + args.push_back(reg_value); + } + + EmitInvokeIntrinsicNoThrow(IntrinsicHelper::FilledNewArray, args); + } + + EmitStoreDalvikRetValReg(kObject, kAccurate, object_addr); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + +void DexLang::EmitInsn_FillArrayData(unsigned dex_pc, const Instruction* insn) { + DecodedInstruction dec_insn(insn); + + // Read the payload + int32_t payload_offset = static_cast<int32_t>(dex_pc) + + static_cast<int32_t>(dec_insn.vB); + + const Instruction::ArrayDataPayload* payload = + reinterpret_cast<const Instruction::ArrayDataPayload*>( + code_item_->insns_ + payload_offset); + + // Load array object + llvm::Value* array_addr = EmitLoadDalvikReg(dec_insn.vA, kObject, kAccurate); + + 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::Value* method_object_addr = EmitLoadMethodObjectAddr(); + + EmitInvokeIntrinsic4(dex_pc, IntrinsicHelper::FillArrayData, + method_object_addr, irb_.getInt32(dex_pc), array_addr, + irb_.getInt32(payload_offset)); + } + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + void DexLang::EmitInsn_UnaryConditionalBranch(unsigned dex_pc, const Instruction* insn, CondBranchKind cond) { DecodedInstruction dec_insn(insn); - int8_t src_reg_cat = GetInferredRegCategory(dex_pc, dec_insn.vA); + compiler_llvm::RegCategory src_reg_cat = + GetInferredRegCategory(dex_pc, dec_insn.vA); - DCHECK_NE(kRegUnknown, src_reg_cat); - DCHECK_NE(kRegCat2, src_reg_cat); + DCHECK_NE(compiler_llvm::kRegUnknown, src_reg_cat); + DCHECK_NE(compiler_llvm::kRegCat2, src_reg_cat); int32_t branch_offset = dec_insn.vB; llvm::Value* src1_value; llvm::Value* src2_value; - if (src_reg_cat == kRegZero) { + if (src_reg_cat == compiler_llvm::kRegZero) { src1_value = irb_.getInt32(0); src2_value = irb_.getInt32(0); - } else if (src_reg_cat == kRegCat1nr) { + } else if (src_reg_cat == compiler_llvm::kRegCat1nr) { src1_value = EmitLoadDalvikReg(dec_insn.vA, kInt, kReg); src2_value = irb_.getInt32(0); } else { @@ -1341,8 +1692,7 @@ void DexLang::EmitInsn_BinaryConditionalBranch(unsigned dex_pc, } } - llvm::Value* cond_value = - EmitConditionResult(src1_value, src2_value, cond); + llvm::Value* cond_value = EmitConditionResult(src1_value, src2_value, cond); irb_.CreateCondBr(cond_value, GetBasicBlock(dex_pc + branch_offset), @@ -1350,6 +1700,93 @@ void DexLang::EmitInsn_BinaryConditionalBranch(unsigned dex_pc, return; } +void DexLang::EmitInsn_PackedSwitch(unsigned dex_pc, const Instruction* insn) { + DecodedInstruction dec_insn(insn); + + int32_t payload_offset = static_cast<int32_t>(dex_pc) + + static_cast<int32_t>(dec_insn.vB); + + const Instruction::PackedSwitchPayload* payload = + reinterpret_cast<const Instruction::PackedSwitchPayload*>( + code_item_->insns_ + payload_offset); + + llvm::Value* value = EmitLoadDalvikReg(dec_insn.vA, kInt, kAccurate); + + llvm::SwitchInst* sw = + irb_.CreateSwitch(value, GetNextBasicBlock(dex_pc), payload->case_count); + + for (uint16_t i = 0; i < payload->case_count; ++i) { + sw->addCase(irb_.getInt32(payload->first_key + i), + GetBasicBlock(dex_pc + payload->targets[i])); + } + return; +} + +void DexLang::EmitInsn_SparseSwitch(unsigned dex_pc, const Instruction* insn) { + DecodedInstruction dec_insn(insn); + + int32_t payload_offset = static_cast<int32_t>(dex_pc) + + static_cast<int32_t>(dec_insn.vB); + + const Instruction::SparseSwitchPayload* payload = + reinterpret_cast<const Instruction::SparseSwitchPayload*>( + code_item_->insns_ + payload_offset); + + const int32_t* keys = payload->GetKeys(); + const int32_t* targets = payload->GetTargets(); + + llvm::Value* value = EmitLoadDalvikReg(dec_insn.vA, kInt, kAccurate); + + llvm::SwitchInst* sw = + irb_.CreateSwitch(value, GetNextBasicBlock(dex_pc), payload->case_count); + + for (size_t i = 0; i < payload->case_count; ++i) { + sw->addCase(irb_.getInt32(keys[i]), GetBasicBlock(dex_pc + targets[i])); + } + return; +} + +void DexLang::EmitInsn_FPCompare(unsigned dex_pc, const Instruction* insn, + JType fp_jty, bool gt_bias) { + DecodedInstruction dec_insn(insn); + + DCHECK(fp_jty == kFloat || fp_jty == kDouble) << "JType: " << fp_jty; + + llvm::Value* src1_value = EmitLoadDalvikReg(dec_insn.vB, fp_jty, kAccurate); + llvm::Value* src2_value = EmitLoadDalvikReg(dec_insn.vC, fp_jty, kAccurate); + + llvm::Value* cmp_eq = irb_.CreateFCmpOEQ(src1_value, src2_value); + llvm::Value* cmp_lt; + + if (gt_bias) { + cmp_lt = irb_.CreateFCmpOLT(src1_value, src2_value); + } else { + cmp_lt = irb_.CreateFCmpULT(src1_value, src2_value); + } + + llvm::Value* result = EmitCompareResultSelection(cmp_eq, cmp_lt); + EmitStoreDalvikReg(dec_insn.vA, kInt, kAccurate, result); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + +void DexLang::EmitInsn_LongCompare(unsigned dex_pc, const Instruction* insn) { + DecodedInstruction dec_insn(insn); + + llvm::Value* src1_value = EmitLoadDalvikReg(dec_insn.vB, kLong, kAccurate); + llvm::Value* src2_value = EmitLoadDalvikReg(dec_insn.vC, kLong, kAccurate); + + llvm::Value* cmp_eq = irb_.CreateICmpEQ(src1_value, src2_value); + llvm::Value* cmp_lt = irb_.CreateICmpSLT(src1_value, src2_value); + + llvm::Value* result = EmitCompareResultSelection(cmp_eq, cmp_lt); + EmitStoreDalvikReg(dec_insn.vA, kInt, kAccurate, result); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + void DexLang::EmitInsn_AGet(unsigned dex_pc, const Instruction* insn, JType elem_jty) { DecodedInstruction dec_insn(insn); @@ -1398,10 +1835,9 @@ void DexLang::EmitInsn_AGet(unsigned dex_pc, const Instruction* insn, EmitGuard_ArrayException(dex_pc, array_addr, index_value); - llvm::Value* array_element_value = EmitInvokeIntrinsic2(dex_pc, - aget_intrinsic, - array_addr, - index_value); + llvm::Value* array_element_value = EmitInvokeIntrinsic2NoThrow(aget_intrinsic, + array_addr, + index_value); EmitStoreDalvikReg(dec_insn.vA, elem_jty, kArray, array_element_value); @@ -1451,24 +1887,218 @@ void DexLang::EmitInsn_APut(unsigned dex_pc, const Instruction* insn, } } - // Construct argument list passed to the intrinsic - llvm::Value* elem_addr = EmitLoadDalvikReg(dec_insn.vA, elem_jty, kAccurate); llvm::Value* array_addr = EmitLoadDalvikReg(dec_insn.vB, kObject, kAccurate); llvm::Value* index_value = EmitLoadDalvikReg(dec_insn.vC, kInt, kAccurate); EmitGuard_ArrayException(dex_pc, array_addr, index_value); + llvm::Value* new_value = EmitLoadDalvikReg(dec_insn.vA, elem_jty, kArray); + // Check the type if an object is putting if (elem_jty == kObject) { EmitInvokeIntrinsic2(dex_pc, IntrinsicHelper::CheckPutArrayElement, - elem_addr, array_addr); + new_value, array_addr); + + EmitMarkGCCard(new_value, array_addr); } - EmitInvokeIntrinsic3(dex_pc, aput_intrinsic, - elem_addr, array_addr, index_value); + EmitInvokeIntrinsic3NoThrow(aput_intrinsic, new_value, array_addr, index_value); irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + +void DexLang::EmitInsn_IGet(unsigned dex_pc, const Instruction* insn, + JType field_jty) { + DecodedInstruction dec_insn(insn); + + uint32_t reg_idx = dec_insn.vB; + uint32_t field_idx = dec_insn.vC; + + llvm::Value* object_addr = EmitLoadDalvikReg(reg_idx, kObject, kAccurate); + + EmitGuard_NullPointerException(dex_pc, object_addr); + + int field_offset; + bool is_volatile; + bool is_fast_path = compiler_.ComputeInstanceFieldInfo(field_idx, &cunit_, + field_offset, + is_volatile, + /* is_put */false); + // Select corresponding intrinsic accroding to the field type and is_fast_path + IntrinsicHelper::IntrinsicId iget_intrinsic = IntrinsicHelper::UnknownId; + + switch (field_jty) { + case kInt: { + iget_intrinsic = + (is_fast_path) ? IntrinsicHelper::InstanceFieldGetFast : + IntrinsicHelper::InstanceFieldGet; + break; + } + case kLong: { + iget_intrinsic = + (is_fast_path) ? IntrinsicHelper::InstanceFieldGetWideFast : + IntrinsicHelper::InstanceFieldGetWide; + break; + } + case kObject: { + iget_intrinsic = + (is_fast_path) ? IntrinsicHelper::InstanceFieldGetObjectFast : + IntrinsicHelper::InstanceFieldGetObject; + break; + } + case kBoolean: { + iget_intrinsic = + (is_fast_path) ? IntrinsicHelper::InstanceFieldGetBooleanFast : + IntrinsicHelper::InstanceFieldGetBoolean; + break; + } + case kByte: { + iget_intrinsic = + (is_fast_path) ? IntrinsicHelper::InstanceFieldGetByteFast : + IntrinsicHelper::InstanceFieldGetByte; + break; + } + case kChar: { + iget_intrinsic = + (is_fast_path) ? IntrinsicHelper::InstanceFieldGetCharFast : + IntrinsicHelper::InstanceFieldGetChar; + break; + } + case kShort: { + iget_intrinsic = + (is_fast_path) ? IntrinsicHelper::InstanceFieldGetShortFast : + IntrinsicHelper::InstanceFieldGetShort; + break; + } + default: { + LOG(FATAL) << "Unexpected element type got in iget instruction!"; + return; + } + } + + llvm::Value* instance_field_value; + + if (!is_fast_path) { + llvm::Constant* field_idx_value = irb_.getInt32(field_idx); + + llvm::Value* method_object_addr = EmitLoadMethodObjectAddr(); + + instance_field_value = EmitInvokeIntrinsic3(dex_pc, iget_intrinsic, + field_idx_value, + method_object_addr, + object_addr); + } else { + DCHECK_GE(field_offset, 0); + + instance_field_value = + EmitInvokeIntrinsic3NoThrow(iget_intrinsic, + irb_.getInt32(field_offset), + irb_.getInt1(is_volatile), + object_addr); + } + + EmitStoreDalvikReg(dec_insn.vA, field_jty, kField, instance_field_value); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + +void DexLang::EmitInsn_IPut(unsigned dex_pc, const Instruction* insn, + JType field_jty) { + DecodedInstruction dec_insn(insn); + + uint32_t reg_idx = dec_insn.vB; + uint32_t field_idx = dec_insn.vC; + + llvm::Value* object_addr = EmitLoadDalvikReg(reg_idx, kObject, kAccurate); + + EmitGuard_NullPointerException(dex_pc, object_addr); + + llvm::Value* new_value = EmitLoadDalvikReg(dec_insn.vA, field_jty, kField); + + int field_offset; + bool is_volatile; + bool is_fast_path = compiler_.ComputeInstanceFieldInfo(field_idx, &cunit_, + field_offset, + is_volatile, + /* is_iput */true); + + // Select corresponding intrinsic accroding to the field type and is_fast_path + IntrinsicHelper::IntrinsicId iput_intrinsic = IntrinsicHelper::UnknownId; + + switch (field_jty) { + case kInt: { + iput_intrinsic = + (is_fast_path) ? IntrinsicHelper::InstanceFieldPutFast : + IntrinsicHelper::InstanceFieldPut; + break; + } + case kLong: { + iput_intrinsic = + (is_fast_path) ? IntrinsicHelper::InstanceFieldPutWideFast : + IntrinsicHelper::InstanceFieldPutWide; + break; + } + case kObject: { + iput_intrinsic = + (is_fast_path) ? IntrinsicHelper::InstanceFieldPutObjectFast : + IntrinsicHelper::InstanceFieldPutObject; + break; + } + case kBoolean: { + iput_intrinsic = + (is_fast_path) ? IntrinsicHelper::InstanceFieldPutBooleanFast : + IntrinsicHelper::InstanceFieldPutBoolean; + break; + } + case kByte: { + iput_intrinsic = + (is_fast_path) ? IntrinsicHelper::InstanceFieldPutByteFast : + IntrinsicHelper::InstanceFieldPutByte; + break; + } + case kChar: { + iput_intrinsic = + (is_fast_path) ? IntrinsicHelper::InstanceFieldPutCharFast : + IntrinsicHelper::InstanceFieldPutChar; + break; + } + case kShort: { + iput_intrinsic = + (is_fast_path) ? IntrinsicHelper::InstanceFieldPutShortFast : + IntrinsicHelper::InstanceFieldPutShort; + break; + } + default: { + LOG(FATAL) << "Unexpected element type got in iput instruction!"; + return; + } + } + + if (!is_fast_path) { + llvm::Value* field_idx_value = irb_.getInt32(field_idx); + + llvm::Value* method_object_addr = EmitLoadMethodObjectAddr(); + + EmitInvokeIntrinsic4(dex_pc, iput_intrinsic, field_idx_value, + method_object_addr, object_addr, new_value); + + } else { + DCHECK_GE(field_offset, 0); + + EmitInvokeIntrinsic4NoThrow(iput_intrinsic, irb_.getInt32(field_offset), + irb_.getInt1(is_volatile), object_addr, + new_value); + + // If put an object, mark the GC card table + if (field_jty == kObject) { + EmitMarkGCCard(new_value, object_addr); + } + } + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); return; } @@ -1560,8 +2190,8 @@ void DexLang::EmitInsn_SGet(unsigned dex_pc, const Instruction* insn, llvm::Value* method_object_addr = EmitLoadMethodObjectAddr(); static_storage_addr = - EmitInvokeIntrinsic(dex_pc, IntrinsicHelper::LoadDeclaringClassSSB, - method_object_addr); + EmitInvokeIntrinsicNoThrow(IntrinsicHelper::LoadDeclaringClassSSB, + method_object_addr); } else { // Medium path, static storage base in a different class which // requires checks that the other class is initialized @@ -1570,9 +2200,10 @@ void DexLang::EmitInsn_SGet(unsigned dex_pc, const Instruction* insn, } static_field_value = - EmitInvokeIntrinsic3(dex_pc, sget_intrinsic, - static_storage_addr, irb_.getInt32(field_offset), - irb_.getInt1(is_volatile)); + EmitInvokeIntrinsic3NoThrow(sget_intrinsic, + static_storage_addr, + irb_.getInt32(field_offset), + irb_.getInt1(is_volatile)); } EmitStoreDalvikReg(dec_insn.vA, field_jty, kField, static_field_value); @@ -1668,8 +2299,8 @@ void DexLang::EmitInsn_SPut(unsigned dex_pc, const Instruction* insn, llvm::Value* method_object_addr = EmitLoadMethodObjectAddr(); static_storage_addr = - EmitInvokeIntrinsic(dex_pc, IntrinsicHelper::LoadDeclaringClassSSB, - method_object_addr); + EmitInvokeIntrinsicNoThrow(IntrinsicHelper::LoadDeclaringClassSSB, + method_object_addr); } else { // Medium path, static storage base in a different class which // requires checks that the other class is initialized @@ -1677,9 +2308,14 @@ void DexLang::EmitInsn_SPut(unsigned dex_pc, const Instruction* insn, static_storage_addr = EmitLoadStaticStorage(dex_pc, ssb_index); } - EmitInvokeIntrinsic4(dex_pc, sput_intrinsic, - static_storage_addr, irb_.getInt32(field_offset), - irb_.getInt1(is_volatile), new_value); + EmitInvokeIntrinsic4NoThrow(sput_intrinsic, static_storage_addr, + irb_.getInt32(field_offset), + irb_.getInt1(is_volatile), new_value); + + // If put an object, mark the GC card table + if (field_jty == kObject) { + EmitMarkGCCard(new_value, static_storage_addr); + } } irb_.CreateBr(GetNextBasicBlock(dex_pc)); @@ -1725,13 +2361,40 @@ void DexLang::EmitInsn_Invoke(unsigned dex_pc, const Instruction* insn, llvm::Value* thread_object_addr = EmitGetCurrentThread(); + // Select intrinsic according to the invoke_type + IntrinsicHelper::IntrinsicId invoke_intr = IntrinsicHelper::UnknownId; + switch (invoke_type) { + case kStatic: { + invoke_intr = IntrinsicHelper::FindStaticMethodWithAccessCheck; + break; + } + case kDirect: { + invoke_intr = IntrinsicHelper::FindDirectMethodWithAccessCheck; + break; + } + case kVirtual: { + invoke_intr = IntrinsicHelper::FindVirtualMethodWithAccessCheck; + break; + } + case kSuper: { + invoke_intr = IntrinsicHelper::FindSuperMethodWithAccessCheck; + break; + } + case kInterface: { + invoke_intr = IntrinsicHelper::FindInterfaceMethodWithAccessCheck; + break; + } + default: { + LOG(FATAL) << "Unknown type of invoke: " << invoke_type; + } + } + callee_method_object_addr = - EmitInvokeIntrinsic5(dex_pc, IntrinsicHelper::GetCalleeMethodObjAddr, - this_addr, + EmitInvokeIntrinsic4(dex_pc, invoke_intr, callee_method_idx_value, + this_addr, caller_method_object_addr, - thread_object_addr, - irb_.getInt32(static_cast<unsigned>(invoke_type))); + thread_object_addr); } else { switch (invoke_type) { case kStatic: @@ -1743,18 +2406,16 @@ void DexLang::EmitInsn_Invoke(unsigned dex_pc, const Instruction* insn, irb_.GetJMethodTy()); } else { callee_method_object_addr = - EmitInvokeIntrinsic(dex_pc, - IntrinsicHelper::GetSDCalleeMethodObjAddrFast, - callee_method_idx_value); + EmitInvokeIntrinsicNoThrow(IntrinsicHelper::GetSDCalleeMethodObjAddrFast, + callee_method_idx_value); } break; } case kVirtual: { DCHECK(vtable_idx != -1); callee_method_object_addr = - EmitInvokeIntrinsic2(dex_pc, - IntrinsicHelper::GetVirtualCalleeMethodObjAddrFast, - irb_.getInt32(vtable_idx), this_addr); + EmitInvokeIntrinsic2NoThrow(IntrinsicHelper::GetVirtualCalleeMethodObjAddrFast, + irb_.getInt32(vtable_idx), this_addr); break; } case kSuper: { @@ -1770,8 +2431,8 @@ void DexLang::EmitInsn_Invoke(unsigned dex_pc, const Instruction* insn, callee_method_object_addr = EmitInvokeIntrinsic4(dex_pc, IntrinsicHelper::GetInterfaceCalleeMethodObjAddrFast, - this_addr, callee_method_idx_value, + this_addr, caller_method_object_addr, thread_object_addr); break; @@ -1792,27 +2453,50 @@ void DexLang::EmitInsn_Invoke(unsigned dex_pc, const Instruction* insn, // Select the corresponding intrinsic according to the return type IntrinsicHelper::IntrinsicId invoke_intrinsic = IntrinsicHelper::UnknownId; - if (callee_ret_jty == kVoid) { - invoke_intrinsic = IntrinsicHelper::InvokeRetVoid; - } else { - switch (GetRegCategoryFromJType(callee_ret_jty)) { - case kRegCat1nr: { - invoke_intrinsic = IntrinsicHelper::InvokeRetCat1; - break; - } - case kRegCat2: { - invoke_intrinsic = IntrinsicHelper::InvokeRetCat2; - break; - } - case kRegObject: { - invoke_intrinsic = IntrinsicHelper::InvokeRetObject; - break; - } - default: { - LOG(FATAL) << "Unknown register category for type: " - << callee_ret_jty; - break; - } + switch (callee_ret_jty) { + case kVoid: { + invoke_intrinsic = IntrinsicHelper::InvokeRetVoid; + break; + } + case kBoolean: { + invoke_intrinsic = IntrinsicHelper::InvokeRetBoolean; + break; + } + case kByte: { + invoke_intrinsic = IntrinsicHelper::InvokeRetByte; + break; + } + case kChar: { + invoke_intrinsic = IntrinsicHelper::InvokeRetChar; + break; + } + case kShort: { + invoke_intrinsic = IntrinsicHelper::InvokeRetShort; + break; + } + case kInt: { + invoke_intrinsic = IntrinsicHelper::InvokeRetInt; + break; + } + case kLong: { + invoke_intrinsic = IntrinsicHelper::InvokeRetLong; + break; + } + case kFloat: { + invoke_intrinsic = IntrinsicHelper::InvokeRetFloat; + break; + } + case kDouble: { + invoke_intrinsic = IntrinsicHelper::InvokeRetDouble; + break; + } + case kObject: { + invoke_intrinsic = IntrinsicHelper::InvokeRetObject; + break; + } + default: { + LOG(FATAL) << "Unknown register category for type: " << callee_ret_jty; + break; } } @@ -1833,8 +2517,8 @@ void DexLang::EmitInsn_Invoke(unsigned dex_pc, const Instruction* insn, // Load argument values according to the shorty for (uint32_t i = 1; i < callee_shorty_size; i++) { - unsigned reg_idx = (arg_fmt == kArgReg) ? (dec_insn.vC + arg_idx) : - (dec_insn.arg[arg_idx]); + unsigned reg_idx = (arg_fmt == kArgRange) ? (dec_insn.vC + arg_idx) : + (dec_insn.arg[arg_idx]); JType jty = GetJTypeFromShorty(callee_shorty[i]); args.push_back(EmitLoadDalvikReg(reg_idx, jty, kAccurate)); arg_idx++; @@ -1853,16 +2537,166 @@ void DexLang::EmitInsn_Invoke(unsigned dex_pc, const Instruction* insn, // Store the return value for the subsequent move-result if (callee_shorty[0] != 'V') { - retval_ = retval; - retval_jty_ = GetJTypeFromShorty(callee_shorty[0]); - } else { - retval_ = NULL; + EmitStoreDalvikRetValReg(callee_ret_jty, kAccurate, retval); } irb_.CreateBr(GetNextBasicBlock(dex_pc)); return; } +void DexLang::EmitInsn_Neg(unsigned dex_pc, const Instruction* insn, + JType op_jty) { + DecodedInstruction dec_insn(insn); + + DCHECK(op_jty == kInt || op_jty == kLong) << op_jty; + + llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, op_jty, kAccurate); + llvm::Value* result_value = irb_.CreateNeg(src_value); + EmitStoreDalvikReg(dec_insn.vA, op_jty, kAccurate, result_value); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + +void DexLang::EmitInsn_Not(unsigned dex_pc, const Instruction* insn, + JType op_jty) { + DecodedInstruction dec_insn(insn); + + DCHECK(op_jty == kInt || op_jty == kLong) << op_jty; + + llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, op_jty, kAccurate); + llvm::Value* result_value = irb_.CreateXor(src_value, 0xFFFFFFFFFFFFFFFFLL); + + EmitStoreDalvikReg(dec_insn.vA, op_jty, kAccurate, result_value); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + +void DexLang::EmitInsn_SExt(unsigned dex_pc, const Instruction* insn) { + DecodedInstruction dec_insn(insn); + + llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, kInt, kAccurate); + llvm::Value* result_value = irb_.CreateSExt(src_value, irb_.GetJLongTy()); + EmitStoreDalvikReg(dec_insn.vA, kLong, kAccurate, result_value); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + +void DexLang::EmitInsn_Trunc(unsigned dex_pc, const Instruction* insn) { + DecodedInstruction dec_insn(insn); + + llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, kLong, kAccurate); + llvm::Value* result_value = irb_.CreateTrunc(src_value, irb_.GetJIntTy()); + EmitStoreDalvikReg(dec_insn.vA, kInt, kAccurate, result_value); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + +void DexLang::EmitInsn_TruncAndSExt(unsigned dex_pc, const Instruction* insn, + unsigned N) { + DecodedInstruction dec_insn(insn); + + llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, kInt, kAccurate); + + llvm::Value* trunc_value = + irb_.CreateTrunc(src_value, llvm::Type::getIntNTy(context_, N)); + + llvm::Value* result_value = irb_.CreateSExt(trunc_value, irb_.GetJIntTy()); + + EmitStoreDalvikReg(dec_insn.vA, kInt, kAccurate, result_value); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + +void DexLang::EmitInsn_TruncAndZExt(unsigned dex_pc, const Instruction* insn, + unsigned N) { + DecodedInstruction dec_insn(insn); + + llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, kInt, kAccurate); + + llvm::Value* trunc_value = + irb_.CreateTrunc(src_value, llvm::Type::getIntNTy(context_, N)); + + llvm::Value* result_value = irb_.CreateZExt(trunc_value, irb_.GetJIntTy()); + + EmitStoreDalvikReg(dec_insn.vA, kInt, kAccurate, result_value); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + +void DexLang::EmitInsn_FNeg(unsigned dex_pc, const Instruction* insn, + JType op_jty) { + DecodedInstruction dec_insn(insn); + + DCHECK(op_jty == kFloat || op_jty == kDouble) << op_jty; + + llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, op_jty, kAccurate); + llvm::Value* result_value = irb_.CreateFNeg(src_value); + EmitStoreDalvikReg(dec_insn.vA, op_jty, kAccurate, result_value); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + +void DexLang::EmitInsn_IntToFP(unsigned dex_pc, const Instruction* insn, + JType src_jty, JType dest_jty) { + DecodedInstruction dec_insn(insn); + + DCHECK(src_jty == kInt || src_jty == kLong) << src_jty; + DCHECK(dest_jty == kFloat || dest_jty == kDouble) << dest_jty; + + llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, src_jty, kAccurate); + llvm::Type* dest_type = irb_.GetJType(dest_jty, kAccurate); + llvm::Value* dest_value = irb_.CreateSIToFP(src_value, dest_type); + EmitStoreDalvikReg(dec_insn.vA, dest_jty, kAccurate, dest_value); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + +void DexLang::EmitInsn_FPToInt(unsigned dex_pc, const Instruction* insn, + JType src_jty, JType dest_jty, + IntrinsicHelper::IntrinsicId intr_id) { + DecodedInstruction dec_insn(insn); + + DCHECK(src_jty == kFloat || src_jty == kDouble) << src_jty; + DCHECK(dest_jty == kInt || dest_jty == kLong) << dest_jty; + + llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, src_jty, kAccurate); + llvm::Value* dest_value = EmitInvokeIntrinsicNoThrow(intr_id, src_value); + EmitStoreDalvikReg(dec_insn.vA, dest_jty, kAccurate, dest_value); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + +void DexLang::EmitInsn_FExt(unsigned dex_pc, const Instruction* insn) { + DecodedInstruction dec_insn(insn); + + llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, kFloat, kAccurate); + llvm::Value* result_value = irb_.CreateFPExt(src_value, irb_.GetJDoubleTy()); + EmitStoreDalvikReg(dec_insn.vA, kDouble, kAccurate, result_value); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + +void DexLang::EmitInsn_FTrunc(unsigned dex_pc, const Instruction* insn) { + DecodedInstruction dec_insn(insn); + + llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, kDouble, kAccurate); + llvm::Value* result_value = irb_.CreateFPTrunc(src_value, irb_.GetJFloatTy()); + EmitStoreDalvikReg(dec_insn.vA, kFloat, kAccurate, result_value); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + void DexLang::EmitInsn_IntArithm(unsigned dex_pc, const Instruction* insn, IntArithmKind arithm, JType op_jty, bool is_2addr) { @@ -1909,6 +2743,70 @@ void DexLang::EmitInsn_IntArithmImmediate(unsigned dex_pc, return; } +void DexLang::EmitInsn_IntShiftArithm(unsigned dex_pc, const Instruction* insn, + IntShiftArithmKind arithm, JType op_jty, + bool is_2addr) { + DecodedInstruction dec_insn(insn); + + DCHECK(op_jty == kInt || op_jty == kLong) << op_jty; + + llvm::Value* src1_value; + llvm::Value* src2_value; + + // NOTE: The 2nd operand of the shift arithmetic instruction is + // 32-bit integer regardless of the 1st operand. + if (is_2addr) { + src1_value = EmitLoadDalvikReg(dec_insn.vA, op_jty, kAccurate); + src2_value = EmitLoadDalvikReg(dec_insn.vB, kInt, kAccurate); + } else { + src1_value = EmitLoadDalvikReg(dec_insn.vB, op_jty, kAccurate); + src2_value = EmitLoadDalvikReg(dec_insn.vC, kInt, kAccurate); + } + + llvm::Value* result_value = EmitIntShiftArithmResultComputation(dex_pc, + src1_value, + src2_value, + arithm, + op_jty); + + EmitStoreDalvikReg(dec_insn.vA, op_jty, kAccurate, result_value); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + +void DexLang::EmitInsn_IntShiftArithmImmediate(unsigned dex_pc, + const Instruction* insn, + IntShiftArithmKind arithm) { + DecodedInstruction dec_insn(insn); + + llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, kInt, kAccurate); + + llvm::Value* imm_value = irb_.getInt32(dec_insn.vC); + + llvm::Value* result_value = EmitIntShiftArithmResultComputation(dex_pc, + src_value, + imm_value, + arithm, kInt); + + EmitStoreDalvikReg(dec_insn.vA, kInt, kAccurate, result_value); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + +void DexLang::EmitInsn_RSubImmediate(unsigned dex_pc, const Instruction* insn) { + DecodedInstruction dec_insn(insn); + + llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB, kInt, kAccurate); + llvm::Value* imm_value = irb_.getInt32(dec_insn.vC); + llvm::Value* result_value = irb_.CreateSub(imm_value, src_value); + EmitStoreDalvikReg(dec_insn.vA, kInt, kAccurate, result_value); + + irb_.CreateBr(GetNextBasicBlock(dex_pc)); + return; +} + void DexLang::EmitInsn_FPArithm(unsigned dex_pc, const Instruction* insn, FPArithmKind arithm, JType op_jty, bool is_2addr) { @@ -2048,32 +2946,32 @@ bool DexLang::EmitInstruction(unsigned dex_pc, const Instruction* insn) { EmitInsn_LoadConstantString(ARGS); break; } - case Instruction::CONST_CLASS: - //EmitInsn_LoadConstantClass(ARGS); + case Instruction::CONST_CLASS: { + EmitInsn_LoadConstantClass(ARGS); break; - - case Instruction::MONITOR_ENTER: - //EmitInsn_MonitorEnter(ARGS); + } + case Instruction::MONITOR_ENTER: { + EmitInsn_MonitorEnter(ARGS); break; - - case Instruction::MONITOR_EXIT: - //EmitInsn_MonitorExit(ARGS); + } + case Instruction::MONITOR_EXIT: { + EmitInsn_MonitorExit(ARGS); break; - - case Instruction::CHECK_CAST: - //EmitInsn_CheckCast(ARGS); + } + case Instruction::CHECK_CAST: { + EmitInsn_CheckCast(ARGS); break; - - case Instruction::INSTANCE_OF: - //EmitInsn_InstanceOf(ARGS); + } + case Instruction::INSTANCE_OF: { + EmitInsn_InstanceOf(ARGS); break; - + } case Instruction::ARRAY_LENGTH: { EmitInsn_ArrayLength(ARGS); break; } case Instruction::NEW_INSTANCE: - //EmitInsn_NewInstance(ARGS); + EmitInsn_NewInstance(ARGS); break; case Instruction::NEW_ARRAY: { @@ -2081,55 +2979,55 @@ bool DexLang::EmitInstruction(unsigned dex_pc, const Instruction* insn) { break; } case Instruction::FILLED_NEW_ARRAY: - //EmitInsn_FilledNewArray(ARGS, false); + EmitInsn_FilledNewArray(ARGS, /* is_range */false); break; case Instruction::FILLED_NEW_ARRAY_RANGE: - //EmitInsn_FilledNewArray(ARGS, true); + EmitInsn_FilledNewArray(ARGS, /* is_range */true); break; case Instruction::FILL_ARRAY_DATA: - //EmitInsn_FillArrayData(ARGS); + EmitInsn_FillArrayData(ARGS); break; - case Instruction::THROW: - //EmitInsn_ThrowException(ARGS); + case Instruction::THROW: { + EmitInsn_ThrowException(ARGS); break; - + } case Instruction::GOTO: case Instruction::GOTO_16: case Instruction::GOTO_32: { EmitInsn_UnconditionalBranch(ARGS); break; } - case Instruction::PACKED_SWITCH: - //EmitInsn_PackedSwitch(ARGS); + case Instruction::PACKED_SWITCH: { + EmitInsn_PackedSwitch(ARGS); break; - - case Instruction::SPARSE_SWITCH: - //EmitInsn_SparseSwitch(ARGS); + } + case Instruction::SPARSE_SWITCH: { + EmitInsn_SparseSwitch(ARGS); break; - - case Instruction::CMPL_FLOAT: - //EmitInsn_FPCompare(ARGS, kFloat, false); + } + case Instruction::CMPL_FLOAT: { + EmitInsn_FPCompare(ARGS, kFloat, false); break; - - case Instruction::CMPG_FLOAT: - //EmitInsn_FPCompare(ARGS, kFloat, true); + } + case Instruction::CMPG_FLOAT: { + EmitInsn_FPCompare(ARGS, kFloat, true); break; - - case Instruction::CMPL_DOUBLE: - //EmitInsn_FPCompare(ARGS, kDouble, false); + } + case Instruction::CMPL_DOUBLE: { + EmitInsn_FPCompare(ARGS, kDouble, false); break; - - case Instruction::CMPG_DOUBLE: - //EmitInsn_FPCompare(ARGS, kDouble, true); + } + case Instruction::CMPG_DOUBLE: { + EmitInsn_FPCompare(ARGS, kDouble, true); break; - - case Instruction::CMP_LONG: - //EmitInsn_LongCompare(ARGS); + } + case Instruction::CMP_LONG: { + EmitInsn_LongCompare(ARGS); break; - + } case Instruction::IF_EQ: { EmitInsn_BinaryConditionalBranch(ARGS, kCondBranch_EQ); break; @@ -2234,62 +3132,62 @@ bool DexLang::EmitInstruction(unsigned dex_pc, const Instruction* insn) { EmitInsn_APut(ARGS, kShort); break; } - case Instruction::IGET: - //EmitInsn_IGet(ARGS, kInt); + case Instruction::IGET: { + EmitInsn_IGet(ARGS, kInt); break; - - case Instruction::IGET_WIDE: - //EmitInsn_IGet(ARGS, kLong); + } + case Instruction::IGET_WIDE: { + EmitInsn_IGet(ARGS, kLong); break; - - case Instruction::IGET_OBJECT: - //EmitInsn_IGet(ARGS, kObject); + } + case Instruction::IGET_OBJECT: { + EmitInsn_IGet(ARGS, kObject); break; - - case Instruction::IGET_BOOLEAN: - //EmitInsn_IGet(ARGS, kBoolean); + } + case Instruction::IGET_BOOLEAN: { + EmitInsn_IGet(ARGS, kBoolean); break; - - case Instruction::IGET_BYTE: - //EmitInsn_IGet(ARGS, kByte); + } + case Instruction::IGET_BYTE: { + EmitInsn_IGet(ARGS, kByte); break; - - case Instruction::IGET_CHAR: - //EmitInsn_IGet(ARGS, kChar); + } + case Instruction::IGET_CHAR: { + EmitInsn_IGet(ARGS, kChar); break; - - case Instruction::IGET_SHORT: - //EmitInsn_IGet(ARGS, kShort); + } + case Instruction::IGET_SHORT: { + EmitInsn_IGet(ARGS, kShort); break; - - case Instruction::IPUT: - //EmitInsn_IPut(ARGS, kInt); + } + case Instruction::IPUT: { + EmitInsn_IPut(ARGS, kInt); break; - - case Instruction::IPUT_WIDE: - //EmitInsn_IPut(ARGS, kLong); + } + case Instruction::IPUT_WIDE: { + EmitInsn_IPut(ARGS, kLong); break; - - case Instruction::IPUT_OBJECT: - //EmitInsn_IPut(ARGS, kObject); + } + case Instruction::IPUT_OBJECT: { + EmitInsn_IPut(ARGS, kObject); break; - - case Instruction::IPUT_BOOLEAN: - //EmitInsn_IPut(ARGS, kBoolean); + } + case Instruction::IPUT_BOOLEAN: { + EmitInsn_IPut(ARGS, kBoolean); break; - - case Instruction::IPUT_BYTE: - //EmitInsn_IPut(ARGS, kByte); + } + case Instruction::IPUT_BYTE: { + EmitInsn_IPut(ARGS, kByte); break; - - case Instruction::IPUT_CHAR: - //EmitInsn_IPut(ARGS, kChar); + } + case Instruction::IPUT_CHAR: { + EmitInsn_IPut(ARGS, kChar); break; - - case Instruction::IPUT_SHORT: - //EmitInsn_IPut(ARGS, kShort); + } + case Instruction::IPUT_SHORT: { + EmitInsn_IPut(ARGS, kShort); break; - + } case Instruction::SGET: { EmitInsn_SGet(ARGS, kInt); break; @@ -2386,90 +3284,90 @@ bool DexLang::EmitInstruction(unsigned dex_pc, const Instruction* insn) { EmitInsn_Invoke(ARGS, kInterface, kArgRange); break; } - case Instruction::NEG_INT: - //EmitInsn_Neg(ARGS, kInt); + case Instruction::NEG_INT: { + EmitInsn_Neg(ARGS, kInt); break; - - case Instruction::NOT_INT: - //EmitInsn_Not(ARGS, kInt); + } + case Instruction::NOT_INT: { + EmitInsn_Not(ARGS, kInt); break; - - case Instruction::NEG_LONG: - //EmitInsn_Neg(ARGS, kLong); + } + case Instruction::NEG_LONG: { + EmitInsn_Neg(ARGS, kLong); break; - - case Instruction::NOT_LONG: - //EmitInsn_Not(ARGS, kLong); + } + case Instruction::NOT_LONG: { + EmitInsn_Not(ARGS, kLong); break; - - case Instruction::NEG_FLOAT: - //EmitInsn_FNeg(ARGS, kFloat); + } + case Instruction::NEG_FLOAT: { + EmitInsn_FNeg(ARGS, kFloat); break; - - case Instruction::NEG_DOUBLE: - //EmitInsn_FNeg(ARGS, kDouble); + } + case Instruction::NEG_DOUBLE: { + EmitInsn_FNeg(ARGS, kDouble); break; - - case Instruction::INT_TO_LONG: - //EmitInsn_SExt(ARGS); + } + case Instruction::INT_TO_LONG: { + EmitInsn_SExt(ARGS); break; - - case Instruction::INT_TO_FLOAT: - //EmitInsn_IntToFP(ARGS, kInt, kFloat); + } + case Instruction::INT_TO_FLOAT: { + EmitInsn_IntToFP(ARGS, kInt, kFloat); break; - - case Instruction::INT_TO_DOUBLE: - //EmitInsn_IntToFP(ARGS, kInt, kDouble); + } + case Instruction::INT_TO_DOUBLE: { + EmitInsn_IntToFP(ARGS, kInt, kDouble); break; - - case Instruction::LONG_TO_INT: - //EmitInsn_Trunc(ARGS); + } + case Instruction::LONG_TO_INT: { + EmitInsn_Trunc(ARGS); break; - - case Instruction::LONG_TO_FLOAT: - //EmitInsn_IntToFP(ARGS, kLong, kFloat); + } + case Instruction::LONG_TO_FLOAT: { + EmitInsn_IntToFP(ARGS, kLong, kFloat); break; - - case Instruction::LONG_TO_DOUBLE: - //EmitInsn_IntToFP(ARGS, kLong, kDouble); + } + case Instruction::LONG_TO_DOUBLE: { + EmitInsn_IntToFP(ARGS, kLong, kDouble); break; - - case Instruction::FLOAT_TO_INT: - //EmitInsn_FPToInt(ARGS, kFloat, kInt, F2I); + } + case Instruction::FLOAT_TO_INT: { + EmitInsn_FPToInt(ARGS, kFloat, kInt, IntrinsicHelper::F2I); break; - - case Instruction::FLOAT_TO_LONG: - //EmitInsn_FPToInt(ARGS, kFloat, kLong, F2L); + } + case Instruction::FLOAT_TO_LONG: { + EmitInsn_FPToInt(ARGS, kFloat, kLong, IntrinsicHelper::F2L); break; - - case Instruction::FLOAT_TO_DOUBLE: - //EmitInsn_FExt(ARGS); + } + case Instruction::FLOAT_TO_DOUBLE: { + EmitInsn_FExt(ARGS); break; - - case Instruction::DOUBLE_TO_INT: - //EmitInsn_FPToInt(ARGS, kDouble, kInt, D2I); + } + case Instruction::DOUBLE_TO_INT: { + EmitInsn_FPToInt(ARGS, kDouble, kInt, IntrinsicHelper::D2I); break; - - case Instruction::DOUBLE_TO_LONG: - //EmitInsn_FPToInt(ARGS, kDouble, kLong, D2L); + } + case Instruction::DOUBLE_TO_LONG: { + EmitInsn_FPToInt(ARGS, kDouble, kLong, IntrinsicHelper::D2L); break; - - case Instruction::DOUBLE_TO_FLOAT: - //EmitInsn_FTrunc(ARGS); + } + case Instruction::DOUBLE_TO_FLOAT: { + EmitInsn_FTrunc(ARGS); break; - - case Instruction::INT_TO_BYTE: - //EmitInsn_TruncAndSExt(ARGS, 8); + } + case Instruction::INT_TO_BYTE: { + EmitInsn_TruncAndSExt(ARGS, 8); break; - - case Instruction::INT_TO_CHAR: - //EmitInsn_TruncAndZExt(ARGS, 16); + } + case Instruction::INT_TO_CHAR: { + EmitInsn_TruncAndZExt(ARGS, 16); break; - - case Instruction::INT_TO_SHORT: - //EmitInsn_TruncAndSExt(ARGS, 16); + } + case Instruction::INT_TO_SHORT: { + EmitInsn_TruncAndSExt(ARGS, 16); break; - + } case Instruction::ADD_INT: { EmitInsn_IntArithm(ARGS, kIntArithm_Add, kInt, false); break; @@ -2502,18 +3400,18 @@ bool DexLang::EmitInstruction(unsigned dex_pc, const Instruction* insn) { EmitInsn_IntArithm(ARGS, kIntArithm_Xor, kInt, false); break; } - case Instruction::SHL_INT: - //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kInt, false); + case Instruction::SHL_INT: { + EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kInt, false); break; - - case Instruction::SHR_INT: - //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kInt, false); + } + case Instruction::SHR_INT: { + EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kInt, false); break; - - case Instruction::USHR_INT: - //EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kInt, false); + } + case Instruction::USHR_INT: { + EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kInt, false); break; - + } case Instruction::ADD_LONG: { EmitInsn_IntArithm(ARGS, kIntArithm_Add, kLong, false); break; @@ -2546,18 +3444,18 @@ bool DexLang::EmitInstruction(unsigned dex_pc, const Instruction* insn) { EmitInsn_IntArithm(ARGS, kIntArithm_Xor, kLong, false); break; } - case Instruction::SHL_LONG: - //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kLong, false); + case Instruction::SHL_LONG: { + EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kLong, false); break; - - case Instruction::SHR_LONG: - //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kLong, false); + } + case Instruction::SHR_LONG: { + EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kLong, false); break; - - case Instruction::USHR_LONG: - //EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kLong, false); + } + case Instruction::USHR_LONG: { + EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kLong, false); break; - + } case Instruction::ADD_FLOAT: { EmitInsn_FPArithm(ARGS, kFPArithm_Add, kFloat, false); break; @@ -2630,18 +3528,18 @@ bool DexLang::EmitInstruction(unsigned dex_pc, const Instruction* insn) { EmitInsn_IntArithm(ARGS, kIntArithm_Xor, kInt, true); break; } - case Instruction::SHL_INT_2ADDR: - //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kInt, true); + case Instruction::SHL_INT_2ADDR: { + EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kInt, true); break; - - case Instruction::SHR_INT_2ADDR: - //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kInt, true); + } + case Instruction::SHR_INT_2ADDR: { + EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kInt, true); break; - - case Instruction::USHR_INT_2ADDR: - //EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kInt, true); + } + case Instruction::USHR_INT_2ADDR: { + EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kInt, true); break; - + } case Instruction::ADD_LONG_2ADDR: { EmitInsn_IntArithm(ARGS, kIntArithm_Add, kLong, true); break; @@ -2674,18 +3572,18 @@ bool DexLang::EmitInstruction(unsigned dex_pc, const Instruction* insn) { EmitInsn_IntArithm(ARGS, kIntArithm_Xor, kLong, true); break; } - case Instruction::SHL_LONG_2ADDR: - //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kLong, true); + case Instruction::SHL_LONG_2ADDR: { + EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kLong, true); break; - - case Instruction::SHR_LONG_2ADDR: - //EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kLong, true); + } + case Instruction::SHR_LONG_2ADDR: { + EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kLong, true); break; - - case Instruction::USHR_LONG_2ADDR: - //EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kLong, true); + } + case Instruction::USHR_LONG_2ADDR: { + EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kLong, true); break; - + } case Instruction::ADD_FLOAT_2ADDR: { EmitInsn_FPArithm(ARGS, kFPArithm_Add, kFloat, true); break; @@ -2732,10 +3630,10 @@ bool DexLang::EmitInstruction(unsigned dex_pc, const Instruction* insn) { break; } case Instruction::RSUB_INT: - case Instruction::RSUB_INT_LIT8: - //EmitInsn_RSubImmediate(ARGS); + case Instruction::RSUB_INT_LIT8: { + EmitInsn_RSubImmediate(ARGS); break; - + } case Instruction::MUL_INT_LIT16: case Instruction::MUL_INT_LIT8: { EmitInsn_IntArithmImmediate(ARGS, kIntArithm_Mul); @@ -2766,17 +3664,18 @@ bool DexLang::EmitInstruction(unsigned dex_pc, const Instruction* insn) { EmitInsn_IntArithmImmediate(ARGS, kIntArithm_Xor); break; } - case Instruction::SHL_INT_LIT8: - //EmitInsn_IntShiftArithmImmediate(ARGS, kIntArithm_Shl); + case Instruction::SHL_INT_LIT8: { + EmitInsn_IntShiftArithmImmediate(ARGS, kIntArithm_Shl); break; - - case Instruction::SHR_INT_LIT8: - //EmitInsn_IntShiftArithmImmediate(ARGS, kIntArithm_Shr); + } + case Instruction::SHR_INT_LIT8: { + EmitInsn_IntShiftArithmImmediate(ARGS, kIntArithm_Shr); break; - - case Instruction::USHR_INT_LIT8: - //EmitInsn_IntShiftArithmImmediate(ARGS, kIntArithm_UShr); + } + case Instruction::USHR_INT_LIT8: { + EmitInsn_IntShiftArithmImmediate(ARGS, kIntArithm_UShr); break; + } case Instruction::UNUSED_3E: case Instruction::UNUSED_3F: diff --git a/src/greenland/dex_lang.h b/src/greenland/dex_lang.h index ce4b462..6b212d0 100644 --- a/src/greenland/dex_lang.h +++ b/src/greenland/dex_lang.h @@ -18,6 +18,7 @@ #define ART_SRC_GREENLAND_DEX_LANG_H_ #include "backend_types.h" +#include "compiler_llvm/backend_types.h" #include "dalvik_reg.h" #include "ir_builder.h" @@ -28,14 +29,13 @@ #include <vector> -#include <llvm/LLVMContext.h> +#include <llvm/Module.h> #include <llvm/ADT/ArrayRef.h> namespace llvm { class BasicBlock; class Function; class LLVMContext; - class Module; class Type; } @@ -54,34 +54,26 @@ class DexLang { public: class Context { private: - llvm::LLVMContext context_; - llvm::Module* module_; + llvm::Module& module_; IntrinsicHelper* intrinsic_helper_; - volatile int32_t ref_count_; - volatile int32_t mem_usage_; - - ~Context(); - - DISALLOW_COPY_AND_ASSIGN(Context); - public: - Context(); + Context(llvm::Module& module); + ~Context(); inline llvm::LLVMContext& GetLLVMContext() - { return context_; } + { return module_.getContext(); } + inline llvm::Module& GetOutputModule() - { return *module_; } + { return module_; } + inline IntrinsicHelper& GetIntrinsicHelper() { return *intrinsic_helper_; } + inline const IntrinsicHelper& GetIntrinsicHelper() const + { return *intrinsic_helper_; } - Context& IncRef(); - void DecRef(); - - void AddMemUsageApproximation(size_t usage); - inline bool IsMemUsageThresholdReached() const { - return (mem_usage_ > (30 << 20)); // (threshold: 30MiB) - } + private: + DISALLOW_COPY_AND_ASSIGN(Context); }; public: @@ -94,7 +86,7 @@ class DexLang { inline IRBuilder& GetIRBuilder() { return irb_; } - llvm::Value* AllocateDalvikReg(JType jty, unsigned reg_idx); + llvm::Value* AllocateDalvikReg(RegCategory cat, unsigned reg_idx); private: Context& dex_lang_ctx_; @@ -104,6 +96,7 @@ class DexLang { const DexFile* dex_file_; const DexFile::CodeItem* code_item_; DexCache* dex_cache_; + uint32_t method_idx_; llvm::LLVMContext& context_; llvm::Module& module_; @@ -161,9 +154,27 @@ class DexLang { // Return Value Related //---------------------------------------------------------------------------- // Hold the return value returned from the lastest invoke-* instruction - llvm::Value* retval_; - // The type of ret_val_ - JType retval_jty_; + DalvikReg* retval_reg_; + + llvm::Value* EmitLoadDalvikRetValReg(JType jty, JTypeSpace space) { + return retval_reg_->GetValue(jty, space); + } + + llvm::Value* EmitLoadDalvikRetValReg(char shorty, JTypeSpace space) { + return EmitLoadDalvikRetValReg(GetJTypeFromShorty(shorty), space); + } + + void EmitStoreDalvikRetValReg(JType jty, JTypeSpace space, + llvm::Value* new_value) { + retval_reg_->SetValue(jty, space, new_value); + return; + } + + void EmitStoreDalvikRetValReg(char shorty, JTypeSpace space, + llvm::Value* new_value) { + EmitStoreDalvikRetValReg(GetJTypeFromShorty(shorty), space, new_value); + return; + } private: //---------------------------------------------------------------------------- @@ -211,7 +222,6 @@ class DexLang { //---------------------------------------------------------------------------- // Shadow Frame //---------------------------------------------------------------------------- - bool require_shadow_frame; unsigned num_shadow_frame_entries_; void EmitUpdateDexPC(unsigned dex_pc); @@ -228,8 +238,6 @@ class DexLang { bool CreateFunction(); llvm::FunctionType* GetFunctionType(); - bool PrepareDalvikRegs(); - bool EmitPrologue(); bool EmitPrologueAssignArgRegister(); bool EmitPrologueAllcaShadowFrame(); @@ -263,6 +271,12 @@ class DexLang { kIntArithm_Xor, }; + enum IntShiftArithmKind { + kIntArithm_Shl, + kIntArithm_Shr, + kIntArithm_UShr, + }; + enum FPArithmKind { kFPArithm_Add, kFPArithm_Sub, @@ -280,14 +294,37 @@ class DexLang { llvm::Value* EmitGetCurrentThread(); - llvm::Value* EmitInvokeIntrinsicNoThrow(IntrinsicHelper::IntrinsicId intr_id); + void EmitMarkGCCard(llvm::Value* value, llvm::Value* target_addr); + llvm::Value* EmitInvokeIntrinsicNoThrow(IntrinsicHelper::IntrinsicId intr_id, - llvm::ArrayRef<llvm::Value*> args); - llvm::Value* EmitInvokeIntrinsic(unsigned dex_pc, - IntrinsicHelper::IntrinsicId intr_id); + llvm::ArrayRef<llvm::Value*> args + = llvm::ArrayRef<llvm::Value*>()); + llvm::Value* EmitInvokeIntrinsic2NoThrow(IntrinsicHelper::IntrinsicId intr_id, + llvm::Value* arg1, + llvm::Value* arg2) { + llvm::Value* args[] = { arg1, arg2 }; + return EmitInvokeIntrinsicNoThrow(intr_id, args); + } + llvm::Value* EmitInvokeIntrinsic3NoThrow(IntrinsicHelper::IntrinsicId intr_id, + llvm::Value* arg1, + llvm::Value* arg2, + llvm::Value* arg3) { + llvm::Value* args[] = { arg1, arg2, arg3 }; + return EmitInvokeIntrinsicNoThrow(intr_id, args); + } + llvm::Value* EmitInvokeIntrinsic4NoThrow(IntrinsicHelper::IntrinsicId intr_id, + llvm::Value* arg1, + llvm::Value* arg2, + llvm::Value* arg3, + llvm::Value* arg4) { + llvm::Value* args[] = { arg1, arg2, arg3, arg4 }; + return EmitInvokeIntrinsicNoThrow(intr_id, args); + } + llvm::Value* EmitInvokeIntrinsic(unsigned dex_pc, IntrinsicHelper::IntrinsicId intr_id, - llvm::ArrayRef<llvm::Value*> args); + llvm::ArrayRef<llvm::Value*> args + = llvm::ArrayRef<llvm::Value*>()); llvm::Value* EmitInvokeIntrinsic2(unsigned dex_pc, IntrinsicHelper::IntrinsicId intr_id, llvm::Value* arg1, @@ -323,10 +360,19 @@ class DexLang { return EmitInvokeIntrinsic(dex_pc, intr_id, args); } - RegCategory GetInferredRegCategory(unsigned dex_pc, unsigned reg_idx); + 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); + llvm::Value* EmitAllocNewArray(unsigned dex_pc, int32_t length, + uint32_t type_idx, bool is_filled_new_array); + + llvm::Value* EmitCompareResultSelection(llvm::Value* cmp_eq, + llvm::Value* cmp_lt); + llvm::Value* EmitLoadStaticStorage(unsigned dex_pc, unsigned type_idx); llvm::Value* EmitConditionResult(llvm::Value* lhs, llvm::Value* rhs, @@ -338,6 +384,12 @@ class DexLang { IntArithmKind arithm, JType op_jty); + llvm::Value* EmitIntShiftArithmResultComputation(uint32_t dex_pc, + llvm::Value* lhs, + llvm::Value* rhs, + IntShiftArithmKind arithm, + JType op_jty); + llvm::Value* EmitIntDivRemResultComputation(unsigned dex_pc, llvm::Value* dividend, llvm::Value* divisor, @@ -354,18 +406,15 @@ class DexLang { // MOVE_EXCEPTION, THROW instructions void EmitInsn_MoveException(GEN_INSN_ARGS); -#if 0 void EmitInsn_ThrowException(GEN_INSN_ARGS); // RETURN instructions -#endif void EmitInsn_ReturnVoid(GEN_INSN_ARGS); void EmitInsn_Return(GEN_INSN_ARGS); // CONST, CONST_CLASS, CONST_STRING instructions void EmitInsn_LoadConstant(GEN_INSN_ARGS, JType imm_jty); void EmitInsn_LoadConstantString(GEN_INSN_ARGS); -#if 0 void EmitInsn_LoadConstantClass(GEN_INSN_ARGS); // MONITOR_ENTER, MONITOR_EXIT instructions @@ -378,22 +427,18 @@ class DexLang { // NEW_INSTANCE instructions void EmitInsn_NewInstance(GEN_INSN_ARGS); -#endif // ARRAY_LEN, NEW_ARRAY, FILLED_NEW_ARRAY, FILL_ARRAY_DATA instructions void EmitInsn_ArrayLength(GEN_INSN_ARGS); void EmitInsn_NewArray(GEN_INSN_ARGS); -#if 0 void EmitInsn_FilledNewArray(GEN_INSN_ARGS, bool is_range); void EmitInsn_FillArrayData(GEN_INSN_ARGS); -#endif // GOTO, IF_TEST, IF_TESTZ instructions void EmitInsn_UnconditionalBranch(GEN_INSN_ARGS); - void EmitInsn_BinaryConditionalBranch(GEN_INSN_ARGS, CondBranchKind cond); void EmitInsn_UnaryConditionalBranch(GEN_INSN_ARGS, CondBranchKind cond); + void EmitInsn_BinaryConditionalBranch(GEN_INSN_ARGS, CondBranchKind cond); -#if 0 // PACKED_SWITCH, SPARSE_SWITCH instrutions void EmitInsn_PackedSwitch(GEN_INSN_ARGS); void EmitInsn_SparseSwitch(GEN_INSN_ARGS); @@ -402,48 +447,22 @@ class DexLang { void EmitInsn_FPCompare(GEN_INSN_ARGS, JType fp_jty, bool gt_bias); void EmitInsn_LongCompare(GEN_INSN_ARGS); -#endif // AGET, APUT instrutions void EmitInsn_AGet(GEN_INSN_ARGS, JType elem_jty); void EmitInsn_APut(GEN_INSN_ARGS, JType elem_jty); -#if 0 // IGET, IPUT instructions void EmitInsn_IGet(GEN_INSN_ARGS, JType field_jty); void EmitInsn_IPut(GEN_INSN_ARGS, JType field_jty); -#endif // SGET, SPUT instructions void EmitInsn_SGet(GEN_INSN_ARGS, JType field_jty); void EmitInsn_SPut(GEN_INSN_ARGS, JType field_jty); -#if 0 - // INVOKE instructions - llvm::Value* EmitFixStub(llvm::Value* callee_method_object_addr, - uint32_t method_idx, - bool is_static); - llvm::Value* EmitEnsureResolved(llvm::Value* callee, - llvm::Value* caller, - uint32_t dex_method_idx, - bool is_virtual); -#endif - void EmitInsn_Invoke(GEN_INSN_ARGS, InvokeType invoke_type, InvokeArgFmt arg_fmt); -#if 0 - llvm::Value* EmitLoadSDCalleeMethodObjectAddr(uint32_t callee_method_idx); - - llvm::Value* EmitLoadVirtualCalleeMethodObjectAddr(int vtable_idx, - llvm::Value* this_addr); - - llvm::Value* EmitCallRuntimeForCalleeMethodObjectAddr(uint32_t callee_method_idx, - InvokeType invoke_type, - llvm::Value* this_addr, - unsigned dex_pc, - bool is_fast_path); - // Unary instructions void EmitInsn_Neg(GEN_INSN_ARGS, JType op_jty); void EmitInsn_Not(GEN_INSN_ARGS, JType op_jty); @@ -455,18 +474,16 @@ class DexLang { void EmitInsn_FNeg(GEN_INSN_ARGS, JType op_jty); void EmitInsn_IntToFP(GEN_INSN_ARGS, JType src_jty, JType dest_jty); void EmitInsn_FPToInt(GEN_INSN_ARGS, JType src_jty, JType dest_jty, - runtime_support::RuntimeId runtime_func_id); + IntrinsicHelper::IntrinsicId intr_id); void EmitInsn_FExt(GEN_INSN_ARGS); void EmitInsn_FTrunc(GEN_INSN_ARGS); -#endif // Integer binary arithmetic instructions void EmitInsn_IntArithm(GEN_INSN_ARGS, IntArithmKind arithm, JType op_jty, bool is_2addr); void EmitInsn_IntArithmImmediate(GEN_INSN_ARGS, IntArithmKind arithm); -#if 0 void EmitInsn_IntShiftArithm(GEN_INSN_ARGS, IntShiftArithmKind arithm, JType op_jty, bool is_2addr); @@ -475,7 +492,6 @@ class DexLang { void EmitInsn_RSubImmediate(GEN_INSN_ARGS); -#endif // Floating-point binary arithmetic instructions void EmitInsn_FPArithm(GEN_INSN_ARGS, FPArithmKind arithm, JType op_jty, bool is_2addr); diff --git a/src/greenland/gbc_context.cc b/src/greenland/gbc_context.cc new file mode 100644 index 0000000..ec86bfb --- /dev/null +++ b/src/greenland/gbc_context.cc @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "gbc_context.h" + +#include "atomic.h" + +namespace art { +namespace greenland { + +GBCContext::GBCContext() + : context_(), module_(NULL), ref_count_(1), mem_usage_(0) { + module_ = new llvm::Module("art", context_); + + // Initialize the contents of an empty module + // Type of "JavaObject" + llvm::StructType::create(context_, "JavaObject"); + // Type of "Method" + llvm::StructType::create(context_, "Method"); + // Type of "Thread" + llvm::StructType::create(context_, "Thread"); + + dex_lang_ctx_ = new DexLang::Context(*module_); + return; +} + +GBCContext::~GBCContext() { + delete dex_lang_ctx_; + return; +} + +GBCContext& GBCContext::IncRef() { + android_atomic_inc(&ref_count_); + return *this; +} + +const GBCContext& GBCContext::IncRef() const { + android_atomic_inc(&ref_count_); + return *this; +} + +void GBCContext::DecRef() const { + int32_t old_ref_count = android_atomic_dec(&ref_count_); + if (old_ref_count <= 1) { + delete this; + } + return; +} + +void GBCContext::AddMemUsageApproximation(size_t usage) { + android_atomic_add(static_cast<int32_t>(usage), &mem_usage_); + return; +} + +} // namespace greenland +} // namespace art diff --git a/src/greenland/gbc_context.h b/src/greenland/gbc_context.h new file mode 100644 index 0000000..7c31816 --- /dev/null +++ b/src/greenland/gbc_context.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_SRC_GREENLAND_GBC_CONTEXT_H_ +#define ART_SRC_GREENLAND_GBC_CONTEXT_H_ + +#include "dex_lang.h" + +#include "macros.h" + +#include <llvm/LLVMContext.h> + +namespace llvm { + class Module; +} // namespace llvm + +namespace art { +namespace greenland { + +class IntrinsicHelper; + +class GBCContext { + private: + llvm::LLVMContext context_; + llvm::Module* module_; + DexLang::Context* dex_lang_ctx_; + + mutable volatile int32_t ref_count_; + volatile int32_t mem_usage_; + + ~GBCContext(); + + public: + GBCContext(); + + inline llvm::LLVMContext& GetLLVMContext() + { return context_; } + inline llvm::Module& GetOutputModule() + { return *module_; } + + inline IntrinsicHelper& GetIntrinsicHelper() + { return dex_lang_ctx_->GetIntrinsicHelper(); } + inline const IntrinsicHelper& GetIntrinsicHelper() const + { return dex_lang_ctx_->GetIntrinsicHelper(); } + + inline DexLang::Context& GetDexLangContext() + { return *dex_lang_ctx_; } + inline const DexLang::Context& GetDexLangContext() const + { return *dex_lang_ctx_; } + + GBCContext& IncRef(); + const GBCContext& IncRef() const; + void DecRef() const; + + void AddMemUsageApproximation(size_t usage); + inline bool IsMemUsageThresholdReached() const { + return (mem_usage_ > (30 << 20)); // (threshold: 30MiB) + } + + private: + DISALLOW_COPY_AND_ASSIGN(GBCContext); +}; + +} // namespace greenland +} // namespace art + +#endif // ART_SRC_GREENLAND_GBC_CONTEXT_H_ diff --git a/src/greenland/gbc_function.h b/src/greenland/gbc_function.h new file mode 100644 index 0000000..b7cbea6 --- /dev/null +++ b/src/greenland/gbc_function.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_SRC_GREENLAND_GBC_FUNCTION_H_ +#define ART_SRC_GREENLAND_GBC_FUNCTION_H_ + +#include "gbc_context.h" + +namespace llvm { + class Function; +} // namespace llvm + +namespace art { + class OatCompilationUnit; +} // namespace art + +namespace art { +namespace greenland { + +class GBCContext; + +class GBCFunction { + private: + // The GBCContext associated with this GBCFunction + GBCContext& context_; + + // The LLVM Function in Greenland bitcode + llvm::Function& func_; + + // The associated OatCompilationUnit + const OatCompilationUnit& cunit_; + + public: + GBCFunction(GBCContext& context, llvm::Function& func, + const OatCompilationUnit& cunit) + : context_(context.IncRef()), func_(func), cunit_(cunit) { } + + ~GBCFunction() { + context_.DecRef(); + return; + } + + IntrinsicHelper& GetIntrinsicHelper() { + return context_.GetIntrinsicHelper(); + } + const IntrinsicHelper& GetIntrinsicHelper() const { + return context_.GetIntrinsicHelper(); + } + + llvm::Function& GetBitcode() { + return func_; + } + const llvm::Function& GetBitcode() const { + return func_; + } + + const OatCompilationUnit& GetOatCompilationUnit() const { + return cunit_; + } +}; + +} // namespace greenland +} // namespace art + +#endif // ART_SRC_GREENLAND_GBC_FUNCTION_H_ diff --git a/src/greenland/greenland.cc b/src/greenland/greenland.cc index bbf990d..469f7d5 100644 --- a/src/greenland/greenland.cc +++ b/src/greenland/greenland.cc @@ -16,6 +16,8 @@ #include "greenland.h" +#include "gbc_context.h" +#include "gbc_function.h" #include "target_codegen_machine.h" #include "target_registry.h" @@ -63,6 +65,9 @@ void InitializeAllInvokeStubCompilers() { } void InitializeGreenland() { + // Initialize LLVM internal data structure for multithreading + llvm::llvm_start_multithreaded(); + // Initialize passes llvm::PassRegistry ®istry = *llvm::PassRegistry::getPassRegistry(); @@ -83,9 +88,6 @@ void InitializeGreenland() { InitializeAllCodeGenMachines(); InitializeAllInvokeStubCompilers(); - // Initialize LLVM internal data structure for multithreading - llvm::llvm_start_multithreaded(); - return; } @@ -96,7 +98,7 @@ namespace greenland { Greenland::Greenland(art::Compiler& compiler) : compiler_(compiler), codegen_machine_(NULL), - lock_("greenland_compiler_lock"), cur_dex_lang_ctx_(NULL) { + lock_("greenland_compiler_lock"), cur_gbc_ctx_(NULL) { // Initialize Greenland pthread_once(&greenland_initialized, InitializeGreenland); @@ -107,7 +109,7 @@ Greenland::Greenland(art::Compiler& compiler) } Greenland::~Greenland() { - cur_dex_lang_ctx_->DecRef(); + cur_gbc_ctx_->DecRef(); delete codegen_machine_; } @@ -115,9 +117,10 @@ CompiledMethod* Greenland::Compile(OatCompilationUnit& cunit) { MutexLock GUARD(lock_); // Dex to LLVM IR - DexLang::Context& dex_lang_ctx = GetDexLangContext(); + GBCContext& gbc_ctx = GetGBCContext(); - UniquePtr<DexLang> dex_lang(new DexLang(dex_lang_ctx, compiler_, cunit)); + UniquePtr<DexLang> dex_lang(new DexLang(gbc_ctx.GetDexLangContext(), + compiler_, cunit)); llvm::Function* func = dex_lang->Build(); @@ -127,40 +130,47 @@ CompiledMethod* Greenland::Compile(OatCompilationUnit& cunit) { return NULL; } - dex_lang_ctx.GetOutputModule().dump(); + func->dump(); + + // NOTE: From statistic, the bitcode size is 4.5 times bigger than the + // Dex file. Besides, we have to convert the code unit into bytes. + // Thus, we got our magic number 9. + gbc_ctx.AddMemUsageApproximation( + cunit.GetCodeItem()->insns_size_in_code_units_ * 900); + + GBCFunction gbc_func(gbc_ctx, *func, cunit); - UniquePtr<CompiledMethod> result(codegen_machine_->Run(*this, *func, cunit, - dex_lang_ctx)); + UniquePtr<CompiledMethod> result(codegen_machine_->Run(compiler_, gbc_func)); - // dex_lang_ctx was no longer needed - dex_lang_ctx.DecRef(); + // gbc_ctx was no longer needed + gbc_ctx.DecRef(); return result.release(); } -DexLang::Context& Greenland::GetDexLangContext() { +GBCContext& Greenland::GetGBCContext() { //MutexLock GUARD(lock_); - ResetDexLangContextIfThresholdReached(); + ResetGBCContextIfThresholdReached(); - if (cur_dex_lang_ctx_ == NULL) { - cur_dex_lang_ctx_ = new DexLang::Context(); + if (cur_gbc_ctx_ == NULL) { + cur_gbc_ctx_ = new GBCContext(); } - CHECK(cur_dex_lang_ctx_ != NULL); + CHECK(cur_gbc_ctx_ != NULL); - return cur_dex_lang_ctx_->IncRef(); + return cur_gbc_ctx_->IncRef(); } -void Greenland::ResetDexLangContextIfThresholdReached() { +void Greenland::ResetGBCContextIfThresholdReached() { lock_.AssertHeld(); - if (cur_dex_lang_ctx_ == NULL) { + if (cur_gbc_ctx_ == NULL) { return; } - if (cur_dex_lang_ctx_->IsMemUsageThresholdReached()) { - cur_dex_lang_ctx_->DecRef(); - cur_dex_lang_ctx_ = NULL; + if (cur_gbc_ctx_->IsMemUsageThresholdReached()) { + cur_gbc_ctx_->DecRef(); + cur_gbc_ctx_ = NULL; } return; } diff --git a/src/greenland/greenland.h b/src/greenland/greenland.h index 4407c92..1d6f8e5 100644 --- a/src/greenland/greenland.h +++ b/src/greenland/greenland.h @@ -17,8 +17,6 @@ #ifndef ART_SRC_GREENLAND_GREENLAND_H_ #define ART_SRC_GREENLAND_GREENLAND_H_ -#include "dex_lang.h" - #include "macros.h" #include "object.h" @@ -31,6 +29,7 @@ namespace art { namespace art { namespace greenland { +class GBCContext; class TargetCodeGenMachine; class Greenland { @@ -54,11 +53,11 @@ class Greenland { Mutex lock_; - // NOTE: Ensure that the lock_ is held before altering cur_dex_lang_ctx_ - DexLang::Context *cur_dex_lang_ctx_; + // NOTE: Ensure that the lock_ is held before altering cur_gbc_ctx + GBCContext *cur_gbc_ctx_; - DexLang::Context& GetDexLangContext(); - void ResetDexLangContextIfThresholdReached(); + GBCContext& GetGBCContext(); + void ResetGBCContextIfThresholdReached(); DISALLOW_COPY_AND_ASSIGN(Greenland); }; diff --git a/src/greenland/inferred_reg_category_map.cc b/src/greenland/inferred_reg_category_map.cc deleted file mode 100644 index 4f7f4ff..0000000 --- a/src/greenland/inferred_reg_category_map.cc +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "inferred_reg_category_map.h" - -#include "backend_types.h" -#include "stl_util.h" - -#include <stdint.h> -#include <vector> - -namespace art { -namespace greenland { - -InferredRegCategoryMap::InferredRegCategoryMap(uint32_t insns_size, - uint8_t regs_size) -: registers_size_(regs_size), lines_(insns_size, NULL), can_be_object_(regs_size) { -} - -InferredRegCategoryMap::~InferredRegCategoryMap() { - STLDeleteElements(&lines_); -} - -RegCategory InferredRegCategoryMap::GetRegCategory(uint32_t dex_pc, - uint16_t reg_idx) const { - if (lines_[dex_pc] == NULL) { - return kRegUnknown; - } - return lines_[dex_pc]->GetRegCategory(reg_idx); -} - -void InferredRegCategoryMap::SetRegCategory(uint32_t dex_pc, - uint16_t reg_idx, - RegCategory cat) { - if (cat != kRegUnknown) { - if (lines_[dex_pc] == NULL) { - lines_[dex_pc] = new RegCategoryLine(); - } - - (*lines_[dex_pc]).SetRegCategory(reg_idx, cat); - } -} - -bool InferredRegCategoryMap::IsRegCanBeObject(uint16_t reg_idx) const { - return can_be_object_[reg_idx]; -} - -void InferredRegCategoryMap::SetRegCanBeObject(uint16_t reg_idx) { - can_be_object_[reg_idx] = true; -} - -bool InferredRegCategoryMap:: -operator==(InferredRegCategoryMap const& rhs) const { - - if (registers_size_ != rhs.registers_size_) { - return false; - } - - if (lines_.size() != rhs.lines_.size()) { - return false; - } - - for (size_t i = 0; i < lines_.size(); ++i) { - if (lines_[i] == NULL && rhs.lines_[i] == NULL) { - continue; - } - - if ((lines_[i] == NULL && rhs.lines_[i] != NULL) || - (lines_[i] != NULL && rhs.lines_[i] == NULL)) { - return false; - } - - if (*lines_[i] != *rhs.lines_[i]) { - return false; - } - } - - return true; -} - -bool InferredRegCategoryMap:: -operator!=(InferredRegCategoryMap const& rhs) const { - - return !(*this == rhs); -} - - -} // namespace greenland -} // namespace art diff --git a/src/greenland/inferred_reg_category_map.h b/src/greenland/inferred_reg_category_map.h deleted file mode 100644 index 57e0c30..0000000 --- a/src/greenland/inferred_reg_category_map.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_SRC_GREENLAND_INFERRED_REG_CATEGORY_MAP_H_ -#define ART_SRC_GREENLAND_INFERRED_REG_CATEGORY_MAP_H_ - -#include "backend_types.h" - -#include <stdint.h> -#include <vector> - -#include "safe_map.h" - -namespace art { -namespace greenland { - -class InferredRegCategoryMap { - private: - class RegCategoryLine { - private: - typedef SafeMap<uint16_t, uint8_t> Table; - Table reg_category_line_; - - public: - RegCategory GetRegCategory(uint16_t reg_idx) const { - // TODO: C++0x auto - Table::const_iterator result = reg_category_line_.find(reg_idx); - if (result == reg_category_line_.end()) { - return kRegUnknown; - } - return static_cast<RegCategory>(result->second); - } - - void SetRegCategory(uint16_t reg_idx, RegCategory cat) { - if (cat != kRegUnknown) { - reg_category_line_.Put(reg_idx, cat); - } - } - - bool operator==(RegCategoryLine const& rhs) const { - return reg_category_line_ == rhs.reg_category_line_; - } - bool operator!=(RegCategoryLine const& rhs) const { - return reg_category_line_ != rhs.reg_category_line_; - } - }; - - public: - InferredRegCategoryMap(uint32_t insns_size_in_code_units, uint8_t regs_size); - - ~InferredRegCategoryMap(); - - RegCategory GetRegCategory(uint32_t dex_pc, uint16_t reg_idx) const; - void SetRegCategory(uint32_t dex_pc, uint16_t reg_idx, RegCategory cat); - - bool IsRegCanBeObject(uint16_t reg_idx) const; - void SetRegCanBeObject(uint16_t reg_idx); - - bool operator==(InferredRegCategoryMap const& rhs) const; - bool operator!=(InferredRegCategoryMap const& rhs) const; - - private: - uint16_t registers_size_; - - std::vector<RegCategoryLine*> lines_; - - std::vector<bool> can_be_object_; - - DISALLOW_COPY_AND_ASSIGN(InferredRegCategoryMap); -}; - - -} // namespace greenland -} // namespace art - -#endif // ART_SRC_GREENLAND_INFERRED_REG_CATEGORY_MAP_H_ diff --git a/src/greenland/intrinsic_func_list.def b/src/greenland/intrinsic_func_list.def index 3f3fae1..f288bbc 100644 --- a/src/greenland/intrinsic_func_list.def +++ b/src/greenland/intrinsic_func_list.def @@ -58,10 +58,31 @@ // Thread* dex_lang_get_current_thread() _EVAL_DEF_INTRINSICS_FUNC(GetCurrentThread, dex_lang_get_current_thread, - kAttrReadOnly | kAttrNoThrow, - kJavaThreadTy, + kAttrReadNone | kAttrNoThrow, + kJavaThreadTy, _EXPAND_ARG0()) +// void dex_lang_test_suspend(Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(TestSuspend, + dex_lang_test_suspend, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG1(kJavaThreadTy)) + +// void dex_lang_check_suspend() /* Expands to GetCurrentThread/TestSuspend */ +_EVAL_DEF_INTRINSICS_FUNC(CheckSuspend, + dex_lang_check_suspend, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG0()) + +// void dex_lang_mark_gc_card(Object* new_value, Object* object) +_EVAL_DEF_INTRINSICS_FUNC(MarkGCCard, + dex_lang_mark_gc_card, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG2(kJavaObjectTy, kJavaObjectTy)) + //---------------------------------------------------------------------------- // Exception //---------------------------------------------------------------------------- @@ -78,6 +99,13 @@ _EVAL_DEF_INTRINSICS_FUNC(CatchTargets, kInt32Ty, _EXPAND_ARG1(kInt32ConstantTy)) +// void dex_lang_throw_exception(JavaObject* exception) +_EVAL_DEF_INTRINSICS_FUNC(ThrowException, + dex_lang_throw_exception, + kAttrDoThrow, + kVoidTy, + _EXPAND_ARG1(kJavaObjectTy)) + // JavaObject* dex_lang_get_current_exception() _EVAL_DEF_INTRINSICS_FUNC(GetException, dex_lang_get_current_exception, @@ -102,31 +130,24 @@ _EVAL_DEF_INTRINSICS_FUNC(FindCatchBlock, // void dex_lang_throw_div_zero() _EVAL_DEF_INTRINSICS_FUNC(ThrowDivZeroException, dex_lang_throw_div_zero, - kAttrNoThrow, + kAttrDoThrow, kVoidTy, _EXPAND_ARG0()) // void dex_lang_throw_null_pointer_exception(uint32_t dex_pc) _EVAL_DEF_INTRINSICS_FUNC(ThrowNullPointerException, dex_lang_throw_null_pointer_exception, - kAttrNoThrow, + kAttrDoThrow, kVoidTy, _EXPAND_ARG1(kInt32ConstantTy)) // void dex_lang_throw_array_bounds(int index, int array_len) _EVAL_DEF_INTRINSICS_FUNC(ThrowIndexOutOfBounds, dex_lang_throw_array_bounds, - kAttrNoThrow, + kAttrDoThrow, kVoidTy, _EXPAND_ARG2(kInt32Ty, kInt32Ty)) -// void dex_lang_throw(exception_object) -_EVAL_DEF_INTRINSICS_FUNC(Throw, - dex_lang_throw, - kAttrNoThrow, - kVoidTy, - _EXPAND_ARG1(kJavaObjectTy)) - //---------------------------------------------------------------------------- // ConstString //---------------------------------------------------------------------------- @@ -138,16 +159,24 @@ _EVAL_DEF_INTRINSICS_FUNC(ConstString, kJavaObjectTy, _EXPAND_ARG1(kInt32ConstantTy)) -// JavaObject* dex_lang_const_string(uint32_t string_idx) -_EVAL_DEF_INTRINSICS_FUNC(ConstStringFast, - dex_lang_const_string.fast, +// JavaObject* dex_lang_load_string_from_dex_cache(Method* method, uint32_t string_idx) +_EVAL_DEF_INTRINSICS_FUNC(LoadStringFromDexCache, + dex_lang_load_string_from_dex_cache, kAttrReadOnly | kAttrNoThrow, kJavaObjectTy, _EXPAND_ARG1(kInt32ConstantTy)) +// JavaObject* dex_lang_resolve_string(Method* method, uint32_t string_idx) +_EVAL_DEF_INTRINSICS_FUNC(ResolveString, + dex_lang_resolve_string, + kAttrNone, + kJavaObjectTy, + _EXPAND_ARG2(kJavaMethodTy, kInt32ConstantTy)) + //---------------------------------------------------------------------------- // ConstClass //---------------------------------------------------------------------------- + // JavaObject* dex_lang_const_class(uint32_t type_idx) _EVAL_DEF_INTRINSICS_FUNC(ConstClass, dex_lang_const_class, @@ -155,16 +184,96 @@ _EVAL_DEF_INTRINSICS_FUNC(ConstClass, kJavaObjectTy, _EXPAND_ARG1(kInt32ConstantTy)) +// JavaObject* dex_lang_initialize_type_and_verify_access(uint32_t type_idx, +// Method* referrer, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(InitializeTypeAndVerifyAccess, + dex_lang_initialize_type_and_verify_access, + kAttrNone, + kJavaObjectTy, + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaThreadTy)) + +// JavaObject* dex_lang_load_type_from_dex_cache(uint32_t type_idx) +_EVAL_DEF_INTRINSICS_FUNC(LoadTypeFromDexCache, + dex_lang_load_type_from_dex_cache, + kAttrReadOnly | kAttrNoThrow, + kJavaObjectTy, + _EXPAND_ARG1(kInt32ConstantTy)) + +// JavaObject* dex_lang_initialize_type(uint32_t type_idx, +// Method* referrer, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(InitializeType, + dex_lang_initialize_type, + kAttrNone, + kJavaObjectTy, + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaThreadTy)) + +//---------------------------------------------------------------------------- +// Lock +//---------------------------------------------------------------------------- + +// void dex_lang_lock_object(JavaObject* obj, Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(LockObject, + dex_lang_lock_object, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG2(kJavaObjectTy, kJavaThreadTy)) + +// void dex_lang_unlock_object(JavaObject* obj, Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(UnlockObject, + dex_lang_unlock_object, + kAttrNone, + kVoidTy, + _EXPAND_ARG2(kJavaObjectTy, kJavaThreadTy)) + //---------------------------------------------------------------------------- -// CheckCast +// Cast //---------------------------------------------------------------------------- -// void dex_lang_check_cast(uint32_t type_idx, JavaObject* obj) + +// void dex_lang_check_cast(JavaObject* dest_type, JavaObject* src_type) _EVAL_DEF_INTRINSICS_FUNC(CheckCast, dex_lang_check_cast, + kAttrNone, + kVoidTy, + _EXPAND_ARG2(kJavaObjectTy, kJavaObjectTy)) + +// void dex_lang_hl_check_cast(uint32_t type_idx, JavaObject* obj) +_EVAL_DEF_INTRINSICS_FUNC(HLCheckCast, + dex_lang_hl_check_cast, kAttrReadOnly | kAttrNoThrow, kVoidTy, _EXPAND_ARG2(kInt32ConstantTy, kJavaObjectTy)) +// int dex_lang_is_assignable(JavaObject* dest_type, JavaObject* src_type) +_EVAL_DEF_INTRINSICS_FUNC(IsAssignable, + dex_lang_is_assignable, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG2(kJavaObjectTy, kJavaObjectTy)) + +//---------------------------------------------------------------------------- +// Allocation +//---------------------------------------------------------------------------- + +// JavaObject* dex_lang_alloc_object(uint32_t type_idx, +// Method* referrer, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(AllocObject, + dex_lang_alloc_object, + kAttrNone, + kJavaObjectTy, + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaThreadTy)) + +// JavaObject* dex_lang_alloc_object_with_access_check(uint32_t type_idx, +// Method* referrer, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(AllocObjectWithAccessCheck, + dex_lang_alloc_object_with_access_check, + kAttrNone, + kJavaObjectTy, + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaThreadTy)) + //---------------------------------------------------------------------------- // Instance //---------------------------------------------------------------------------- @@ -187,13 +296,6 @@ _EVAL_DEF_INTRINSICS_FUNC(InstanceOf, // Array //---------------------------------------------------------------------------- -// uint32_t dex_lang_array_length(int32_t opt_flags, JavaObject* array) -_EVAL_DEF_INTRINSICS_FUNC(ArrayLength, - dex_lang_array_length, - kAttrReadOnly | kAttrNoThrow, - kInt32Ty, - _EXPAND_ARG2(kInt32Ty, kJavaObjectTy)) - // JavaObject* dex_lang_new_array(uint32_t type_idx, uint32_t array_size) _EVAL_DEF_INTRINSICS_FUNC(NewArray, dex_lang_new_array, @@ -201,12 +303,59 @@ _EVAL_DEF_INTRINSICS_FUNC(NewArray, kJavaObjectTy, _EXPAND_ARG2(kInt32ConstantTy, kInt32Ty)) -// void dex_lang_fill_array_data(int32_t offset, JavaObject* array) -_EVAL_DEF_INTRINSICS_FUNC(FillArrayData, - dex_lang_fill_array_data, +// uint32_t dex_lang_opt_array_length(int32_t opt_flags, JavaObject* array) +_EVAL_DEF_INTRINSICS_FUNC(OptArrayLength, + dex_lang_opt_array_length, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG2(kInt32Ty, kJavaObjectTy)) + +// uint32_t dex_lang_array_length(JavaObject* array) +_EVAL_DEF_INTRINSICS_FUNC(ArrayLength, + dex_lang_array_length, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG1(kJavaObjectTy)) + +// JavaObject* dex_lang_alloc_array(uint32_t type_idx, +// Method* referrer, +// uint32_t length, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(AllocArray, + dex_lang_alloc_array, kAttrNone, - kVoidTy, - _EXPAND_ARG2(kInt32ConstantTy, kJavaObjectTy)) + kJavaObjectTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kInt32Ty, kJavaThreadTy)) + +// JavaObject* dex_lang_alloc_array_with_access_check(uint32_t type_idx, +// Method* referrer, +// uint32_t length, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(AllocArrayWithAccessCheck, + dex_lang_alloc_array_with_access_check, + kAttrNone, + kJavaObjectTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kInt32Ty, kJavaThreadTy)) + +// JavaObject* dex_lang_check_and_alloc_array(uint32_t type_idx, +// Method* referrer, +// uint32_t length, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(CheckAndAllocArray, + dex_lang_check_and_alloc_array, + kAttrNone, + kJavaObjectTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kInt32ConstantTy, kJavaThreadTy)) + +// JavaObject* dex_lang_check_and_alloc_array_with_access_check(uint32_t type_idx, +// Method* referrer, +// uint32_t length, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(CheckAndAllocArrayWithAccessCheck, + dex_lang_check_and_alloc_array_with_access_check, + kAttrNone, + kJavaObjectTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kInt32ConstantTy, kJavaThreadTy)) // dex_lang_aget_* and dex_lang_aput_* never generate exception since the // necessary checking on arguments (e.g., array and index) has already done @@ -301,10 +450,221 @@ _EVAL_DEF_INTRINSICS_FUNC(ArrayPutShort, // void dex_lang_check_put_array_element(JavaObject* value, JavaObject* array) _EVAL_DEF_INTRINSICS_FUNC(CheckPutArrayElement, dex_lang_check_put_array_element, - kAttrReadOnly | kAttrNoThrow, + kAttrNone, kVoidTy, _EXPAND_ARG2(kJavaObjectTy, kJavaObjectTy)) +// void dex_lang_filled_new_array(Array* array, +// uint32_t elem_jty, ...) +_EVAL_DEF_INTRINSICS_FUNC(FilledNewArray, + dex_lang_filled_new_array, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kVarArgTy)) + +// void dex_lang_fill_array_data(Method* referrer, +// uint32_t dex_pc, +// Array* array, +// uint32_t payload_offset) +_EVAL_DEF_INTRINSICS_FUNC(FillArrayData, + dex_lang_fill_array_data, + kAttrNone, + kVoidTy, + _EXPAND_ARG4(kJavaMethodTy, kInt32ConstantTy, kJavaObjectTy, kInt32ConstantTy)) + +// void dex_lang_hl_fill_array_data(int32_t offset, JavaObject* array) +_EVAL_DEF_INTRINSICS_FUNC(HLFillArrayData, + dex_lang_hl_fill_array_data, + kAttrNone, + kVoidTy, + _EXPAND_ARG2(kInt32ConstantTy, kJavaObjectTy)) + +//---------------------------------------------------------------------------- +// Instance Field +//---------------------------------------------------------------------------- + +// [type] dex_lang_iget_[type](uint32_t field_idx, +// Method* referrer, +// JavaObject* obj) +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGet, + dex_lang_iget, + kAttrNone, + _JTYPE(kInt32Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetWide, + dex_lang_iget_wide, + kAttrNone, + _JTYPE(kInt64Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetObject, + dex_lang_iget_object, + kAttrNone, + _JTYPE(kJavaObjectTy, kField), + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetBoolean, + dex_lang_iget_boolean, + kAttrNone, + _JTYPE(kInt1Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetByte, + dex_lang_iget_byte, + kAttrNone, + _JTYPE(kInt8Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetChar, + dex_lang_iget_char, + kAttrNone, + _JTYPE(kInt16Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetShort, + dex_lang_iget_short, + kAttrNone, + _JTYPE(kInt16Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy)) + +// [type] dex_lang_iget_[type].fast(int field_offset, +// bool is_volatile, +// JavaObject* obj) +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetFast, + dex_lang_iget.fast, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt32Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetWideFast, + dex_lang_iget_wide.fast, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt64Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetObjectFast, + dex_lang_iget_object.fast, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kJavaObjectTy, kField), + _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetBooleanFast, + dex_lang_iget_boolean.fast, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt1Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetByteFast, + dex_lang_iget_byte.fast, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt8Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetCharFast, + dex_lang_iget_char.fast, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt16Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetShortFast, + dex_lang_iget_short.fast, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt16Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy)) + +// void dex_lang_iput_[type](uint32_t field_idx, +// Method* referrer, +// JavaObject* obj, +// [type] new_value) +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPut, + dex_lang_iput, + kAttrNone, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt32Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutWide, + dex_lang_iput_wide, + kAttrNone, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt64Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutObject, + dex_lang_iput_object, + kAttrNone, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kJavaObjectTy, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutBoolean, + dex_lang_iput_boolean, + kAttrNone, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt1Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutByte, + dex_lang_iput_byte, + kAttrNone, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt8Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutChar, + dex_lang_iput_char, + kAttrNone, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt16Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutShort, + dex_lang_iput_short, + kAttrNone, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt16Ty, kField))) + +// void dex_lang_iput_[type].fast(int field_offset, +// bool is_volatile, +// JavaObject* obj, +// [type] new_value) +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutFast, + dex_lang_iput.fast, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt32Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutWideFast, + dex_lang_iput_wide.fast, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt64Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutObjectFast, + dex_lang_iput_object.fast, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kJavaObjectTy, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutBooleanFast, + dex_lang_iput_boolean.fast, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt1Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutByteFast, + dex_lang_iput_byte.fast, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt8Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutCharFast, + dex_lang_iput_char.fast, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt16Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutShortFast, + dex_lang_iput_short.fast, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt16Ty, kField))) + //---------------------------------------------------------------------------- // Static Field //---------------------------------------------------------------------------- @@ -312,43 +672,43 @@ _EVAL_DEF_INTRINSICS_FUNC(CheckPutArrayElement, // [type] dex_lang_sget_[type](uint32_t field_idx, Method* referrer) _EVAL_DEF_INTRINSICS_FUNC(StaticFieldGet, dex_lang_sget, - kAttrReadOnly, + kAttrNone, _JTYPE(kInt32Ty, kField), _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy)) _EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetWide, dex_lang_sget_wide, - kAttrReadOnly, + kAttrNone, _JTYPE(kInt64Ty, kField), _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy)) _EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetObject, dex_lang_sget_object, - kAttrReadOnly, + kAttrNone, _JTYPE(kJavaObjectTy, kField), _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy)) _EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetBoolean, dex_lang_sget_boolean, - kAttrReadOnly, + kAttrNone, _JTYPE(kInt1Ty, kField), _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy)) _EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetByte, dex_lang_sget_byte, - kAttrReadOnly, + kAttrNone, _JTYPE(kInt8Ty, kField), _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy)) _EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetChar, dex_lang_sget_char, - kAttrReadOnly, + kAttrNone, _JTYPE(kInt16Ty, kField), _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy)) _EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetShort, dex_lang_sget_short, - kAttrReadOnly, + kAttrNone, _JTYPE(kInt16Ty, kField), _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy)) @@ -802,7 +1162,7 @@ _EVAL_DEF_INTRINSICS_FUNC(HLInvokeDouble, _EXPAND_ARG1(kVarArgTy)) // FILLED_NEW_ARRAY returns object -_EVAL_DEF_INTRINSICS_FUNC(FilledNewArray, +_EVAL_DEF_INTRINSICS_FUNC(HLFilledNewArray, dex_lang_hl_filled_new_array, kAttrNone, kJavaObjectTy, @@ -812,21 +1172,60 @@ _EVAL_DEF_INTRINSICS_FUNC(FilledNewArray, // Invoke //---------------------------------------------------------------------------- -// Method* dex_lang_get_callee_method_obj_addr(uint32_t method_idx, -// JavaObject* this, -// Method* referrer, -// Thread* thread, -// InvokeType type) -_EVAL_DEF_INTRINSICS_FUNC(GetCalleeMethodObjAddr, - dex_lang_get_callee_method_obj_addr, - kAttrReadOnly, +// Method* dex_lang_find_static_method_with_access_check(uint32_t method_idx, +// JavaObject* this, +// Method* referrer, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(FindStaticMethodWithAccessCheck, + dex_lang_find_static_method_with_access_check, + kAttrNone, + kJavaMethodTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy)) + +// Method* dex_lang_find_direct_method_with_access_check(uint32_t method_idx, +// JavaObject* this, +// Method* referrer, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(FindDirectMethodWithAccessCheck, + dex_lang_find_direct_method_with_access_check, + kAttrNone, kJavaMethodTy, - _EXPAND_ARG5(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy, kInt32ConstantTy)) + _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy)) + +// Method* dex_lang_find_virtual_method_with_access_check(uint32_t method_idx, +// JavaObject* this, +// Method* referrer, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(FindVirtualMethodWithAccessCheck, + dex_lang_find_virtual_method_with_access_check, + kAttrNone, + kJavaMethodTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy)) + +// Method* dex_lang_find_super_method_with_access_check(uint32_t method_idx, +// JavaObject* this, +// Method* referrer, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(FindSuperMethodWithAccessCheck, + dex_lang_find_super_method_with_access_check, + kAttrNone, + kJavaMethodTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy)) + +// Method* dex_lang_find_interface_method_with_access_check(uint32_t method_idx, +// JavaObject* this, +// Method* referrer, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(FindInterfaceMethodWithAccessCheck, + dex_lang_find_interface_method_with_access_check, + kAttrNone, + kJavaMethodTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy)) // Method* dex_lang_get_sd_callee_method_obj_addr(uint32_t method_idx) _EVAL_DEF_INTRINSICS_FUNC(GetSDCalleeMethodObjAddrFast, dex_lang_get_sd_callee_method_obj_addr_fast, - kAttrReadOnly, + kAttrReadOnly | kAttrNoThrow, kJavaMethodTy, _EXPAND_ARG1(kInt32ConstantTy)) @@ -844,7 +1243,7 @@ _EVAL_DEF_INTRINSICS_FUNC(GetVirtualCalleeMethodObjAddrFast, // Thread* thread) _EVAL_DEF_INTRINSICS_FUNC(GetInterfaceCalleeMethodObjAddrFast, dex_lang_get_interface_callee_method_obj_addr_fast, - kAttrReadOnly, + kAttrNone, kJavaMethodTy, _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy)) @@ -856,21 +1255,63 @@ _EVAL_DEF_INTRINSICS_FUNC(InvokeRetVoid, kVoidTy, _EXPAND_ARG2(kJavaMethodTy, kVarArgTy)) -// INVOKE method returns the value of type in Dalvik register category 1 -_EVAL_DEF_INTRINSICS_FUNC(InvokeRetCat1, - dex_lang_invoke.i32, +// INVOKE method returns the value of type boolean +_EVAL_DEF_INTRINSICS_FUNC(InvokeRetBoolean, + dex_lang_invoke.bool, + kAttrNone, + kInt1Ty, + _EXPAND_ARG2(kJavaMethodTy, kVarArgTy)) + +// INVOKE method returns the value of type byte +_EVAL_DEF_INTRINSICS_FUNC(InvokeRetByte, + dex_lang_invoke.byte, + kAttrNone, + kInt8Ty, + _EXPAND_ARG2(kJavaMethodTy, kVarArgTy)) + +// INVOKE method returns the value of type char +_EVAL_DEF_INTRINSICS_FUNC(InvokeRetChar, + dex_lang_invoke.char, + kAttrNone, + kInt16Ty, + _EXPAND_ARG2(kJavaMethodTy, kVarArgTy)) + +// INVOKE method returns the value of type short +_EVAL_DEF_INTRINSICS_FUNC(InvokeRetShort, + dex_lang_invoke.short, + kAttrNone, + kInt16Ty, + _EXPAND_ARG2(kJavaMethodTy, kVarArgTy)) + +// INVOKE method returns the value of type int +_EVAL_DEF_INTRINSICS_FUNC(InvokeRetInt, + dex_lang_invoke.int, kAttrNone, kInt32Ty, _EXPAND_ARG2(kJavaMethodTy, kVarArgTy)) -// INVOKE method returns the value of type in Dalvik register category 2 -_EVAL_DEF_INTRINSICS_FUNC(InvokeRetCat2, - dex_lang_invoke.i64, +// INVOKE method returns the value of type long +_EVAL_DEF_INTRINSICS_FUNC(InvokeRetLong, + dex_lang_invoke.long, kAttrNone, kInt64Ty, _EXPAND_ARG2(kJavaMethodTy, kVarArgTy)) -// INVOKE method returns the value of type in Dalvik register category "object" +// INVOKE method returns the value of type float +_EVAL_DEF_INTRINSICS_FUNC(InvokeRetFloat, + dex_lang_invoke.float, + kAttrNone, + kFloatTy, + _EXPAND_ARG2(kJavaMethodTy, kVarArgTy)) + +// INVOKE method returns the value of type double +_EVAL_DEF_INTRINSICS_FUNC(InvokeRetDouble, + dex_lang_invoke.double, + kAttrNone, + kDoubleTy, + _EXPAND_ARG2(kJavaMethodTy, kVarArgTy)) + +// INVOKE method returns the value of type "object" _EVAL_DEF_INTRINSICS_FUNC(InvokeRetObject, dex_lang_invoke.object, kAttrNone, @@ -884,46 +1325,57 @@ _EVAL_DEF_INTRINSICS_FUNC(InvokeRetObject, // int dex_lang_{div,rem}_int(int a, int b) _EVAL_DEF_INTRINSICS_FUNC(DivInt, dex_lang_div_int, - kAttrReadOnly | kAttrNoThrow, + kAttrReadNone | kAttrNoThrow, kInt32Ty, _EXPAND_ARG2(kInt32Ty, kInt32Ty)) _EVAL_DEF_INTRINSICS_FUNC(RemInt, dex_lang_rem_int, - kAttrReadOnly | kAttrNoThrow, + kAttrReadNone | kAttrNoThrow, kInt32Ty, _EXPAND_ARG2(kInt32Ty, kInt32Ty)) // long dex_lang_{div,rem}_long(long a, long b) _EVAL_DEF_INTRINSICS_FUNC(DivLong, dex_lang_div_long, - kAttrReadOnly | kAttrNoThrow, + kAttrReadNone | kAttrNoThrow, kInt64Ty, _EXPAND_ARG2(kInt64Ty, kInt64Ty)) _EVAL_DEF_INTRINSICS_FUNC(RemLong, dex_lang_rem_long, - kAttrReadOnly | kAttrNoThrow, + kAttrReadNone | kAttrNoThrow, kInt64Ty, _EXPAND_ARG2(kInt64Ty, kInt64Ty)) -//---------------------------------------------------------------------------- -// Suspend Test -//---------------------------------------------------------------------------- +// int64_t dex_lang_d2l(double f) +_EVAL_DEF_INTRINSICS_FUNC(D2L, + dex_lang_d2l, + kAttrReadNone | kAttrNoThrow, + kInt64Ty, + _EXPAND_ARG1(kDoubleTy)) -// void dex_lang_test_suspend(Thread* thread) -_EVAL_DEF_INTRINSICS_FUNC(TestSuspend, - dex_lang_test_suspend, - kAttrNoThrow, - kVoidTy, - _EXPAND_ARG1(kJavaThreadTy)) +// int32_t dex_lang_d2l(double f) +_EVAL_DEF_INTRINSICS_FUNC(D2I, + dex_lang_d2i, + kAttrReadNone | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG1(kDoubleTy)) + +// int64_t dex_lang_f2l(float f) +_EVAL_DEF_INTRINSICS_FUNC(F2L, + dex_lang_f2l, + kAttrReadNone | kAttrNoThrow, + kInt64Ty, + _EXPAND_ARG1(kFloatTy)) + +// int32_t dex_lang_f2i(float f) +_EVAL_DEF_INTRINSICS_FUNC(F2I, + dex_lang_f2i, + kAttrReadNone | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG1(kFloatTy)) -// void dex_lang_check_suspend() /* Expands to GetCurrentThread/TestSuspend */ -_EVAL_DEF_INTRINSICS_FUNC(CheckSuspend, - dex_lang_check_suspend, - kAttrNoThrow, - kVoidTy, - _EXPAND_ARG0()) //---------------------------------------------------------------------------- // sput intrinsics to assist MIR to Greenland_ir conversion. // "HL" versions - will be deprecated when fast/slow path handling done diff --git a/src/greenland/intrinsic_helper.cc b/src/greenland/intrinsic_helper.cc index b1837fb..7e926d6 100644 --- a/src/greenland/intrinsic_helper.cc +++ b/src/greenland/intrinsic_helper.cc @@ -21,7 +21,6 @@ #include <llvm/DerivedTypes.h> #include <llvm/Function.h> #include <llvm/Intrinsics.h> -#include <llvm/Module.h> #include <llvm/Support/IRBuilder.h> using namespace art; @@ -65,10 +64,12 @@ GetLLVMTypeOfIntrinsicValType(IRBuilder& irb, case IntrinsicHelper::kInt64ConstantTy: { return irb.getInt64Ty(); } - case IntrinsicHelper::kFloatTy: { + case IntrinsicHelper::kFloatTy: + case IntrinsicHelper::kFloatConstantTy: { return irb.getFloatTy(); } - case IntrinsicHelper::kDoubleTy: { + case IntrinsicHelper::kDoubleTy: + case IntrinsicHelper::kDoubleConstantTy: { return irb.getDoubleTy(); } case IntrinsicHelper::kNone: @@ -86,7 +87,7 @@ GetLLVMTypeOfIntrinsicValType(IRBuilder& irb, namespace art { namespace greenland { -const IntrinsicHelper::IntrinsicInfo IntrinsicHelper::Info[MaxIntrinsicId] = { +const IntrinsicHelper::IntrinsicInfo IntrinsicHelper::Info[] = { #define DEF_INTRINSICS_FUNC(_, NAME, ATTR, RET_TYPE, ARG1_TYPE, ARG2_TYPE, \ ARG3_TYPE, ARG4_TYPE, \ ARG5_TYPE) \ @@ -144,6 +145,7 @@ IntrinsicHelper::IntrinsicHelper(llvm::LLVMContext& context, info.name_, &module); fn->setOnlyReadsMemory(info.attr_ & kAttrReadOnly); + fn->setDoesNotAccessMemory(info.attr_ & kAttrReadNone); // None of the intrinsics throws exception fn->setDoesNotThrow(true); diff --git a/src/greenland/intrinsic_helper.h b/src/greenland/intrinsic_helper.h index 7e84cc9..365d529 100644 --- a/src/greenland/intrinsic_helper.h +++ b/src/greenland/intrinsic_helper.h @@ -47,11 +47,22 @@ class IntrinsicHelper { enum IntrinsicAttribute { kAttrNone = 0, - // Intrinsic that doesn't modify the memory state - kAttrReadOnly = 1 << 0, + // Intrinsic that neither modified the memory state nor refer to the global + // state + kAttrReadNone = 1 << 0, + + // Intrinsic that doesn't modify the memory state. Note that one should set + // this flag carefully when the intrinsic may throw exception. Since the + // thread state is implicitly modified when an exception is thrown. + kAttrReadOnly = 1 << 1, + + // Note that intrinsic without kAttrNoThrow and kAttrDoThrow set means that + // intrinsic generates exception in some cases // Intrinsic that never generates exception - kAttrNoThrow = 1 << 1, + kAttrNoThrow = 1 << 2, + // Intrinsic that always generate exception + kAttrDoThrow = 1 << 3, }; enum IntrinsicValType { @@ -68,15 +79,16 @@ class IntrinsicHelper { kInt16Ty, kInt32Ty, kInt64Ty, + kFloatTy, + kDoubleTy, kInt1ConstantTy, kInt8ConstantTy, kInt16ConstantTy, kInt32ConstantTy, kInt64ConstantTy, - - kFloatTy, - kDoubleTy, + kFloatConstantTy, + kDoubleConstantTy, kVarArgTy, }; @@ -93,7 +105,7 @@ class IntrinsicHelper { } IntrinsicInfo; private: - static const IntrinsicInfo Info[MaxIntrinsicId]; + static const IntrinsicInfo Info[]; public: static const IntrinsicInfo& GetInfo(IntrinsicId id) { @@ -130,7 +142,10 @@ class IntrinsicHelper { } private: - llvm::Function* intrinsic_funcs_[MaxIntrinsicId]; + // FIXME: "+1" is to workaround the GCC bugs: + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43949 + // Remove this when uses newer GCC (> 4.4.3) + llvm::Function* intrinsic_funcs_[MaxIntrinsicId + 1]; // Map a llvm::Function to its intrinsic id llvm::DenseMap<const llvm::Function*, IntrinsicId> intrinsic_funcs_map_; diff --git a/src/greenland/ir_builder.cc b/src/greenland/ir_builder.cc index d47a458..e83996a 100644 --- a/src/greenland/ir_builder.cc +++ b/src/greenland/ir_builder.cc @@ -25,9 +25,24 @@ IRBuilder::IRBuilder(llvm::LLVMContext& context, llvm::Module& module, IntrinsicHelper& intrinsic_helper) : LLVMIRBuilder(context), java_object_type_(NULL), java_method_type_(NULL), java_thread_type_(NULL), intrinsic_helper_(intrinsic_helper) { + // JavaObject must be defined in the module java_object_type_ = module.getTypeByName("JavaObject")->getPointerTo(); - java_method_type_ = module.getTypeByName("Method")->getPointerTo(); - java_thread_type_ = module.getTypeByName("Thread")->getPointerTo(); + + // If type of Method is not explicitly defined in the module, use JavaObject* + llvm::Type* type = module.getTypeByName("Method"); + if (type != NULL) { + java_method_type_ = type->getPointerTo(); + } else { + java_method_type_ = java_object_type_; + } + + // If type of Thread is not explicitly defined in the module, use JavaObject* + type = module.getTypeByName("Thread"); + if (type != NULL) { + java_thread_type_ = type->getPointerTo(); + } else { + java_thread_type_ = java_object_type_; + } } llvm::Type* IRBuilder::GetJTypeInAccurateSpace(JType jty) { diff --git a/src/greenland/lir.h b/src/greenland/lir.h deleted file mode 100644 index 82116b2..0000000 --- a/src/greenland/lir.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_SRC_GREENLAND_LIR_H_ -#define ART_SRC_GREENLAND_LIR_H_ - -#include "logging.h" -#include "macros.h" -#include "object.h" - -#include "lir_desc.h" -#include "lir_operand.h" - -#include <vector> - -#include <llvm/ADT/ilist_node.h> - -namespace art { -namespace greenland { - -class LIRFunction; - -class LIR : public llvm::ilist_node<LIR> { - private: - // LIRs are allocated and owned by LIRFunction. - friend class LIRFunction; - - LIR(const LIRDesc& desc); - - ~LIR() { } - - private: - LIRFunction* parent_; - - const LIRDesc& desc_; // Instruction descriptor - - std::vector<LIROperand> operands_; - -#if 0 - struct { - bool is_nop:1; // LIR is optimized away - bool pc_rel_fixup:1; // May need pc-relative fixup - unsigned int age:4; // default is 0, set lazily by the optimizer - unsigned int size:5; // in bytes - unsigned int unused:21; - } flags_; - - int alias_info_; // For Dalvik register & litpool disambiguation - uint8_t use_mask_; // Resource mask for use - uint8_t def_mask_; // Resource mask for def -#endif - - private: - // Intrusive list support - friend struct llvm::ilist_traits<LIR>; - friend struct llvm::ilist_traits<LIRFunction>; - void SetParent(LIRFunction *parent) { - parent_ = parent; - } - - public: - const LIRFunction* GetParent() const { - return parent_; - } - - LIRFunction* GetParent() { - return parent_; - } - - const LIRDesc& GetDesc() const { - return desc_; - } - - int GetOpcode() const { - return desc_.opcode_; - } - - public: - //---------------------------------------------------------------------------- - // Operand Operations - //---------------------------------------------------------------------------- - unsigned GetNumOperands() const { - return static_cast<unsigned>(operands_.size()); - } - - const LIROperand& GetOperand(unsigned i) const { - DCHECK(i < GetNumOperands()) << "GetOperand() out of range!"; - return operands_[i]; - } - - LIROperand& GetOperand(unsigned i) { - DCHECK(i < GetNumOperands()) << "GetOperand() out of range!"; - return operands_[i]; - } - - /// iterator/begin/end - Iterate over all operands of a machine instruction. - typedef std::vector<LIROperand>::iterator op_iterator; - typedef std::vector<LIROperand>::const_iterator const_op_iterator; - - op_iterator operands_begin() { return operands_.begin(); } - op_iterator operands_end() { return operands_.end(); } - - const_op_iterator operands_begin() const { return operands_.begin(); } - const_op_iterator operands_end() const { return operands_.end(); } - - private: - DISALLOW_COPY_AND_ASSIGN(LIR); -}; - -} // namespace greenland -} // namespace art - -#endif // ART_SRC_GREENLAND_LIR_H_ diff --git a/src/greenland/lir_frame_info.h b/src/greenland/lir_frame_info.h deleted file mode 100644 index ecaa7f3..0000000 --- a/src/greenland/lir_frame_info.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_SRC_GREENLAND_LIR_FRAME_INFO_H_ -#define ART_SRC_GREENLAND_LIR_FRAME_INFO_H_ - -#include "logging.h" - -#include <vector> - -namespace art { -namespace greenland { - -class LIRFrameInfo { - private: - struct StackObject { - // The offset from the stack pointer - off_t sp_offset_; - - // The object is a dead object if its size is 0 - size_t size_; - - unsigned alignment_; - - StackObject(size_t size, unsigned alignment) - : size_(size), alignment_(alignment) { } - }; - - // stack_size_ and sp_offset_ in each StackObject will be updated by ... - size_t stack_size_; - - std::vector<StackObject> objects_; - - public: - LIRFrameInfo() : stack_size_(0) { } - - bool HasStackObjects() const { - return !objects_.empty(); - } - - unsigned GetNumObjects() const { - return objects_.size(); - } - - size_t GetStackSize() const { - return stack_size_; - } - void SetStackSize(size_t stack_size) { - stack_size_ = stack_size; - return; - } - - //---------------------------------------------------------------------------- - // Stack Object - //---------------------------------------------------------------------------- - size_t GetObjectOffset(unsigned idx) const { - DCHECK(idx < GetNumObjects()) << "Invalid frame index!"; - return objects_[idx].sp_offset_; - } - void SetObjectOffset(unsigned idx, off_t sp_offset) { - DCHECK(idx < GetNumObjects()) << "Invalid frame index!"; - objects_[idx].sp_offset_ = sp_offset; - return; - } - - size_t GetObjectSize(unsigned idx) const { - DCHECK(idx < GetNumObjects()) << "Invalid frame index!"; - return objects_[idx].size_; - } - - size_t GetObjectAlignment(unsigned idx) const { - DCHECK(idx < GetNumObjects()) << "Invalid frame index!"; - return objects_[idx].alignment_; - } - - unsigned AllocateStackObject(size_t size, unsigned alignment = 1) { - DCHECK(size > 0); - objects_.push_back(StackObject(size, alignment)); - return objects_.size() - 1; - } - - void RemoveStackObject(unsigned idx) { - DCHECK(idx < GetNumObjects()) << "Invalid frame index!"; - objects_[idx].size_ = 0; - return; - } -}; - -} // namespace greenland -} // namespace art - -#endif // ART_SRC_GREENLAND_LIR_FRAME_INFO_H_ diff --git a/src/greenland/lir_function.cc b/src/greenland/lir_function.cc deleted file mode 100644 index 5def2ac..0000000 --- a/src/greenland/lir_function.cc +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "lir_function.h" - -#include "lir_frame_info.h" - -#include "logging.h" - -namespace llvm { - -using art::greenland::LIR; -using art::greenland::LIRFunction; - -void ilist_traits<LIR>::addNodeToList(LIR* lir) { - DCHECK(lir->GetParent() == 0) << "LIR already in a function"; - // Update the LIR::parent_ - lir->SetParent(parent_); - return; -} - -void ilist_traits<LIR>::removeNodeFromList(LIR* lir) { - DCHECK(lir->GetParent() == 0) << "LIR is not in a function"; - // Update the LIR::parent_ - lir->SetParent(NULL); - return; -} - -void ilist_traits<LIR>::transferNodesFromList(ilist_traits &src_traits, - ilist_iterator<LIR> first, - ilist_iterator<LIR> last) { - UNIMPLEMENTED(FATAL); - return; -} - -void ilist_traits<LIR>::deleteNode(LIR* lir) { - CHECK(!lir->GetParent()) << "LIR is still in a block!"; - parent_->DeleteLIR(lir); - return; -} - -} // namespace llvm - -namespace art { -namespace greenland { - -LIRFunction::LIRFunction() : frame_info_(NULL) { - lirs_.parent_ = this; - frame_info_ = new (allocator_) LIRFrameInfo(); - return; -} - -LIRFunction::~LIRFunction() { - lirs_.clear(); - lir_recycler_.clear(allocator_); - - frame_info_->~LIRFrameInfo(); - allocator_.Deallocate(frame_info_); - - return; -} - -LIR* LIRFunction::CreateLIR(const LIRDesc& desc) { - return new (lir_recycler_.Allocate<LIR>(allocator_)) LIR(desc); -} - -void LIRFunction::DeleteLIR(LIR* lir) { - lir->~LIR(); - lir_recycler_.Deallocate(allocator_, lir); -} - -} // namespace greenland -} // namespace art diff --git a/src/greenland/lir_function.h b/src/greenland/lir_function.h deleted file mode 100644 index 0e77f17..0000000 --- a/src/greenland/lir_function.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_SRC_GREENLAND_LIR_FUNCTION_H_ -#define ART_SRC_GREENLAND_LIR_FUNCTION_H_ - -#include "lir.h" - -#include <llvm/ADT/ilist.h> -#include <llvm/Support/Allocator.h> -#include <llvm/Support/Recycler.h> - -namespace llvm { - -template <> -struct ilist_traits<art::greenland::LIR> : - public ilist_default_traits<art::greenland::LIR> { - private: - mutable ilist_half_node<art::greenland::LIR> sentinel_; - - friend class art::greenland::LIRFunction; - art::greenland::LIRFunction* parent_; - - public: - art::greenland::LIR *createSentinel() const { - return static_cast<art::greenland::LIR*>(&sentinel_); - } - void destroySentinel(art::greenland::LIR *) const {} - - art::greenland::LIR *provideInitialHead() const { - return createSentinel(); - } - art::greenland::LIR *ensureHead(art::greenland::LIR*) const { - return createSentinel(); - } - static void noteHead(art::greenland::LIR*, art::greenland::LIR*) {} - - void addNodeToList(art::greenland::LIR* N); - void removeNodeFromList(art::greenland::LIR* N); - void transferNodesFromList(ilist_traits &src_traits, - ilist_iterator<art::greenland::LIR> first, - ilist_iterator<art::greenland::LIR> last); - void deleteNode(art::greenland::LIR *N); -private: - void createNode(const art::greenland::LIR &); -}; - -} // namespace llvm - -namespace art { -namespace greenland { - -class LIRFrameInfo; - -class LIRFunction { - private: - llvm::ilist<LIR> lirs_; - - // Pool-allocate the objects reside in this instance - llvm::BumpPtrAllocator allocator_; - - // Allocation management for instructions in function. - llvm::Recycler<LIR> lir_recycler_; - - // The stack information - LIRFrameInfo* frame_info_; - - public: - LIRFunction(); - ~LIRFunction(); - - public: - //---------------------------------------------------------------------------- - // LIR Accessor Functions - //---------------------------------------------------------------------------- - typedef llvm::ilist<LIR>::iterator iterator; - typedef llvm::ilist<LIR>::const_iterator const_iterator; - typedef std::reverse_iterator<iterator> reverse_iterator; - typedef std::reverse_iterator<const_iterator> const_reverse_iterator; - - unsigned GetNumLIRs() const { - return static_cast<unsigned>(lirs_.size()); - } - bool IsEmpty() const { - return lirs_.empty(); - } - - LIR& front() { return lirs_.front(); } - LIR& back() { return lirs_.back(); } - const LIR& front() const { return lirs_.front(); } - const LIR& back() const { return lirs_.back(); } - - iterator begin() { return lirs_.begin(); } - const_iterator begin() const { return lirs_.begin(); } - iterator end() { return lirs_.end(); } - const_iterator end() const { return lirs_.end(); } - reverse_iterator rbegin() { return lirs_.rbegin(); } - const_reverse_iterator rbegin() const { return lirs_.rbegin(); } - reverse_iterator rend () { return lirs_.rend(); } - const_reverse_iterator rend () const { return lirs_.rend(); } - - void pop_front() { - lirs_.pop_front(); - } - - void push_back(LIR *lir) { - lirs_.push_back(lir); - } - - iterator insert(iterator i, LIR* lir) { - return lirs_.insert(i, lir); - } - - iterator erase(iterator i) { - return lirs_.erase(i); - } - - LIR* remove(iterator i) { - return lirs_.remove(i); - } - - public: - //---------------------------------------------------------------------------- - // LIR Memory Allocation - //---------------------------------------------------------------------------- - LIR* CreateLIR(const LIRDesc& desc); - - void DeleteLIR(LIR* lir); - - public: - const LIRFrameInfo& GetFrameInfo() const { - return *frame_info_; - } - LIRFrameInfo& GetFrameInfo() { - return *frame_info_; - } - - private: - DISALLOW_COPY_AND_ASSIGN(LIRFunction); -}; - -} // namespace greenland -} // namespace art - -#endif // ART_SRC_GREENLAND_LIR_FUNCTION_H_ diff --git a/src/greenland/lir_operand.h b/src/greenland/lir_operand.h deleted file mode 100644 index d6d9232..0000000 --- a/src/greenland/lir_operand.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_SRC_GREENLAND_LIR_OPERAND_H_ -#define ART_SRC_GREENLAND_LIR_OPERAND_H_ - -#include "logging.h" - -namespace llvm { - class ConstantFP; -} - -namespace art { -namespace greenland { - -class LIR; - -class LIROperand { - public: - enum Type { - UnknownType, - RegisterType, - ImmediateType, - FPImmediateType, - LabelType, - }; - - private: - Type type_; - - union { - // RegisterType - unsigned reg_no_; - - // ImmediateType - int64_t imm_val_; - - // FPImmediateType - const llvm::ConstantFP *fp_imm_val_; - - // LabelType - const LIR* target_; - } contents_; - - friend class LIR; - LIROperand() : type_(UnknownType) { } - - void SetType(enum Type type) { - type_ = type; - return; - } - - public: - enum Type GetType() const { - return type_; - } - - bool IsReg() const { - return (type_ == RegisterType); - } - bool IsImm() const { - return (type_ == ImmediateType); - } - bool IsFPImm() const { - return (type_ == FPImmediateType); - } - bool IsLabel() const { - return (type_ == LabelType); - } - - //---------------------------------------------------------------------------- - // Accessors - //---------------------------------------------------------------------------- - unsigned GetReg() const { - CHECK(IsReg()) << "This is not a register operand!"; - return contents_.reg_no_; - } - - int64_t GetImm() const { - CHECK(IsImm()) << "This is not a immediate operand!"; - return contents_.imm_val_; - } - - const llvm::ConstantFP* GetFPImm() const { - CHECK(IsFPImm()) << "This is not a FP immediate operand!"; - return contents_.fp_imm_val_; - } - - const LIR* GetLabelTarget() const { - CHECK(IsFPImm()) << "This is not a label operand!"; - return contents_.target_; - } - - //---------------------------------------------------------------------------- - // Mutators - //---------------------------------------------------------------------------- - void SetReg(unsigned reg_no) { - if (type_ == UnknownType) { - type_ = RegisterType; - } - CHECK(IsReg()) << "This is not a register operand!"; - contents_.reg_no_ = reg_no; - return; - } - - void SetImm(int64_t imm_val) { - if (type_ == UnknownType) { - type_ = ImmediateType; - } - CHECK(IsImm()) << "This is not a immediate operand!"; - contents_.imm_val_ = imm_val; - return; - } - - void SetFPImm(const llvm::ConstantFP* fp_imm_val) { - if (type_ == UnknownType) { - type_ = FPImmediateType; - } - CHECK(IsFPImm()) << "This is not a FP immediate operand!"; - contents_.fp_imm_val_ = fp_imm_val; - return; - } - - void SetLabelTarget(LIR* target) { - if (type_ == UnknownType) { - type_ = LabelType; - } - CHECK(IsLabel()) << "This is not a label operand!"; - contents_.target_ = target; - return; - } - -}; - -} // namespace greenland -} // namespace art - -#endif // ART_SRC_GREENLAND_LIR_OPERAND_H_ diff --git a/src/greenland/mips/mips_codegen_machine.h b/src/greenland/mips/mips_codegen_machine.h index e3412e9..c9f0abf 100644 --- a/src/greenland/mips/mips_codegen_machine.h +++ b/src/greenland/mips/mips_codegen_machine.h @@ -29,9 +29,27 @@ class MipsCodeGenMachine : public TargetCodeGenMachine { MipsCodeGenMachine(); virtual ~MipsCodeGenMachine(); - virtual TargetLIREmitter* CreateLIREmitter(const llvm::Function& func, - const OatCompilationUnit& cunit, - DexLang::Context& dex_lang_ctx) { + virtual TargetLIREmitter* CreateLIREmitter() { + return NULL; + } + + virtual const TargetDataLayout* GetDataLayout() const { + return NULL; + } + + virtual const TargetLIRInfo* GetLIRInfo() const { + return NULL; + } + + virtual const TargetRegisterInfo* GetRegisterInfo() const { + return NULL; + } + + virtual const char* GetConditionCodeName(unsigned cond) const { + return NULL; + } + + virtual TargetLIRBuilder* CreateLIRBuilder() { return NULL; } @@ -42,6 +60,10 @@ class MipsCodeGenMachine : public TargetCodeGenMachine { virtual TargetAssembler* GetAssembler() { return NULL; } + + virtual std::string PrettyTargeteLIR(const LIR& lir) const { + return ""; + } }; } // namespace greenland diff --git a/src/greenland/target_lir.def b/src/greenland/mips/mips_lir.def index a3838c6..0741f1b 100644 --- a/src/greenland/target_lir.def +++ b/src/greenland/mips/mips_lir.def @@ -14,9 +14,5 @@ * limitations under the License. */ -// DEF_LIR_DESC(OPCODE, NUM_OPS) -#ifndef DEF_LIR_DESC -# error "missing DEF_LIR_DESC definition!" -#endif - -DEF_LIR_DESC(kBlockLabel, 1) +#include "greenland/target_lir.def" +#include "greenland/clear_target_lir.def" diff --git a/src/greenland/register_allocator.cc b/src/greenland/register_allocator.cc new file mode 100644 index 0000000..b19f111 --- /dev/null +++ b/src/greenland/register_allocator.cc @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "register_allocator.h" +#include "lir_function.h" +#include "lir_frame_info.h" +#include "lir_reg.h" + +#include "target_register_info.h" + +#include "logging.h" +#include "stl_util.h" + +namespace art { +namespace greenland { + +void RegisterAllocator::BuildKillInfo(LIRFunction& lir_func) { + //TODO: Build Register KillInfo +} + +static LIRBasicBlock::iterator +GetSourceIterator(LIRBasicBlock& sourceBB, LIRBasicBlock& targetBB) { + LIRBasicBlock::iterator it; + for (it = sourceBB.back(); it != sourceBB.begin(); --it) { + if (it->IsBranch() && (it->GetOperand(0).GetLabelTarget() == &targetBB)) + break; + } + return it; +} + +void RegisterAllocator::PHIElimination(LIRFunction& lir_func) { + for (LIRFunction::iterator bb = lir_func.begin(); bb != lir_func.end(); ++bb) { + if (bb->IsEmpty() || !bb->front().IsPHI()) + continue; + + LIRBasicBlock::iterator it; // current LIR + LIRBasicBlock::iterator next_it; // next LIR + for(it = bb->begin(); it != bb->end(); it = next_it) { + next_it = it; ++next_it; + if (!it->IsPHI()) + break; + + for (unsigned i = 1; i < it->GetNumOperands(); i+=2) { + const LIROperand& dst = it->GetOperand(0); + const LIROperand& src = it->GetOperand(i); + LIRBasicBlock* sourceBB = + const_cast<LIRBasicBlock*> (it->GetOperand(i + 1).GetLabelTarget()); + + LIR* lir = reg_info_.CreateCopy(lir_func, dst.GetReg(), src); + LOG(INFO) << "PHIElimination: Insert COPY into BB: " << sourceBB->GetName(); + sourceBB->insert(GetSourceIterator(*sourceBB, *bb), lir); + } + + bb->erase(it); + } + } +} + +RegisterAllocator::Storage +RegisterAllocator::AllocateStorage(LIRFunction &lir_func, unsigned vreg_idx) { + // The virtual register is allocated, return it. + if (allocated_map_.find(vreg_idx) != allocated_map_.end()) { + return allocated_map_[vreg_idx]; + } + + Storage s; + // Have free register(s). + if (!allocatable_list_.empty()) { + s.regTag = kPhyRegType; + s.index = allocatable_list_.front(); + allocatable_list_.pop_front(); + } + else { + s.regTag = kFrameType; + if (stackstorage_list_.empty()) { + // FIXME: Get register subword + s.index = lir_func.GetFrameInfo().AllocateStackObject(4); + } + else { + s.index = stackstorage_list_.front(); + stackstorage_list_.pop_front(); + } + } + allocated_map_[vreg_idx] = s; + return s; +} + +void RegisterAllocator::KeepStorage(const LIR& lir) { + unsigned reg_value = lir.GetOperand(0).GetReg(); + int frame_idx = lir.GetOperand(1).GetFrameIndex(); + + if (!LIRReg::IsVirtualReg(reg_value)) + return; + + unsigned vreg_idx = LIRReg::GetRegNo(reg_value); + + LOG(INFO) << "VIRTUAL REG " << vreg_idx << " Keep in Stack Frame [" << frame_idx << "];"; + + Storage s; + s.regTag = kInStackType; + s.index = frame_idx; + allocated_map_[vreg_idx] = s; +} + +void RegisterAllocator::FreeStorage(unsigned vreg_idx) { + //TODO: Check vreg_idx must be allocated + Storage s = allocated_map_[vreg_idx]; + + if (s.regTag == kInStackType) + return; + + if (s.regTag == kPhyRegType) + allocatable_list_.push_front(s.index); + else + stackstorage_list_.push_front(s.index); + + allocated_map_.erase(vreg_idx); +} + +void RegisterAllocator::InitializeAllocation(LIRFunction &lir_func) { + allocatable_list_ = reg_info_.GetAllocatableList(); + stackstorage_list_.clear(); + allocated_map_.clear(); +} + +void RegisterAllocator::PreRegisterAllocation(LIRFunction &lir_func) { + PHIElimination(lir_func); +} + +void +RegisterAllocator::HandleInsnCopy(LIRBasicBlock &bb, + LIRBasicBlock::iterator it, + LIRBasicBlock::iterator next_it) { + unsigned reg_dst = it->GetOperand(0).GetReg(); + unsigned reg_src = it->GetOperand(1).GetReg(); + + Storage stor_dst = {-1, kNoneType}; + Storage stor_src = {-1, kNoneType}; + unsigned vidx_dst = 0, vidx_src = 0; + + if (LIRReg::IsVirtualReg(reg_dst)) { + vidx_dst = LIRReg::GetRegNo(reg_dst); + LOG(INFO) << "VIRTUAL REG " << vidx_dst << " in COPY need allocated !!"; + stor_dst = AllocateStorage(bb.GetParent(), vidx_dst); + } + + if (LIRReg::IsVirtualReg(reg_src)) { + vidx_src = LIRReg::GetRegNo(reg_src); + LOG(INFO) << "VIRTUAL REG " << vidx_src << " in COPY need allocated !!"; + stor_src = AllocateStorage(bb.GetParent(), vidx_src); + } + + if ((LIRReg::IsPhysicalReg(reg_dst) || (stor_dst.regTag == kPhyRegType)) + && (LIRReg::IsPhysicalReg(reg_src) || (stor_src.regTag == kPhyRegType))) { + // MovRR + unsigned idx_dst = (LIRReg::IsPhysicalReg(reg_dst)) ? + LIRReg::GetRegNo(reg_dst) : stor_dst.index; + unsigned idx_src = (LIRReg::IsPhysicalReg(reg_src)) ? + LIRReg::GetRegNo(reg_src) : stor_src.index; + LOG(INFO) << "\t [COPY] create MOVE: move " << idx_dst << ", "<< idx_src; + LIR* lir = reg_info_.CreateMoveReg(bb.GetParent(), idx_dst, idx_src); + bb.insert(next_it, lir); + bb.erase(it); + + if(LIRReg::IsVirtualReg(reg_src)) { + FreeStorage(vidx_src); + } + return; + } + + if ((stor_dst.regTag == stor_src.regTag) && (stor_dst.index == stor_src.index)) { + // Redundant move + FreeStorage(vidx_dst); + FreeStorage(vidx_src); + bb.erase(it); + return; + } + + if (stor_dst.regTag != kPhyRegType && stor_src.regTag != kPhyRegType) { + unsigned idx = reg_info_.GetTempRegsiter(0); + LIR* lir = reg_info_.CreateLoadStack(bb.GetParent(), idx, stor_src.index); + bb.insert(it, lir); + lir = reg_info_.CreateStoreStack(bb.GetParent(), idx, stor_dst.index); + bb.insert(next_it, lir); + bb.erase(it); + return; + } + + if (stor_dst.regTag != kPhyRegType) { + unsigned idx = (LIRReg::IsPhysicalReg(reg_src)) ? + LIRReg::GetRegNo(reg_src) : stor_src.index; + LOG(INFO) << "\t [COPY] create StoreStack: move " << idx << ", "<< stor_dst.index; + LIR* lir = reg_info_.CreateStoreStack(bb.GetParent(), idx, stor_dst.index); + bb.insert(next_it, lir); + bb.erase(it); + return; + } + + if (stor_src.regTag != kPhyRegType) { + unsigned idx = (LIRReg::IsPhysicalReg(reg_dst)) ? + LIRReg::GetRegNo(reg_dst) : stor_dst.index; + LOG(INFO) << "\t [COPY] create LoadStack: move " << idx << ", "<< stor_src.index; + LIR* lir = reg_info_.CreateLoadStack(bb.GetParent(), idx, stor_src.index); + bb.insert(next_it, lir); + bb.erase(it); + return; + } +} + +void RegisterAllocator::FunctionRegisterAllocation(LIRFunction &lir_func) { + for (LIRFunction::iterator bb = lir_func.begin(); bb != lir_func.end(); ++bb) { + LIRBasicBlock::iterator it; // current LIR + LIRBasicBlock::iterator next_it; // next LIR + for (LIRBasicBlock::iterator it = bb->begin(); it != bb->end(); it = next_it) { + next_it = it; ++next_it; + + // Handle Incoming Args + if (reg_info_.IsLoadIncomingArgs(it)) { + KeepStorage(*it); + bb->erase(it); + continue; + } + + // Handle Copy + if (it->GetOpcode() == opcode::kCOPY) { + HandleInsnCopy(*bb, *it, *next_it); + continue; + } + + std::vector<unsigned> free_list; + //for (LIR::op_iterator opi = i->operands_begin(); opi != i->operands_end(); ++opi) { + for (unsigned i = 0 ; i < it->GetNumOperands(); i++) { + LIROperand& lir_opd = it->GetOperand(i); + unsigned temp_count = 0; + + if (!lir_opd.IsReg()) + continue; + + unsigned reg_value = lir_opd.GetReg(); + if (!LIRReg::IsVirtualReg(reg_value)) + continue; + unsigned vreg_idx = LIRReg::GetRegNo(reg_value); + LOG(INFO) << "\t" << "VIRTUAL REG " << vreg_idx << " need allocated !!"; + Storage s = AllocateStorage(lir_func, vreg_idx); + if (!s.regTag) { + LOG(INFO) << "\t" << "VIRTUAL REG " << vreg_idx << " is map to REG[" << s.index << "]!!"; + lir_opd.SetReg(s.index); + } else { + unsigned temp_idx = reg_info_.GetTempRegsiter(temp_count++); + if ( lir_opd.IsDef() ) { + LIR* lir = reg_info_.CreateStoreStack(lir_func, temp_idx, s.index); + bb->insert(next_it, lir); + lir_opd.SetReg(temp_idx); + } else { + LIR* lir = reg_info_.CreateLoadStack(lir_func, temp_idx, s.index); + bb->insert(it, lir); + lir_opd.SetReg(temp_idx); + } + + LOG(INFO) << "\t" << "VIRTUAL REG " << vreg_idx << " is map to Frame[" << s.index << "]!!"; + } + + if (lir_opd.IsKill()) { + free_list.push_back(vreg_idx); + LOG(INFO) << "\t" << "VIRTUAL REG " << vreg_idx << " is mark kill!!"; + } + } + + for (size_t i = 0 ; i < free_list.size(); i++) { + LOG(INFO) << "\t" << "VIRTUAL REG " << free_list[i] << " is kill!!"; + FreeStorage(free_list[i]); + } + } + } +} + +} // namespace greenland +} // namespace art diff --git a/src/greenland/register_allocator.h b/src/greenland/register_allocator.h new file mode 100644 index 0000000..ffe0914 --- /dev/null +++ b/src/greenland/register_allocator.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_SRC_GREENLAND_REGISTER_ALLOCATOR_H_ +#define ART_SRC_GREENLAND_REGISTER_ALLOCATOR_H_ + +#include "backend_types.h" + +#include "lir_basic_block.h" + +#include <stdint.h> +#include <list> +#include <map> + +namespace art { +namespace greenland { + +class LIR; +class LIRFunction; +class TargetRegisterInfo; + +class RegisterAllocator { + private: + enum RegTypeTag { + kPhyRegType = 0, kFrameType, kInStackType, kNoneType = -1 + }; + + struct Storage { + int index; + RegTypeTag regTag; + }; + + // Storage Allocation + Storage AllocateStorage(LIRFunction &lir_func, unsigned vreg_idx); + void KeepStorage(const LIR& lir); + void FreeStorage(unsigned vreg_idx); + void HandleInsnCopy(LIRBasicBlock& bb, + LIRBasicBlock::iterator it, + LIRBasicBlock::iterator next_lir); + + // Pre-RA + void BuildKillInfo(LIRFunction& lir_func); + void PHIElimination(LIRFunction& lir_func); + + void InitializeAllocation(LIRFunction& lir_func); + void PreRegisterAllocation(LIRFunction& lir_func); + void FunctionRegisterAllocation(LIRFunction& lir_func); + public: + RegisterAllocator(const TargetRegisterInfo& info) : reg_info_(info) { } + ~RegisterAllocator() { } + + void AllocateRegisters(LIRFunction& lir_func) { + InitializeAllocation(lir_func); + PreRegisterAllocation(lir_func); + FunctionRegisterAllocation(lir_func); + } + + private: + std::list<unsigned> allocatable_list_; + std::list<unsigned> stackstorage_list_; + std::map<unsigned, Storage> allocated_map_; + const TargetRegisterInfo& reg_info_; + DISALLOW_COPY_AND_ASSIGN(RegisterAllocator); +}; + +} // namespace greenland +} // namespace art + +#endif // ART_SRC_GREENLAND_REGISTER_ALLOCATOR_H_ diff --git a/src/greenland/target_lir_opcodes.h b/src/greenland/runtime/runtime_utils.h index 27027ca..cbdfcc6 100644 --- a/src/greenland/target_lir_opcodes.h +++ b/src/greenland/runtime/runtime_utils.h @@ -14,21 +14,29 @@ * limitations under the License. */ -#ifndef ART_SRC_GREENLAND_TARGET_LIR_OPCODES_H_ -#define ART_SRC_GREENLAND_TARGET_LIR_OPCODES_H_ +#ifndef ART_SRC_GREENLAND_RUNTIME_UTILS_H_ +#define ART_SRC_GREENLAND_RUNTIME_UTILS_H_ + +#include "asm_support.h" +#include "thread.h" namespace art { namespace greenland { -namespace opcode { -enum { -#define DEF_LIR_DESC(OPCODE, ...) OPCODE, -#include "target_lir.def" -#undef DEF_LIR_DESC -}; +static inline Thread* art_get_current_thread() { +#if defined(__i386__) + Thread* ptr; + __asm__ __volatile__("movl %%fs:(%1), %0" + : "=r"(ptr) // output + : "r"(THREAD_SELF_OFFSET) // input + :); // clobber + return ptr; +#else + return Thread::Current(); +#endif +} -} // namespace opcode } // namespace greenland } // namespace art -#endif // ART_SRC_GREENLAND_TARGET_LIR_OPCODES_H_ +#endif // ART_SRC_GREENLAND_RUNTIME_UTILS_H_ diff --git a/src/greenland/runtime/support_alloc.cc b/src/greenland/runtime/support_alloc.cc new file mode 100644 index 0000000..5198903 --- /dev/null +++ b/src/greenland/runtime/support_alloc.cc @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "greenland/runtime_entry_points.h" + +#include "runtime_utils.h" +#include "runtime_support.h" + +using namespace art; +using namespace art::greenland; + +namespace { + +Object* art_alloc_array_from_code(uint32_t type_idx, + Method* referrer, + uint32_t length, + Thread* thread) { + return AllocArrayFromCode(type_idx, referrer, length, thread, false); +} + +Object* art_alloc_array_from_code_with_access_check(uint32_t type_idx, + Method* referrer, + uint32_t length, + Thread* thread) { + return AllocArrayFromCode(type_idx, referrer, length, thread, true); +} + +Object* art_check_and_alloc_array_from_code(uint32_t type_idx, + Method* referrer, + uint32_t length, + Thread* thread) { + return CheckAndAllocArrayFromCode(type_idx, referrer, length, thread, false); +} + +Object* art_check_and_alloc_array_from_code_with_access_check(uint32_t type_idx, + Method* referrer, + uint32_t length, + Thread* thread) { + return CheckAndAllocArrayFromCode(type_idx, referrer, length, thread, true); +} + +} // anonymous namespace + +namespace art { +namespace greenland { + +void InitAllocRuntimes(RuntimeEntryPoints* entry_points) { + entry_points->AllocArray = art_alloc_array_from_code; + entry_points->AllocArrayWithAccessCheck = art_alloc_array_from_code_with_access_check; + entry_points->CheckAndAllocArray = art_check_and_alloc_array_from_code; + entry_points->CheckAndAllocArrayWithAccessCheck = art_check_and_alloc_array_from_code_with_access_check; + return; +} + +} // namespace greenland +} // namespace art diff --git a/src/greenland/runtime/support_cast.cc b/src/greenland/runtime/support_cast.cc new file mode 100644 index 0000000..d74dbe7 --- /dev/null +++ b/src/greenland/runtime/support_cast.cc @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "greenland/runtime_entry_points.h" + +#include "runtime_utils.h" +#include "runtime_support.h" + +using namespace art; +using namespace art::greenland; + +namespace { + +void art_check_put_array_element_from_code(const Object* element, + const Object* array) { + if (element == NULL) { + return; + } + DCHECK(array != NULL); + Class* array_class = array->GetClass(); + DCHECK(array_class != NULL); + Class* component_type = array_class->GetComponentType(); + Class* element_class = element->GetClass(); + if (UNLIKELY(!component_type->IsAssignableFrom(element_class))) { + Thread* thread = art_get_current_thread(); + thread->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;", + "%s cannot be stored in an array of type %s", + PrettyDescriptor(element_class).c_str(), + PrettyDescriptor(array_class).c_str()); + } + return; +} + +} // anonymous namespace + +namespace art { +namespace greenland { + +void InitCastRuntimes(RuntimeEntryPoints* entry_points) { + entry_points->CheckPutArrayElement = art_check_put_array_element_from_code; +} + +} // namespace greenland +} // namespace art diff --git a/src/greenland/lir_desc.h b/src/greenland/runtime/support_dexcache.cc index 84b7af6..903e5cc 100644 --- a/src/greenland/lir_desc.h +++ b/src/greenland/runtime/support_dexcache.cc @@ -14,27 +14,28 @@ * limitations under the License. */ -#ifndef ART_SRC_GREENLAND_LIR_DESC_H_ -#define ART_SRC_GREENLAND_LIR_DESC_H_ +#include "greenland/runtime_entry_points.h" -namespace art { -namespace greenland { +#include "runtime_utils.h" +#include "runtime_support.h" + +using namespace art; +using namespace art::greenland; + +namespace { -class LIRDesc { - public: - unsigned opcode_; // The opcode number - unsigned short num_operands_; // Num of args (may be more if variable_ops) +Object* art_resolve_string(Method* referrer, uint32_t string_idx) { + return ResolveStringFromCode(referrer, string_idx); +} - unsigned GetOpcode() const { - return opcode_; - } +} // anonymous namespace - unsigned GetNumOperands() const { - return num_operands_; - } -}; +namespace art { +namespace greenland { + +void InitDexCacheRuntimes(RuntimeEntryPoints* entry_points) { + entry_points->ResolveString = art_resolve_string; +} } // namespace greenland } // namespace art - -#endif // ART_SRC_GREENLAND_LIR_DESC_H_ diff --git a/src/greenland/runtime/support_exception.cc b/src/greenland/runtime/support_exception.cc new file mode 100644 index 0000000..2470051 --- /dev/null +++ b/src/greenland/runtime/support_exception.cc @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "greenland/runtime_entry_points.h" + +#include "nth_caller_visitor.h" +#include "runtime_utils.h" +#include "runtime_support.h" + +using namespace art; +using namespace art::greenland; + +namespace { + +int32_t art_find_catch_block(Method* current_method, uint32_t ti_offset) { + Thread* thread = art_get_current_thread(); + Class* exception_type = thread->GetException()->GetClass(); + MethodHelper mh(current_method); + const DexFile::CodeItem* code_item = mh.GetCodeItem(); + DCHECK_LT(ti_offset, code_item->tries_size_); + const DexFile::TryItem* try_item = DexFile::GetTryItems(*code_item, ti_offset); + + int iter_index = 0; + // Iterate over the catch handlers associated with dex_pc + for (CatchHandlerIterator it(*code_item, *try_item); it.HasNext(); it.Next()) { + uint16_t iter_type_idx = it.GetHandlerTypeIndex(); + // Catch all case + if (iter_type_idx == DexFile::kDexNoIndex16) { + return iter_index; + } + // Does this catch exception type apply? + Class* iter_exception_type = mh.GetDexCacheResolvedType(iter_type_idx); + if (iter_exception_type == NULL) { + // The verifier should take care of resolving all exception classes early + LOG(WARNING) << "Unresolved exception class when finding catch block: " + << mh.GetTypeDescriptorFromTypeIdx(iter_type_idx); + } else if (iter_exception_type->IsAssignableFrom(exception_type)) { + return iter_index; + } + ++iter_index; + } + // Handler not found + return -1; +} + +void art_throw_array_bounds(int32_t length, int32_t index) { + Thread* thread = art_get_current_thread(); + thread->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;", + "length=%d; index=%d", length, index); +} + +void art_throw_null_pointer_exception(uint32_t dex_pc) { + Thread* thread = art_get_current_thread(); + NthCallerVisitor visitor(0); + thread->WalkStack(&visitor); + Method* throw_method = visitor.caller; + ThrowNullPointerExceptionFromDexPC(thread, throw_method, dex_pc); +} + +} // anonymous namespace + +namespace art { +namespace greenland { + +void InitExceptionRuntimes(RuntimeEntryPoints* entry_points) { + entry_points->FindCatchBlock = art_find_catch_block; + entry_points->ThrowIndexOutOfBounds = art_throw_array_bounds; + entry_points->ThrowNullPointerException = art_throw_null_pointer_exception; +} + +} // namespace greenland +} // namespace art diff --git a/src/greenland/runtime/support_field.cc b/src/greenland/runtime/support_field.cc new file mode 100644 index 0000000..523740f --- /dev/null +++ b/src/greenland/runtime/support_field.cc @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "greenland/runtime_entry_points.h" + +#include "runtime_utils.h" +#include "runtime_support.h" + +using namespace art; +using namespace art::greenland; + +namespace { + +Object* art_get_obj_static_from_code(uint32_t field_idx, Method* referrer) { + Field* field = FindFieldFast(field_idx, referrer, false, false, sizeof(Object*)); + if (LIKELY(field != NULL)) { + return field->GetObj(NULL); + } + field = FindFieldFromCode(field_idx, referrer, art_get_current_thread(), + true, false, false, sizeof(Object*)); + if (LIKELY(field != NULL)) { + return field->GetObj(NULL); + } + return 0; +} + +} // anonymous namespace + +namespace art { +namespace greenland { + +void InitFieldRuntimes(RuntimeEntryPoints* entry_points) { + entry_points->GetObjectStatic = art_get_obj_static_from_code; +} + +} // namespace greenland +} // namespace art diff --git a/src/greenland/lir.cc b/src/greenland/runtime/support_thread.cc index 72fb03b..25fb698 100644 --- a/src/greenland/lir.cc +++ b/src/greenland/runtime/support_thread.cc @@ -14,16 +14,28 @@ * limitations under the License. */ -#include "lir.h" +#include "greenland/runtime_entry_points.h" -#include "lir_desc.h" -#include "lir_function.h" +#include "runtime_utils.h" +#include "runtime_support.h" +#include "thread_list.h" + +using namespace art; +using namespace art::greenland; + +namespace { + +void art_test_suspend(Thread* thread) { + Runtime::Current()->GetThreadList()->FullSuspendCheck(thread); +} + +} // anonymous namespace namespace art { namespace greenland { -LIR::LIR(const LIRDesc& desc) : parent_(NULL), desc_(desc) { - operands_.reserve(desc_.GetNumOperands()); +void InitThreadRuntimes(RuntimeEntryPoints* entry_points) { + entry_points->TestSuspend = art_test_suspend; } } // namespace greenland diff --git a/src/greenland/runtime_entry_points.cc b/src/greenland/runtime_entry_points.cc new file mode 100644 index 0000000..a9b1edc --- /dev/null +++ b/src/greenland/runtime_entry_points.cc @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "runtime_entry_points.h" + +namespace art { + +// Forward Declarations +namespace greenland { + +void InitThreadRuntimes(RuntimeEntryPoints* entry_points); +void InitExceptionRuntimes(RuntimeEntryPoints* entry_points); +void InitAllocRuntimes(RuntimeEntryPoints* entry_points); +void InitDexCacheRuntimes(RuntimeEntryPoints* entry_points); +void InitFieldRuntimes(RuntimeEntryPoints* entry_points); +void InitCastRuntimes(RuntimeEntryPoints* entry_points); + +} // namespace greenland + +void InitRuntimeEntryPoints(RuntimeEntryPoints* entry_points) { + // Defined in runtime/support_thread.cc + greenland::InitThreadRuntimes(entry_points); + // Defined in runtime/support_exception.cc + greenland::InitExceptionRuntimes(entry_points); + // Defined in runtime/support_alloc.cc + greenland::InitAllocRuntimes(entry_points); + // Defined in runtime/support_dexcache.cc + greenland::InitDexCacheRuntimes(entry_points); + // Defined in runtime/support_field.cc + greenland::InitFieldRuntimes(entry_points); + // Defined in runtime/support_case.cc + greenland::InitCastRuntimes(entry_points); + return; +} + +} // namespace art diff --git a/src/greenland/runtime_entry_points.h b/src/greenland/runtime_entry_points.h new file mode 100644 index 0000000..8cd8ce4 --- /dev/null +++ b/src/greenland/runtime_entry_points.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_SRC_GREENLAND_RUNTIME_ENTRY_POINTS_H_ +#define ART_SRC_GREENLAND_RUNTIME_ENTRY_POINTS_H_ + +#include "macros.h" + +#include <stdint.h> + +#define RUNTIME_ENTRYPOINT(x) \ + (static_cast<uintptr_t>(OFFSETOF_MEMBER(Thread, runtime_entry_points_)) + \ + static_cast<uintptr_t>(OFFSETOF_MEMBER(RuntimeEntryPoints, x))) + +namespace art { + +class Method; +class Object; +class Thread; + +struct PACKED RuntimeEntryPoints { + //---------------------------------------------------------------------------- + // Thread + //---------------------------------------------------------------------------- + void (*TestSuspend)(Thread* thread); + + //---------------------------------------------------------------------------- + // Exception + //---------------------------------------------------------------------------- + int32_t (*FindCatchBlock)(Method* current_method, uint32_t ti_offset); + void (*ThrowIndexOutOfBounds)(int32_t length, int32_t index); + void (*ThrowNullPointerException)(unsigned dex_pc); + + //---------------------------------------------------------------------------- + // Alloc + //---------------------------------------------------------------------------- + Object* (*AllocArray)(uint32_t type_idx, Method* referrer, + uint32_t length, Thread* thread); + + Object* (*AllocArrayWithAccessCheck)(uint32_t type_idx, Method* referrer, + uint32_t length, Thread* thread); + + Object* (*CheckAndAllocArray)(uint32_t type_idx, Method* referrer, + uint32_t length, Thread* thread); + + Object* (*CheckAndAllocArrayWithAccessCheck)(uint32_t type_idx, + Method* referrer, + uint32_t length, + Thread* thread); + + //---------------------------------------------------------------------------- + // DexCache + //---------------------------------------------------------------------------- + Object* (*ResolveString)(Method* referrer, uint32_t string_idx); + + //---------------------------------------------------------------------------- + // Field + //---------------------------------------------------------------------------- + Object* (*GetObjectStatic)(uint32_t field_idx, Method* referrer); + + //---------------------------------------------------------------------------- + // Cast + //---------------------------------------------------------------------------- + void (*CheckPutArrayElement)(const Object* element, const Object* array); + + //---------------------------------------------------------------------------- + // JNI + //---------------------------------------------------------------------------- +}; + +// Initialize an entry point data structure. +void InitRuntimeEntryPoints(RuntimeEntryPoints* entry_points); + +} // namespace art + +#endif // ART_SRC_GREENLAND_RUNTIME_ENTRY_POINTS_H_ diff --git a/src/greenland/target_codegen_machine.cc b/src/greenland/target_codegen_machine.cc index 87a215e..3c65a68 100644 --- a/src/greenland/target_codegen_machine.cc +++ b/src/greenland/target_codegen_machine.cc @@ -16,12 +16,16 @@ #include "target_codegen_machine.h" -#include "greenland.h" +#include "lir_function.h" +#include "lir_pass_manager.h" #include "target_lir_emitter.h" +#include "target_lir_opcodes.h" #include "target_registry.h" #include "compiled_method.h" #include "compiler.h" +#include "oat_compilation_unit.h" +#include "utils.h" #include <UniquePtr.h> @@ -39,23 +43,24 @@ TargetCodeGenMachine* TargetCodeGenMachine::Create(InstructionSet insn_set) { return (*ctor)(); } -CompiledMethod* TargetCodeGenMachine::Run(const Greenland& parent, - const llvm::Function& func, - const OatCompilationUnit& cunit, - DexLang::Context& dex_lang_ctx) { -#if 0 - UniquePtr<TargetLIREmitter> emitter(CreateLIREmitter(func, cunit, - dex_lang_ctx)); - LIRFunction* lir_func = emitter->Emit(); - if (lir_func == NULL) { +CompiledMethod* TargetCodeGenMachine::Run(const Compiler& compiler, + const GBCFunction& gbc_func) { + LIRPassManager lir_pm; + + lir_pm.Add(CreateLIREmitter()); + + LIRFunction lir_func(*this, gbc_func); + + if (!lir_pm.Run(lir_func)) { return NULL; } -#endif + + lir_func.Dump(); // 0x90 is the NOP in x86 std::vector<uint8_t> code(10, 0x90); - return new CompiledMethod(parent.GetCompiler().GetInstructionSet(), code, + return new CompiledMethod(compiler.GetInstructionSet(), code, /* frame_size_in_bytes */0, /* core_spill_mask */0, /* fp_spill_mask */0); diff --git a/src/greenland/target_codegen_machine.h b/src/greenland/target_codegen_machine.h index a0962fe..8cae791 100644 --- a/src/greenland/target_codegen_machine.h +++ b/src/greenland/target_codegen_machine.h @@ -17,26 +17,27 @@ #ifndef ART_SRC_GREENLAND_TARGET_CODEGEN_MACHINE_H_ #define ART_SRC_GREENLAND_TARGET_CODEGEN_MACHINE_H_ -#include "dex_lang.h" - #include "instruction_set.h" +#include <string> + namespace art { class CompiledMethod; - class OatCompilationUnit; -} - -namespace llvm { - class Function; + class Compiler; } namespace art { namespace greenland { -class Greenland; -class TargetLIREmitter; +class GBCFunction; +class LIR; class RegisterAllocator; class TargetAssembler; +class TargetDataLayout; +class TargetLIRBuilder; +class TargetLIREmitter; +class TargetLIRInfo; +class TargetRegisterInfo; class TargetCodeGenMachine { protected: @@ -45,9 +46,17 @@ class TargetCodeGenMachine { public: virtual ~TargetCodeGenMachine() { } - virtual TargetLIREmitter* CreateLIREmitter(const llvm::Function& func, - const OatCompilationUnit& cunit, - DexLang::Context& dex_lang_ctx) =0; + virtual TargetLIREmitter* CreateLIREmitter() = 0; + + virtual const TargetDataLayout* GetDataLayout() const = 0; + + virtual const TargetLIRInfo* GetLIRInfo() const = 0; + + virtual const TargetRegisterInfo* GetRegisterInfo() const = 0; + + virtual const char* GetConditionCodeName(unsigned cond) const = 0; + + virtual TargetLIRBuilder* CreateLIRBuilder() = 0; virtual RegisterAllocator* GetRegisterAllocator() = 0; @@ -56,10 +65,7 @@ class TargetCodeGenMachine { static TargetCodeGenMachine* Create(InstructionSet insn_set); public: - CompiledMethod* Run(const Greenland& parent, - const llvm::Function& func, - const OatCompilationUnit& cunit, - DexLang::Context& dex_lang_ctx); + CompiledMethod* Run(const Compiler& compiler, const GBCFunction& gbc_func); }; } // namespace greenland diff --git a/src/greenland/target_data_layout.h b/src/greenland/target_data_layout.h new file mode 100644 index 0000000..7b634cf --- /dev/null +++ b/src/greenland/target_data_layout.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_SRC_GREENLAND_TARGET_DATA_LAYOUT_H_ +#define ART_SRC_GREENLAND_TARGET_DATA_LAYOUT_H_ + +#include "lir.h" + +#include "logging.h" + +namespace art { +namespace greenland { + +class TargetDataLayout { + private: + // Size of pointer in bytes + unsigned pointer_size_; + + // Stack alignment in bytes + unsigned stack_alignment_; + + public: + TargetDataLayout(unsigned pointer_size, unsigned stack_alignment) + : pointer_size_(pointer_size), stack_alignment_(stack_alignment) { } + + unsigned GetPointerSize() const { + return pointer_size_; + } + unsigned GetPointerSizeInBits() const { + return (pointer_size_ << 3); + } + + unsigned GetStackAlignment() const { + return stack_alignment_; + } + + unsigned GetOpTypeSize(LIR::OperationType op_type) const { + switch (op_type) { + case LIR::kUInt8TypeOp: return 1; break; + case LIR::kSInt8TypeOp: return 1; break; + case LIR::kUInt16TypeOp: return 2; break; + case LIR::kSInt16TypeOp: return 2; break; + case LIR::kInt32TypeOp: return 4; break; + case LIR::kInt64TypeOp: return 8; break; + case LIR::kFloatTypeOp: return 4; break; + case LIR::kDoubleTypeOp: return 8; break; + case LIR::kPointerTypeOp: return pointer_size_; break; + case LIR::kUnknownTypeOp: + default: { + LOG(FATAL) << "Unknown operation type: " << op_type; + return 0; + } + } + // unreachable + } +}; + +} // namespace greenland +} // namespace art + +#endif // ART_SRC_GREENLAND_TARGET_DATA_LAYOUT_H_ diff --git a/src/greenland/target_lir_emitter.cc b/src/greenland/target_lir_emitter.cc deleted file mode 100644 index babb114..0000000 --- a/src/greenland/target_lir_emitter.cc +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "target_lir_emitter.h" - -#include "target_lir_info.h" -#include "target_lir_opcodes.h" - -#include "intrinsic_helper.h" -#include "lir_function.h" - -#include <llvm/Function.h> - -namespace art { -namespace greenland { - -TargetLIREmitter::TargetLIREmitter(const llvm::Function& func, - const OatCompilationUnit& cunit, - DexLang::Context& dex_lang_ctx, - TargetLIRInfo& target_lir_info) - : func_(func), cunit_(cunit), dex_lang_ctx_(dex_lang_ctx.IncRef()), - info_(target_lir_info), lir_func_() { - return; -} - -TargetLIREmitter::~TargetLIREmitter() { - dex_lang_ctx_.DecRef(); - return; -} - -bool TargetLIREmitter::visitBasicBlock(const llvm::BasicBlock& bb) { - // Place the corresponding block label to the output - llvm::DenseMap<const llvm::BasicBlock*, LIR*>::const_iterator label_iter = - block_labels_.find(&bb); - - DCHECK(label_iter != block_labels_.end()); - lir_func_.push_back(label_iter->second); - - // Now, iterate over and process all instructions within the basic block - for (llvm::BasicBlock::const_iterator inst_iter = bb.begin(), - inst_end = bb.end(); inst_iter != inst_end; inst_iter++) { - const llvm::Instruction& inst = *inst_iter; - switch (inst.getOpcode()) { -#define VISIT(OPCODE, CLASS) \ - case llvm::Instruction::OPCODE: { \ - if (!visit ## CLASS(static_cast<const llvm::CLASS&>(inst))) { \ - return false; \ - } \ - break; \ - } - - VISIT(Ret, ReturnInst); - VISIT(Br, BranchInst); - VISIT(ICmp, ICmpInst); - VISIT(IntToPtr, IntToPtrInst); - VISIT(Call, CallInst); - -#undef VISIT - default : { - LOG(INFO) << "Unhandled instruction hit!"; - inst.dump(); - return false; - } - } - } - - return true; -} - -bool TargetLIREmitter::visitReturnInst(const llvm::ReturnInst& inst) { - inst.dump(); - return true; -} - -bool TargetLIREmitter::visitBranchInst(const llvm::BranchInst& inst) { - inst.dump(); - return true; -} - -bool TargetLIREmitter::visitICmpInst(const llvm::ICmpInst& inst) { - inst.dump(); - return true; -} - -bool TargetLIREmitter::visitIntToPtrInst(const llvm::IntToPtrInst& inst) { - inst.dump(); - return true; -} - -bool TargetLIREmitter::visitCallInst(const llvm::CallInst& inst) { - // The callee must be a DexLang intrinsic - return visitDexLangIntrinsics(inst); -} - -bool TargetLIREmitter::visitDexLangIntrinsics(const llvm::CallInst& inst) { - const llvm::Function* callee = inst.getCalledFunction(); - IntrinsicHelper::IntrinsicId intr_id = - dex_lang_ctx_.GetIntrinsicHelper().GetIntrinsicId(callee); - - if (intr_id == IntrinsicHelper::UnknownId) { - LOG(INFO) << "Unexpected call instruction to '" - << callee->getName().str() << "'"; - return false; - } - - //const IntrinsicHelper::IntrinsicInfo& intr_info = - // IntrinsicHelper::GetInfo(intr_id); - - - return true; -} - -LIRFunction* TargetLIREmitter::Emit() { - if (EmitBasicBlockLabels() && - EmitEntrySequence() && - EmitInstructions() && - EmitExitSequence()) { - return &lir_func_; - } - - return NULL; -} - -bool TargetLIREmitter::EmitBasicBlockLabels() { - for (llvm::Function::const_iterator bb_iter = func_.begin(), - bb_end = func_.end(); bb_iter != bb_end; bb_iter++) { - LIR* lir = lir_func_.CreateLIR(info_.GetLIRDesc(opcode::kBlockLabel)); - CHECK(block_labels_.insert(std::make_pair(bb_iter, lir)).second); - } - return true; -} - -bool TargetLIREmitter::EmitEntrySequence() { - // Flush all function arguments to the virtual registers - return true; -} - -bool TargetLIREmitter::EmitInstructions() { - // Iterator over all basic blocks - for (llvm::Function::const_iterator bb_iter = func_.begin(), - bb_end = func_.end(); bb_iter != bb_end; bb_iter++) { - if (!visitBasicBlock(*bb_iter)) { - return false; - } - } - return true; -} - -bool TargetLIREmitter::EmitExitSequence() { - return true; -} - -} // namespace greenland -} // namespace art diff --git a/src/greenland/target_lir_emitter.h b/src/greenland/target_lir_emitter.h deleted file mode 100644 index 8e39e4c..0000000 --- a/src/greenland/target_lir_emitter.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_SRC_GREENLAND_TARGET_LIR_EMITTER_H_ -#define ART_SRC_GREENLAND_TARGET_LIR_EMITTER_H_ - -#include "dex_lang.h" - -#include "lir_function.h" - -#include <llvm/ADT/DenseMap.h> - -namespace art { - class OatCompilationUnit; -} - -namespace llvm { - class BasicBlock; - class BranchInst; - class CallInst; - class Function; - class ICmpInst; - class Instruction; - class IntToPtrInst; - class ReturnInst; -} - -namespace art { -namespace greenland { - -class LIRFunction; -class TargetLIRInfo; - -class TargetLIREmitter { - private: - const llvm::Function& func_; - const OatCompilationUnit& cunit_; - DexLang::Context& dex_lang_ctx_; - TargetLIRInfo& info_; - - private: - llvm::DenseMap<const llvm::BasicBlock*, LIR*> block_labels_; - - protected: - LIRFunction lir_func_; - - TargetLIREmitter(const llvm::Function& func, - const OatCompilationUnit& cunit, - DexLang::Context& dex_lang_ctx, - TargetLIRInfo& target_lir_info); - - private: - bool visitBasicBlock(const llvm::BasicBlock& bb); - - bool visitReturnInst(const llvm::ReturnInst& inst); - bool visitBranchInst(const llvm::BranchInst& inst); - //bool visitSwitchInst(SwitchInst &I) { DELEGATE(TerminatorInst);} - //bool visitIndirectBrInst(IndirectBrInst &I) { DELEGATE(TerminatorInst);} - //bool visitInvokeInst(InvokeInst &I) { DELEGATE(TerminatorInst);} - //bool visitResumeInst(ResumeInst &I) { DELEGATE(TerminatorInst);} - //bool visitUnreachableInst(UnreachableInst &I) { DELEGATE(TerminatorInst);} - bool visitICmpInst(const llvm::ICmpInst& inst); - //bool visitFCmpInst(FCmpInst &I) { DELEGATE(CmpInst);} - //bool visitAllocaInst(AllocaInst &I) { DELEGATE(UnaryInstruction);} - //bool visitLoadInst(LoadInst &I) { DELEGATE(UnaryInstruction);} - //bool visitStoreInst(StoreInst &I) { DELEGATE(Instruction);} - //bool visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) { DELEGATE(Instruction);} - //bool visitAtomicRMWInst(AtomicRMWInst &I) { DELEGATE(Instruction);} - //bool visitFenceInst(FenceInst &I) { DELEGATE(Instruction);} - //bool visitGetElementPtrInst(GetElementPtrInst &I){ DELEGATE(Instruction);} - //bool visitPHINode(PHINode &I) { DELEGATE(Instruction);} - //bool visitTruncInst(TruncInst &I) { DELEGATE(CastInst);} - //bool visitZExtInst(ZExtInst &I) { DELEGATE(CastInst);} - //bool visitSExtInst(SExtInst &I) { DELEGATE(CastInst);} - //bool visitFPTruncInst(FPTruncInst &I) { DELEGATE(CastInst);} - //bool visitFPExtInst(FPExtInst &I) { DELEGATE(CastInst);} - //bool visitFPToUIInst(FPToUIInst &I) { DELEGATE(CastInst);} - //bool visitFPToSIInst(FPToSIInst &I) { DELEGATE(CastInst);} - //bool visitUIToFPInst(UIToFPInst &I) { DELEGATE(CastInst);} - //bool visitSIToFPInst(SIToFPInst &I) { DELEGATE(CastInst);} - //bool visitPtrToIntInst(PtrToIntInst &I) { DELEGATE(CastInst);} - bool visitIntToPtrInst(const llvm::IntToPtrInst& inst); - //bool visitBitCastInst(BitCastInst &I) { DELEGATE(CastInst);} - //bool visitSelectInst(SelectInst &I) { DELEGATE(Instruction);} - bool visitCallInst(const llvm::CallInst& inst); - //bool visitVAArgInst(VAArgInst &I) { DELEGATE(UnaryInstruction);} - //bool visitExtractElementInst(ExtractElementInst &I) { DELEGATE(Instruction);} - //bool visitInsertElementInst(InsertElementInst &I) { DELEGATE(Instruction);} - //bool visitShuffleVectorInst(ShuffleVectorInst &I) { DELEGATE(Instruction);} - //bool visitExtractValueInst(ExtractValueInst &I){ DELEGATE(UnaryInstruction);} - //bool visitInsertValueInst(InsertValueInst &I) { DELEGATE(Instruction); } - //bool visitLandingPadInst(LandingPadInst &I) { DELEGATE(Instruction); } - - bool visitDexLangIntrinsics(const llvm::CallInst& inst); - - public: - virtual ~TargetLIREmitter(); - - LIRFunction* Emit(); - - private: - bool EmitBasicBlockLabels(); - bool EmitEntrySequence(); - bool EmitInstructions(); - bool EmitExitSequence(); -}; - -} // namespace greenland -} // namespace art - -#endif // ART_SRC_GREENLAND_TARGET_LIR_EMITTER_H_ diff --git a/src/greenland/target_lir_info.h b/src/greenland/target_lir_info.h deleted file mode 100644 index 1ed86fa..0000000 --- a/src/greenland/target_lir_info.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_SRC_GREENLAND_TARGET_LIR_INFO_H_ -#define ART_SRC_GREENLAND_TARGET_LIR_INFO_H_ - -#include "lir_desc.h" - -#include "logging.h" - -namespace art { -namespace greenland { - -class TargetLIRInfo { - private: - // An array of target's LIR instruction description - const LIRDesc* desc_; - - unsigned num_desc_; - - public: - TargetLIRInfo(const LIRDesc* desc, unsigned num_desc) - : desc_(desc), num_desc_(num_desc) { - } - - virtual ~TargetLIRInfo() { } - - const LIRDesc& GetLIRDesc(unsigned opcode) { - DCHECK(opcode < num_desc_) << "Invalid opcode: " << opcode; - return desc_[opcode]; - } -}; - -} // namespace greenland -} // namespace art - -#endif // ART_SRC_GREENLAND_TARGET_LIR_INFO_H_ diff --git a/src/greenland/target_register_info.h b/src/greenland/target_register_info.h new file mode 100644 index 0000000..41d69e1 --- /dev/null +++ b/src/greenland/target_register_info.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_SRC_GREENLAND_TARGET_REGISTER_INFO_H_ +#define ART_SRC_GREENLAND_TARGET_REGISTER_INFO_H_ + +#include "lir_function.h" +#include "lir_reg.h" + +#include "target_lir_builder.h" +#include "target_lir_info.h" + +#include <string> + +namespace art { +namespace greenland { + +class TargetRegisterInfo { + protected: + const TargetLIRInfo& lir_info_; + TargetRegisterInfo(const TargetLIRInfo& info) :lir_info_(info) { } + + public: + virtual const char* GetPhyRegName(unsigned reg) const = 0; + + std::string GetRegName(unsigned reg) const { + if (LIRReg::IsVirtualReg(reg)) { + return LIRReg::GetVirtualRegName(reg); + } else { + return GetPhyRegName(reg); + } + } + + virtual LIR* + CreateLoadStack(LIRFunction& lir_func, + unsigned reg, + int frame_idx) const = 0; + + virtual LIR* + CreateStoreStack(LIRFunction& lir_func, + unsigned reg, + int frame_idx) const = 0; + + virtual LIR* + CreateMoveReg(LIRFunction& lir_func, + unsigned dst, + unsigned src) const = 0; + + virtual bool + IsLoadIncomingArgs(const LIR* lir) const = 0; + + virtual LIR* + CreateCopy(LIRFunction& lir_func, + unsigned dst, + const LIROperand& src) const = 0; + + virtual std::list<unsigned> GetAllocatableList() const = 0; + virtual unsigned GetTempRegsiter(unsigned idx) const = 0; + + virtual ~TargetRegisterInfo() { } +}; + +} // namespace greenland +} // namespace art + +#endif // ART_SRC_GREENLAND_TARGET_REGISTER_INFO_H_ diff --git a/src/greenland/target_registry.h b/src/greenland/target_registry.h index 1f93665..0f490e0 100644 --- a/src/greenland/target_registry.h +++ b/src/greenland/target_registry.h @@ -40,7 +40,7 @@ class TargetRegistry { uint32_t shorty_len); static void RegisterTargetCodeGenMachine(InstructionSet insn_set, - TargetCodeGenMachineCtorTy ctor); + TargetCodeGenMachineCtorTy ctor); static TargetCodeGenMachineCtorTy GetTargetCodeGenMachineCtor(InstructionSet insn_set); static void RegisterInvokeStubCompiler(InstructionSet insn_set, diff --git a/src/greenland/tools/target_lir_builder_generator.cc b/src/greenland/tools/target_lir_builder_generator.cc new file mode 100644 index 0000000..2a48136 --- /dev/null +++ b/src/greenland/tools/target_lir_builder_generator.cc @@ -0,0 +1,574 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <cassert> +#include <cctype> +#include <cstring> +#include <iostream> +#include <string> + +// Should be synced with the one in lir_desc.h +#define MAX_LIR_OPERANDS 6 + +//---------------------------------------------------------------------------- +// Operand Info +//---------------------------------------------------------------------------- +class LIROperand { + public: + enum Type { + UnknownType, + RegisterType, + ImmediateType, + LabelType, + FrameIndexType, + }; +}; + +// Copy from lir_desc.h +class LIRDescFlag { + public: + enum Flag { + kNone, + kPseudo, + kVariadic, + + kIsLoad, + kIsStore, + kIsBranch, + + kDefReg0, + kDefReg1, + + kUseReg0, + kUseReg1, + kUseReg2, + kUseReg3, + kUseReg4, + kUseReg5, + + kSetCCodes, + kUseCCodes, + + kNeedRelax, + }; +}; + +class LIROperandInfo { + public: + class TypeStrings { + public: + // Take RegisterType as example: + // type_string_ is "unsigned" + // var_string_ is "reg" + // set_method_ is "SetReg" + const char* type_string_; + const char* var_string_; + const char* set_method_; + }; + + LIROperand::Type GetOperandType(unsigned i) const { + assert((i < num_operands_) && "Invalid operand index!"); + return info_[i].type_; + } + + const TypeStrings& GetOperandTypeStrings(unsigned i) const { + return OperandTypeStrings[GetOperandType(i)]; + } + + private: + static const TypeStrings OperandTypeStrings[]; + + public: + const char* name_; + unsigned num_operands_; + struct { + enum LIROperand::Type type_; + } info_[MAX_LIR_OPERANDS]; +}; + +const LIROperandInfo::TypeStrings LIROperandInfo::OperandTypeStrings[] = { + /* UnknownType */ { "void", "", "", }, + /* RegisterType */ { "unsigned", "reg", "SetReg" }, + /* ImmediateType */ { "int32_t" , "imm_val", "SetImm" }, + /* LabelType */ { "LIRBasicBlock*", "target", "SetLabelTarget" }, + /* FrameIndexType */ { "int", "frame_index", "SetFrameIndex" } +}; + +#define DEF_LIR_OPERAND_INFO(INFO_ID, NUM_OPS, INFO_DEF) \ +static const LIROperandInfo OpInfo ## INFO_ID = \ + { #INFO_ID, NUM_OPS, INFO_DEF }; +#include "greenland/target_lir.def" +#include "greenland/clear_target_lir.def" + +static const LIROperandInfo* const OpInfos[] = { +#define DEF_LIR_OPERAND_INFO(INFO_ID, NUM_OPS, INFO_DEF) \ + &OpInfo ## INFO_ID, +#include "greenland/target_lir.def" +#include "greenland/clear_target_lir.def" +}; + +static const unsigned NumObInfos = sizeof(OpInfos) / sizeof(OpInfos[0]); + +//---------------------------------------------------------------------------- +// Data structure of LIRDesc to load {target}_lir.def +//---------------------------------------------------------------------------- + +class LIRDesc { + public: + const char* opcode_name_; + const char* name_; + const char* format_; + unsigned flags; + const LIROperandInfo& operand_info_; + + bool IsPseudo() const { + return (flags & (1 << LIRDescFlag::kPseudo)); + } +}; + +//---------------------------------------------------------------------------- +// Target-independent LIR Enumeration +//---------------------------------------------------------------------------- +// This is here to get the number of target-independent LIRs +// (i.e., kNumTargetIndependentLIR) +enum { +#define DEF_LIR_DESC(OPCODE, ...) OPCODE, +#include "greenland/target_lir.def" +#include "greenland/clear_target_lir.def" + + kNumTargetIndependentLIR +}; + +//---------------------------------------------------------------------------- +// ARM +//---------------------------------------------------------------------------- +static const LIRDesc ARMLIR[] = { +#define DEF_LIR_DESC(OPCODE, KIND, FLAGS, NAME, FORMAT, OPS_INFO) \ + { #OPCODE, NAME, FORMAT, FLAGS, OpInfo ## OPS_INFO }, +#include "greenland/arm/arm_lir.def" +}; + +//---------------------------------------------------------------------------- +// Mips +//---------------------------------------------------------------------------- +static const LIRDesc MipsLIR[] = { +#define DEF_LIR_DESC(OPCODE, KIND, FLAGS, NAME, FORMAT, OPS_INFO) \ + { #OPCODE, NAME, FORMAT, FLAGS, OpInfo ## OPS_INFO }, +#include "greenland/mips/mips_lir.def" +}; + +//---------------------------------------------------------------------------- +// X86 +//---------------------------------------------------------------------------- +static const LIRDesc X86LIR[] = { +#define DEF_LIR_DESC(OPCODE, KIND, FLAGS, NAME, FORMAT, OPS_INFO) \ + { #OPCODE, NAME, FORMAT, FLAGS, OpInfo ## OPS_INFO }, +#include "greenland/x86/x86_lir.def" +}; + +class Context { + private: + std::ostream& out_; + unsigned indent_; + + public: + Context(std::ostream& out) : out_(out), indent_(0) { } + + void IncIndent() { + indent_ += 2; + return; + } + + void DecIndent() { + indent_ -= 2; + } + + std::ostream& Indent() { + for (unsigned i = 0; i < indent_; i += 2) { + out_.write(" ", 2); + } + return out_; + } + + std::ostream& Newline() { + return out_ << std::endl; + } + + std::ostream& Out() { + return out_; + } + + const LIRDesc* target_lirs_; + unsigned num_target_lirs_; + + std::string lowercase_target_string_; + std::string uppercase_target_string_; + std::string class_name_; +}; + +class GenPrototype { + const LIROperandInfo& op_info_; + const char* preface_; + public: + GenPrototype(const LIROperandInfo& op_info, const char* preface = NULL) + : op_info_(op_info), preface_(preface) { } + + friend std::ostream& operator<<(std::ostream& out, const GenPrototype& obj); +}; + +std::ostream& operator<<(std::ostream& out, const GenPrototype& obj) { + out << "("; + + unsigned num_ops = obj.op_info_.num_operands_; + if (obj.preface_ != NULL) { + out << obj.preface_; + if (num_ops > 0) { + out << ", "; + } + } + + for (unsigned i = 0; i < num_ops; i++) { + const LIROperandInfo::TypeStrings& type_strings = + obj.op_info_.GetOperandTypeStrings(i); + + out << type_strings.type_string_ << " " << type_strings.var_string_ << i; + + if (i != (num_ops - 1)) { + // Append "," if not the last one + out << ", "; + } + } + + out << ")"; + return out; +} + +//---------------------------------------------------------------------------- + +// Forward Declarations +static void GenBeginNamespace(Context& C); +static void GenCreateTargetLIR(Context& C, const LIRDesc& lir, bool proto_only); +static void GenCallSetOperands(Context& C, const LIROperandInfo& operand_info); +static void GenEndNamespace(Context& C); + +static void GenLicenseNote(Context& C) { + C.Indent() << "/*" << std::endl; + C.Indent() << " * Copyright (C) 2012 The Android Open Source Project" << std::endl; + C.Indent() << " *" << std::endl; + C.Indent() << " * Licensed under the Apache License, Version 2.0 (the \"License\"" << std::endl; + C.Indent() << " * you may not use this file except in compliance with the License." << std::endl; + C.Indent() << " * You may obtain a copy of the License at" << std::endl; + C.Indent() << " *" << std::endl; + C.Indent() << " * http://www.apache.org/licenses/LICENSE-2.0" << std::endl; + C.Indent() << " *" << std::endl; + C.Indent() << " * Unless required by applicable law or agreed to in writing, software" << std::endl; + C.Indent() << " * distributed under the License is distributed on an \"AS IS\" BASIS," << std::endl; + C.Indent() << " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied." << std::endl; + C.Indent() << " * See the License for the specific language governing permissions and" << std::endl; + C.Indent() << " * limitations under the License." << std::endl; + C.Indent() << " */" << std::endl; + C.Newline(); + return; +} + +//---------------------------------------------------------------------------- + +static void GenTargetLIRBuilderHeader(Context& C) { + C.Indent() << "#ifdef GET_" << C.uppercase_target_string_ << "_LIR_BUILDER_HEADER"; + C.Newline(); + + //---------------------------------------------------------------------------- + // Include Files + //---------------------------------------------------------------------------- + C.Indent() << "#include \"greenland/target_lir_builder.h\"" << std::endl;; + C.Indent() << "#include \"greenland/target_lir_info.h\"" << std::endl; + C.Newline(); + + GenBeginNamespace(C); + + //---------------------------------------------------------------------------- + // Forward Declarations + //---------------------------------------------------------------------------- + C.Indent() << "class TargetLIRInfo;" << std::endl; + C.Newline(); + + C.Indent() << "class " << C.class_name_ << " : public TargetLIRBuilder {" + << std::endl; + + //---------------------------------------------------------------------------- + // Members + //---------------------------------------------------------------------------- + C.Indent() << " private:" << std::endl; + C.IncIndent(); + C.Indent() << "const TargetLIRInfo& info_;" << std::endl; + C.DecIndent(); + C.Newline(); + + //---------------------------------------------------------------------------- + // APIs + //---------------------------------------------------------------------------- + C.Indent() << " public:" << std::endl; + + C.IncIndent(); + + //---------------------------------------------------------------------------- + // Constructor + //---------------------------------------------------------------------------- + C.Indent() << C.class_name_ << "(const TargetLIRInfo& info) " + ": TargetLIRBuilder(), info_(info) { }" + << std::endl; + C.Newline(); + + //---------------------------------------------------------------------------- + // LIR* Create(unsigned opcode) + //---------------------------------------------------------------------------- + C.Indent() << "LIR* Create(unsigned opcode) {" << std::endl; + C.IncIndent(); + + C.Indent() << "return bb_->GetParent().CreateLIR(*bb_, info_.GetLIRDesc(opcode));" << std::endl; + + C.DecIndent(); + C.Indent() << "}" << std::endl; + C.Newline(); + + //---------------------------------------------------------------------------- + // LIR* Create(LIRDesc& desc) + //---------------------------------------------------------------------------- + C.Indent() << "LIR* Create(const LIRDesc& desc) {" << std::endl; + C.IncIndent(); + + C.Indent() << "return bb_->GetParent().CreateLIR(*bb_, desc);" << std::endl; + + C.DecIndent(); + C.Indent() << "}" << std::endl; + C.Newline(); + + //---------------------------------------------------------------------------- + // LIR* Create_*([operand...]) + //---------------------------------------------------------------------------- + for (unsigned i = 0; i < C.num_target_lirs_; i++) { + const LIRDesc& lir = C.target_lirs_[i]; + if (!lir.IsPseudo() || (i > kNumTargetIndependentLIR)) { + GenCreateTargetLIR(C, lir, /* proto_only */true); + } + } + + C.DecIndent(); + + C.Indent() << "};" << std::endl; + C.Newline(); + + GenEndNamespace(C); + + C.Indent() << "#undef GET_" << C.uppercase_target_string_ << "_LIR_BUILDER_HEADER" << std::endl; + C.Indent() << "#endif // GET_" << C.uppercase_target_string_ << "_LIR_BUILDER_HEADER" << std::endl; + return; +} + +static void GenTargetLIRBuilderImpl(Context& C) { + C.Indent() << "#ifdef GET_" << C.uppercase_target_string_ << "_LIR_BUILDER_IMPL"; + C.Newline(); + + //---------------------------------------------------------------------------- + // Include Files + //---------------------------------------------------------------------------- + C.Indent() << "#include \"greenland/lir_desc.h\"" << std::endl; + C.Indent() << "#include \"greenland/lir_function.h\"" << std::endl; + C.Indent() << "#include \"greenland/" << C.lowercase_target_string_ + << "/" << C.lowercase_target_string_ << "_lir_opcodes.h\"" + << std::endl; + C.Newline(); + + GenBeginNamespace(C); + + for (unsigned i = 0; i < C.num_target_lirs_; i++) { + const LIRDesc& lir = C.target_lirs_[i]; + if (!lir.IsPseudo() || (i > kNumTargetIndependentLIR)) { + GenCreateTargetLIR(C, lir, /* proto_only */false); + } + } + + C.Newline(); + + GenEndNamespace(C); + + C.Indent() << "#undef GET_" << C.uppercase_target_string_ << "_LIR_BUILDER_IMPL" << std::endl; + C.Indent() << "#endif // GET_" << C.uppercase_target_string_ << "_LIR_BUILDER_IMPL" << std::endl; + C.Newline(); + return; +} + +//---------------------------------------------------------------------------- + +static void GenBeginNamespace(Context& C) { + C.Indent() << "namespace art {" << std::endl; + C.Indent() << "namespace greenland {" << std::endl; + C.Newline(); + return; +} + +static void GenCreateTargetLIR(Context& C, const LIRDesc& lir, bool proto_only){ + C.Indent() << "// " << lir.name_ << " " << lir.format_ << std::endl; + + if (proto_only) { + C.Indent() << "LIR* Create_" << &lir.opcode_name_[1] /* hack: skip 'k' */ + << GenPrototype(lir.operand_info_) << ";" << std::endl; + return; + } else { + C.Indent() << "LIR* " << C.class_name_ << "::Create_" + << &lir.opcode_name_[1] /* hack: skip 'k' */ + << GenPrototype(lir.operand_info_) << " {" << std::endl; + } + + C.IncIndent(); + C.Indent() << "LIR* lir = Create(" + << C.lowercase_target_string_ << "::" << lir.opcode_name_<< ");" + << std::endl; + GenCallSetOperands(C, lir.operand_info_); + C.Indent() << "return lir;" << std::endl; + C.DecIndent(); + + C.Indent() << "}" << std::endl; + C.Newline(); + return; +} + +static void +GenCallSetOperands(Context& C, const LIROperandInfo& operand_info) { + if (operand_info.num_operands_ > 0) { + C.Indent() << "Set" << operand_info.name_ << "Operands(*lir, "; + + for (unsigned i = 0; i < operand_info.num_operands_; i++) { + const LIROperandInfo::TypeStrings& type_strings = + operand_info.GetOperandTypeStrings(i); + + C.Out() << type_strings.var_string_ << i; + + if (i != (operand_info.num_operands_ - 1)) { + // Append "," if not the last one + C.Out() << ", "; + } + } + + C.Out() << ");" << std::endl; + } + return; +} + +static void GenEndNamespace(Context& C) { + C.Newline(); + C.Indent() << "} // namespace greenland" << std::endl; + C.Indent() << "} // namespace art" << std::endl; + C.Newline(); + return; +} + +//---------------------------------------------------------------------------- +// Special functionality to generate Set*Operands in TargetLIRBuilder +//---------------------------------------------------------------------------- +static void GenSetOperandsImpl(Context& C, const LIROperandInfo& operand_info); + +static void GenSetOperands(Context& C) { + for (unsigned i = 0; i < NumObInfos; i++) { + const LIROperandInfo& op_info = *OpInfos[i]; + C.Indent() << "static inline void Set" << op_info.name_ + << "Operands" << GenPrototype(op_info, /* preface */"LIR& lir") + << " {" << std::endl; + C.IncIndent(); + GenSetOperandsImpl(C, op_info); + C.DecIndent(); + C.Indent() << "}" << std::endl; + C.Newline(); + } + + return; +} + +static void GenSetOperandsImpl(Context& C, const LIROperandInfo& operand_info) { + if (operand_info.num_operands_ <= 0) { + return; + } + + C.Indent() << "lir"; + for (unsigned i = 0; i < operand_info.num_operands_; i++) { + const LIROperandInfo::TypeStrings& type_strings = + operand_info.GetOperandTypeStrings(i); + + if (i != 0) { + C.Indent() << " "; + } + + C.Out() << "." << type_strings.set_method_ << "(" << i << ", " + << type_strings.var_string_ << i + << ")"; + if (i == (operand_info.num_operands_ - 1)) { + // Append ";" if not the last one + C.Out() << ";"; + } + C.Out() << std::endl; + } + + C.Indent() << "return;" << std::endl; + + return; +} + +int main(int argc, char** argv) { + if (argc < 2) { + std::cerr << "usage: " << argv[0] << " [target]" << std::endl; + return 1; + } + + Context C(std::cout); + + C.lowercase_target_string_ = argv[1]; + for (size_t i = 0, e = C.lowercase_target_string_.length(); i != e; i++) { + C.lowercase_target_string_[i] = ::tolower(C.lowercase_target_string_[i]); + } + + // Special function to generate TargetLIRBuilder::Set*Operands(...). + if (C.lowercase_target_string_ == "gen_set_operands") { + GenSetOperands(C); + return 0; + } + + // Setup the context according to the target supplied + if (C.lowercase_target_string_ == "arm") { + C.target_lirs_ = ARMLIR; + C.num_target_lirs_ = sizeof(ARMLIR) / sizeof(ARMLIR[0]); + C.uppercase_target_string_ = "ARM"; + C.class_name_ = "ARMLIRBuilderBase"; + } else if (C.lowercase_target_string_ == "mips") { + C.target_lirs_ = MipsLIR; + C.num_target_lirs_ = sizeof(MipsLIR) / sizeof(MipsLIR[0]); + C.uppercase_target_string_ = "MIPS"; + C.class_name_ = "MipsLIRBuilderBase"; + } else if (C.lowercase_target_string_ == "x86") { + C.target_lirs_ = X86LIR; + C.num_target_lirs_ = sizeof(X86LIR) / sizeof(X86LIR[0]); + C.uppercase_target_string_ = "X86"; + C.class_name_ = "X86LIRBuilderBase"; + } else { + std::cerr << "unknown target `" << argv[1] << "'!" << std::endl; + return 1; + } + + GenLicenseNote(C); + GenTargetLIRBuilderHeader(C); + GenTargetLIRBuilderImpl(C); + + return 0; +} |