diff options
author | Logan Chien <loganchien@google.com> | 2012-02-17 18:50:32 +0800 |
---|---|---|
committer | Shih-wei Liao <sliao@google.com> | 2012-02-20 23:14:10 -0800 |
commit | 8dfcbea64ef8c9279329119e42a626771669044d (patch) | |
tree | 06245a171b2983b5234b7bd60bef585ddd7e163e | |
parent | dd110694e0edc27a588a68609c678751593f667f (diff) | |
download | art-8dfcbea64ef8c9279329119e42a626771669044d.zip art-8dfcbea64ef8c9279329119e42a626771669044d.tar.gz art-8dfcbea64ef8c9279329119e42a626771669044d.tar.bz2 |
Add shadow stack support to Dex compiler.
Change-Id: I8e188be3fb30c81e2a9e6e466264074ddf7b1624
-rw-r--r-- | src/compiler_llvm/ir_builder.cc | 24 | ||||
-rw-r--r-- | src/compiler_llvm/ir_builder.h | 4 | ||||
-rw-r--r-- | src/compiler_llvm/method_compiler.cc | 164 | ||||
-rw-r--r-- | src/compiler_llvm/method_compiler.h | 10 |
4 files changed, 190 insertions, 12 deletions
diff --git a/src/compiler_llvm/ir_builder.cc b/src/compiler_llvm/ir_builder.cc index 582af65..30ed6ec 100644 --- a/src/compiler_llvm/ir_builder.cc +++ b/src/compiler_llvm/ir_builder.cc @@ -16,6 +16,7 @@ #include "ir_builder.h" #include "runtime_support_func.h" +#include "stringprintf.h" #include <llvm/Module.h> @@ -39,6 +40,10 @@ IRBuilder::IRBuilder(llvm::LLVMContext& context, llvm::Module& module) llvm::Type* jenv_struct_type = llvm::StructType::create(context, "JEnv"); jenv_type_ = jenv_struct_type->getPointerTo(); + // Get Art shadow frame struct type from module + art_frame_type_ = module.getTypeByName("ArtFrame"); + CHECK_NE(art_frame_type_, static_cast<llvm::StructType*>(NULL)); + // Load the runtime support function declaration from module InitRuntimeSupportFuncDecl(); } @@ -179,5 +184,24 @@ llvm::Type* IRBuilder::getJTypeInArraySpace(JType jty) { } +llvm::StructType* IRBuilder::getShadowFrameTy(uint32_t sirt_size) { + std::string name(StringPrintf("ArtFrame%u", sirt_size)); + + // Try to find the existing struct type definition + if (llvm::Type* type = module_->getTypeByName(name)) { + CHECK(llvm::isa<llvm::StructType>(type)); + return static_cast<llvm::StructType*>(type); + } + + // Create new struct type definition + llvm::Type* elem_types[] = { + art_frame_type_, + llvm::ArrayType::get(jobject_type_, sirt_size), + }; + + return llvm::StructType::create(elem_types, name); +} + + } // namespace compiler_llvm } // namespace art diff --git a/src/compiler_llvm/ir_builder.h b/src/compiler_llvm/ir_builder.h index e88073c..0762a0d 100644 --- a/src/compiler_llvm/ir_builder.h +++ b/src/compiler_llvm/ir_builder.h @@ -174,6 +174,8 @@ class IRBuilder : public LLVMIRBuilder { return getJLongTy(); } + llvm::StructType* getShadowFrameTy(uint32_t sirt_size); + //-------------------------------------------------------------------------- // Constant Value Helper Function @@ -282,6 +284,8 @@ class IRBuilder : public LLVMIRBuilder { llvm::PointerType* jenv_type_; + llvm::StructType* art_frame_type_; + llvm::Function* runtime_support_func_decls_[runtime_support::MAX_ID]; }; diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc index caf67c6..572f8d6 100644 --- a/src/compiler_llvm/method_compiler.cc +++ b/src/compiler_llvm/method_compiler.cc @@ -60,11 +60,12 @@ MethodCompiler::MethodCompiler(InstructionSet insn_set, access_flags_(access_flags), module_(compiler_llvm_->GetModule()), context_(compiler_llvm_->GetLLVMContext()), irb_(*compiler_llvm_->GetIRBuilder()), func_(NULL), retval_reg_(NULL), - basic_block_reg_alloca_(NULL), + basic_block_reg_alloca_(NULL), basic_block_shadow_frame_alloca_(NULL), basic_block_reg_zero_init_(NULL), basic_block_reg_arg_init_(NULL), basic_blocks_(code_item->insns_size_in_code_units_), basic_block_landing_pads_(code_item->tries_size_, NULL), - basic_block_unwind_(NULL), basic_block_unreachable_(NULL) { + basic_block_unwind_(NULL), basic_block_unreachable_(NULL), + shadow_frame_(NULL) { } @@ -139,6 +140,9 @@ void MethodCompiler::EmitPrologue() { basic_block_reg_alloca_ = llvm::BasicBlock::Create(*context_, "prologue.alloca", func_); + basic_block_shadow_frame_alloca_ = + llvm::BasicBlock::Create(*context_, "prologue.shadowframe", func_); + basic_block_reg_zero_init_ = llvm::BasicBlock::Create(*context_, "prologue.zeroinit", func_); @@ -152,6 +156,9 @@ void MethodCompiler::EmitPrologue() { retval_reg_.reset(DalvikReg::CreateRetValReg(*this)); + // Create Shadow Frame + EmitPrologueAllocShadowFrame(); + // Store argument to dalvik register irb_.SetInsertPoint(basic_block_reg_arg_init_); EmitPrologueAssignArgRegister(); @@ -163,6 +170,9 @@ void MethodCompiler::EmitPrologue() { void MethodCompiler::EmitPrologueLastBranch() { irb_.SetInsertPoint(basic_block_reg_alloca_); + irb_.CreateBr(basic_block_shadow_frame_alloca_); + + irb_.SetInsertPoint(basic_block_shadow_frame_alloca_); irb_.CreateBr(basic_block_reg_zero_init_); irb_.SetInsertPoint(basic_block_reg_zero_init_); @@ -170,6 +180,53 @@ void MethodCompiler::EmitPrologueLastBranch() { } +void MethodCompiler::EmitPrologueAllocShadowFrame() { + irb_.SetInsertPoint(basic_block_shadow_frame_alloca_); + + // Allocate the shadow frame now! + uint32_t sirt_size = code_item_->registers_size_; + // TODO: registers_size_ is a bad approximation. Compute a + // tighter approximation at Dex verifier while performing data-flow + // analysis. + + llvm::StructType* shadow_frame_type = irb_.getShadowFrameTy(sirt_size); + shadow_frame_ = irb_.CreateAlloca(shadow_frame_type); + + // Zero-initialization of the shadow frame + llvm::ConstantAggregateZero* zero_initializer = + llvm::ConstantAggregateZero::get(shadow_frame_type); + + irb_.CreateStore(zero_initializer, shadow_frame_); + + // Variables for GetElementPtr + llvm::Constant* zero = irb_.getInt32(0); + + llvm::Value* gep_index[] = { + zero, // No displacement for shadow frame pointer + zero, // Get the %ArtFrame data structure + NULL, + }; + + // Store the method pointer + gep_index[2] = irb_.getInt32(1); + llvm::Value* method_field_addr = irb_.CreateGEP(shadow_frame_, gep_index); + llvm::Value* method_object_addr = EmitLoadMethodObjectAddr(); + irb_.CreateStore(method_object_addr, method_field_addr); + + // Store the number of the pointer slots + gep_index[2] = irb_.getInt32(3); + llvm::Value* size_field_addr = irb_.CreateGEP(shadow_frame_, gep_index); + llvm::ConstantInt* sirt_size_value = irb_.getInt32(sirt_size); + irb_.CreateStore(sirt_size_value, size_field_addr); + + // Push the shadow frame + llvm::Value* shadow_frame_upcast = + irb_.CreateConstGEP2_32(shadow_frame_, 0, 0); + + irb_.CreateCall(irb_.GetRuntime(PushShadowFrame), shadow_frame_upcast); +} + + void MethodCompiler::EmitPrologueAssignArgRegister() { uint16_t arg_reg = code_item_->registers_size_ - code_item_->ins_size_; @@ -1145,6 +1202,8 @@ void MethodCompiler::EmitInsn_ThrowException(uint32_t dex_pc, llvm::Value* exception_addr = EmitLoadDalvikReg(dec_insn.vA_, kObject, kAccurate); + EmitUpdateLineNumFromDexPC(dex_pc); + irb_.CreateCall(irb_.GetRuntime(ThrowException), exception_addr); EmitBranchExceptionLandingPad(dex_pc); @@ -1156,6 +1215,9 @@ void MethodCompiler::EmitInsn_ReturnVoid(uint32_t dex_pc, // Garbage collection safe-point EmitGuard_GarbageCollectionSuspend(dex_pc); + // Pop the shadow frame + EmitPopShadowFrame(); + // Return! irb_.CreateRetVoid(); } @@ -1169,6 +1231,11 @@ void MethodCompiler::EmitInsn_Return(uint32_t dex_pc, // Garbage collection safe-point EmitGuard_GarbageCollectionSuspend(dex_pc); + // Pop the shadow frame + EmitPopShadowFrame(); + // NOTE: It is important to keep this AFTER the GC safe-point. Otherwise, + // the return value might be collected since the shadow stack is popped. + // Return! char ret_shorty = method_helper_.GetShorty()[0]; llvm::Value* retval = EmitLoadDalvikReg(dec_insn.vA_, ret_shorty, kAccurate); @@ -1269,8 +1336,10 @@ void MethodCompiler::EmitInsn_LoadConstantString(uint32_t dex_pc, llvm::Value* string_idx_value = irb_.getInt32(string_idx); - string_addr = irb_.CreateCall2(runtime_func, - method_object_addr, string_idx_value); + EmitUpdateLineNumFromDexPC(dex_pc); + + string_addr = irb_.CreateCall2(runtime_func, method_object_addr, + string_idx_value); EmitGuard_ExceptionLandingPad(dex_pc); } @@ -1293,6 +1362,8 @@ llvm::Value* MethodCompiler::EmitLoadConstantClass(uint32_t dex_pc, llvm::Function* runtime_func = irb_.GetRuntime(InitializeTypeAndVerifyAccess); + EmitUpdateLineNumFromDexPC(dex_pc); + llvm::Value* type_object_addr = irb_.CreateCall2(runtime_func, type_idx_value, method_object_addr); @@ -1334,6 +1405,8 @@ llvm::Value* MethodCompiler::EmitLoadConstantClass(uint32_t dex_pc, llvm::Value* method_object_addr = EmitLoadMethodObjectAddr(); + EmitUpdateLineNumFromDexPC(dex_pc); + llvm::Value* loaded_type_object_addr = irb_.CreateCall2(runtime_func, type_idx_value, method_object_addr); @@ -1379,6 +1452,8 @@ void MethodCompiler::EmitInsn_MonitorEnter(uint32_t dex_pc, // TODO: Slow path always. May not need NullPointerException check. EmitGuard_NullPointerException(dex_pc, object_addr); + EmitUpdateLineNumFromDexPC(dex_pc); + irb_.CreateCall(irb_.GetRuntime(LockObject), object_addr); EmitGuard_ExceptionLandingPad(dex_pc); @@ -1396,6 +1471,8 @@ void MethodCompiler::EmitInsn_MonitorExit(uint32_t dex_pc, EmitGuard_NullPointerException(dex_pc, object_addr); + EmitUpdateLineNumFromDexPC(dex_pc); + irb_.CreateCall(irb_.GetRuntime(UnlockObject), object_addr); EmitGuard_ExceptionLandingPad(dex_pc); @@ -1447,6 +1524,8 @@ void MethodCompiler::EmitInsn_CheckCast(uint32_t dex_pc, // Test: Is the object instantiated from the subclass of the given class? irb_.SetInsertPoint(block_test_sub_class); + EmitUpdateLineNumFromDexPC(dex_pc); + irb_.CreateCall2(irb_.GetRuntime(CheckCast), type_object_addr, object_type_object_addr); @@ -1574,6 +1653,8 @@ void MethodCompiler::EmitInsn_NewInstance(uint32_t dex_pc, llvm::Value* method_object_addr = EmitLoadMethodObjectAddr(); + EmitUpdateLineNumFromDexPC(dex_pc); + llvm::Value* object_addr = irb_.CreateCall2(runtime_func, type_index_value, method_object_addr); @@ -1611,6 +1692,8 @@ llvm::Value* MethodCompiler::EmitAllocNewArray(uint32_t dex_pc, llvm::Value* array_length_value = irb_.getInt32(length); + EmitUpdateLineNumFromDexPC(dex_pc); + llvm::Value* object_addr = irb_.CreateCall3(runtime_func, type_index_value, method_object_addr, array_length_value); @@ -2092,6 +2175,8 @@ MethodCompiler::EmitGuard_ArrayIndexOutOfBoundsException(uint32_t dex_pc, irb_.CreateCondBr(cmp, block_exception, block_continue); irb_.SetInsertPoint(block_exception); + + EmitUpdateLineNumFromDexPC(dex_pc); irb_.CreateCall2(irb_.GetRuntime(ThrowIndexOutOfBounds), index, array_len); EmitBranchExceptionLandingPad(dex_pc); @@ -2215,6 +2300,8 @@ void MethodCompiler::EmitInsn_IGet(uint32_t dex_pc, llvm::Value* method_object_addr = EmitLoadMethodObjectAddr(); + EmitUpdateLineNumFromDexPC(dex_pc); + field_value = irb_.CreateCall2(runtime_func, field_idx_value, method_object_addr); @@ -2273,6 +2360,8 @@ void MethodCompiler::EmitInsn_IPut(uint32_t dex_pc, llvm::Value* method_object_addr = EmitLoadMethodObjectAddr(); + EmitUpdateLineNumFromDexPC(dex_pc); + irb_.CreateCall3(runtime_func, field_idx_value, method_object_addr, new_value); @@ -2431,6 +2520,8 @@ llvm::Value* MethodCompiler::EmitLoadStaticStorage(uint32_t dex_pc, llvm::Value* method_object_addr = EmitLoadMethodObjectAddr(); + EmitUpdateLineNumFromDexPC(dex_pc); + llvm::Value* loaded_storage_object_addr = irb_.CreateCall2(runtime_func, type_idx_value, method_object_addr); @@ -2479,6 +2570,8 @@ void MethodCompiler::EmitInsn_SGet(uint32_t dex_pc, llvm::Value* method_object_addr = EmitLoadMethodObjectAddr(); + EmitUpdateLineNumFromDexPC(dex_pc); + static_field_value = irb_.CreateCall2(runtime_func, field_idx_value, method_object_addr); @@ -2531,6 +2624,8 @@ void MethodCompiler::EmitInsn_SPut(uint32_t dex_pc, llvm::Value* method_object_addr = EmitLoadMethodObjectAddr(); + EmitUpdateLineNumFromDexPC(dex_pc); + irb_.CreateCall3(runtime_func, field_idx_value, method_object_addr, new_value); @@ -2652,8 +2747,8 @@ void MethodCompiler::EmitInsn_InvokeVirtual(uint32_t dex_pc, is_range, false); // Invoke callee + EmitUpdateLineNumFromDexPC(dex_pc); llvm::Value* retval = irb_.CreateCall(code_addr, args); - EmitGuard_ExceptionLandingPad(dex_pc); MethodHelper method_helper(callee_method); @@ -2746,8 +2841,8 @@ void MethodCompiler::EmitInsn_InvokeSuper(uint32_t dex_pc, is_range, false); // Invoke callee + EmitUpdateLineNumFromDexPC(dex_pc); llvm::Value* retval = irb_.CreateCall(code_addr, args); - EmitGuard_ExceptionLandingPad(dex_pc); MethodHelper method_helper(callee_method); @@ -2824,6 +2919,8 @@ void MethodCompiler::EmitInsn_InvokeStaticDirect(uint32_t dex_pc, EmitLoadActualParameters(args, callee_method_idx, dec_insn, is_range, is_static); + // Invoke callee + EmitUpdateLineNumFromDexPC(dex_pc); llvm::Value* retval = irb_.CreateCall(code_addr, args); EmitGuard_ExceptionLandingPad(dex_pc); @@ -2859,6 +2956,8 @@ void MethodCompiler::EmitInsn_InvokeInterface(uint32_t dex_pc, llvm::Value* callee_method_idx_value = irb_.getInt32(callee_method_idx); + EmitUpdateLineNumFromDexPC(dex_pc); + llvm::Value* callee_method_object_addr = irb_.CreateCall2(runtime_func, callee_method_idx_value, method_object_addr); @@ -2873,7 +2972,8 @@ void MethodCompiler::EmitInsn_InvokeInterface(uint32_t dex_pc, args.push_back(this_addr); EmitLoadActualParameters(args, callee_method_idx, dec_insn, is_range, false); - // Emit the code to invoke callee + // Invoke callee + EmitUpdateLineNumFromDexPC(dex_pc); llvm::Value* retval = irb_.CreateCall(code_addr, args); EmitGuard_ExceptionLandingPad(dex_pc); @@ -3266,6 +3366,7 @@ void MethodCompiler::EmitGuard_DivZeroException(uint32_t dex_pc, irb_.CreateCondBr(equal_zero, block_exception, block_continue); irb_.SetInsertPoint(block_exception); + EmitUpdateLineNumFromDexPC(dex_pc); irb_.CreateCall(irb_.GetRuntime(ThrowDivZeroException)); EmitBranchExceptionLandingPad(dex_pc); @@ -3341,6 +3442,7 @@ void MethodCompiler::EmitGuard_NullPointerException(uint32_t dex_pc, irb_.CreateCondBr(equal_null, block_exception, block_continue); irb_.SetInsertPoint(block_exception); + EmitUpdateLineNumFromDexPC(dex_pc); irb_.CreateCall(irb_.GetRuntime(ThrowNullPointerException)); EmitBranchExceptionLandingPad(dex_pc); @@ -3470,6 +3572,7 @@ void MethodCompiler::EmitGuard_ExceptionLandingPad(uint32_t dex_pc) { void MethodCompiler::EmitGuard_GarbageCollectionSuspend(uint32_t dex_pc) { llvm::Value* runtime_func = irb_.GetRuntime(TestSuspend); + EmitUpdateLineNumFromDexPC(dex_pc); irb_.CreateCall(runtime_func); EmitGuard_ExceptionLandingPad(dex_pc); @@ -3619,6 +3722,9 @@ llvm::BasicBlock* MethodCompiler::GetUnwindBasicBlock() { llvm::IRBuilderBase::InsertPoint irb_ip_original = irb_.saveIP(); irb_.SetInsertPoint(basic_block_unwind_); + // Pop the shadow frame + EmitPopShadowFrame(); + // Emit the code to return default value (zero) for the given return type. char ret_shorty = method_helper_.GetShorty()[0]; if (ret_shorty == 'V') { @@ -3663,12 +3769,21 @@ llvm::Value* MethodCompiler::AllocDalvikLocalVarReg(RegCategory cat, break; case kRegObject: - irb_.SetInsertPoint(basic_block_reg_alloca_); - reg_addr = irb_.CreateAlloca(irb_.getJObjectTy(), 0, - StringPrintf("p%u", reg_idx)); + { + irb_.SetInsertPoint(basic_block_shadow_frame_alloca_); - irb_.SetInsertPoint(basic_block_reg_zero_init_); - irb_.CreateStore(irb_.getJNull(), reg_addr); + llvm::Value* gep_index[] = { + irb_.getInt32(0), // No pointer displacement + irb_.getInt32(1), // SIRT + irb_.getInt32(reg_idx) // Pointer field + }; + + reg_addr = irb_.CreateGEP(shadow_frame_, gep_index, + StringPrintf("p%u", reg_idx)); + + irb_.SetInsertPoint(basic_block_reg_zero_init_); + irb_.CreateStore(irb_.getJNull(), reg_addr); + } break; default: @@ -3718,5 +3833,30 @@ llvm::Value* MethodCompiler::AllocDalvikRetValReg(RegCategory cat) { } +void MethodCompiler::EmitPopShadowFrame() { + irb_.CreateCall(irb_.GetRuntime(PopShadowFrame)); +} + + +void MethodCompiler::EmitUpdateLineNum(int32_t line_num) { + llvm::Constant* zero = irb_.getInt32(0); + + llvm::Value* gep_index[] = { + zero, // No displacement for shadow frame pointer + zero, // Get the %ArtFrame data structure + irb_.getInt32(2), + }; + + llvm::Value* line_num_field_addr = irb_.CreateGEP(shadow_frame_, gep_index); + llvm::ConstantInt* line_num_value = irb_.getInt32(line_num); + irb_.CreateStore(line_num_value, line_num_field_addr); +} + + +void MethodCompiler::EmitUpdateLineNumFromDexPC(uint32_t dex_pc) { + EmitUpdateLineNum(dex_file_->GetLineNumFromPC(method_, dex_pc)); +} + + } // namespace compiler_llvm } // namespace art diff --git a/src/compiler_llvm/method_compiler.h b/src/compiler_llvm/method_compiler.h index 0ec4858..dd10bc8 100644 --- a/src/compiler_llvm/method_compiler.h +++ b/src/compiler_llvm/method_compiler.h @@ -86,6 +86,7 @@ class MethodCompiler { UniquePtr<DalvikReg> retval_reg_; llvm::BasicBlock* basic_block_reg_alloca_; + llvm::BasicBlock* basic_block_shadow_frame_alloca_; llvm::BasicBlock* basic_block_reg_zero_init_; llvm::BasicBlock* basic_block_reg_arg_init_; std::vector<llvm::BasicBlock*> basic_blocks_; @@ -94,6 +95,8 @@ class MethodCompiler { llvm::BasicBlock* basic_block_unwind_; llvm::BasicBlock* basic_block_unreachable_; + llvm::AllocaInst* shadow_frame_; + public: MethodCompiler(InstructionSet insn_set, @@ -129,6 +132,7 @@ class MethodCompiler { void CreateFunction(); void EmitPrologue(); void EmitPrologueLastBranch(); + void EmitPrologueAllocShadowFrame(); void EmitPrologueAssignArgRegister(); void EmitInstructions(); void EmitInstruction(uint32_t dex_pc, Instruction const* insn); @@ -266,6 +270,12 @@ class MethodCompiler { #undef GEN_INSN_ARGS + // Shadow frame helper function + void EmitPopShadowFrame(); + void EmitUpdateLineNum(int32_t line_number); + void EmitUpdateLineNumFromDexPC(uint32_t dex_pc); + + // Dex cache code generation helper function llvm::Value* EmitLoadDexCacheAddr(MemberOffset dex_cache_offset); |