Add shadow stack support to Dex compiler.
Change-Id: I8e188be3fb30c81e2a9e6e466264074ddf7b1624
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