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