Add shadow stack support to Dex compiler.
Change-Id: I8e188be3fb30c81e2a9e6e466264074ddf7b1624
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 @@
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::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 @@
return getJLongTy();
}
+ llvm::StructType* getShadowFrameTy(uint32_t sirt_size);
+
//--------------------------------------------------------------------------
// Constant Value Helper Function
@@ -282,6 +284,8 @@
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 @@
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 @@
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 @@
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::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::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 @@
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 @@
// Garbage collection safe-point
EmitGuard_GarbageCollectionSuspend(dex_pc);
+ // Pop the shadow frame
+ EmitPopShadowFrame();
+
// Return!
irb_.CreateRetVoid();
}
@@ -1169,6 +1231,11 @@
// 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 @@
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::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* 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 @@
// 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 @@
EmitGuard_NullPointerException(dex_pc, object_addr);
+ EmitUpdateLineNumFromDexPC(dex_pc);
+
irb_.CreateCall(irb_.GetRuntime(UnlockObject), object_addr);
EmitGuard_ExceptionLandingPad(dex_pc);
@@ -1447,6 +1524,8 @@
// 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 @@
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* 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 @@
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 @@
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 @@
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* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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_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::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 @@
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 @@
}
+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 @@
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 @@
llvm::BasicBlock* basic_block_unwind_;
llvm::BasicBlock* basic_block_unreachable_;
+ llvm::AllocaInst* shadow_frame_;
+
public:
MethodCompiler(InstructionSet insn_set,
@@ -129,6 +132,7 @@
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 @@
#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);