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);