Quick compiler exception support

Handle MOVE_RESULT, THROW and THROW_VERIFICATION_ERROR.  Enable
runtests 007 and 014 to pass.  Minor munging of the tests to make
them easier to selectively compile with the Quick compiler.

Change-Id: I756def54d81771b144e8ebc213cd90077e23758b
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc
index 34798f9..9e4b857 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -761,8 +761,12 @@
   if ((PrettyMethod(method_idx, dex_file).find("fibonacci") != std::string::npos)
       || (PrettyMethod(method_idx, dex_file).find("HelloWorld") != std::string::npos)
       || (PrettyMethod(method_idx, dex_file).find("count10_006") != std::string::npos)
+      || (PrettyMethod(method_idx, dex_file).find("exceptions_007") != std::string::npos)
+      || (PrettyMethod(method_idx, dex_file).find("catchAndRethrow") != std::string::npos)
+      || (PrettyMethod(method_idx, dex_file).find("throwNullPointerException") != std::string::npos)
       || (PrettyMethod(method_idx, dex_file).find("math_012") != std::string::npos)
       || (PrettyMethod(method_idx, dex_file).find("math_013") != std::string::npos)
+      || (PrettyMethod(method_idx, dex_file).find("math_014") != std::string::npos)
       || (PrettyMethod(method_idx, dex_file).find("float_017") != std::string::npos)
      ) {
     cUnit->genBitcode = true;
diff --git a/src/compiler/codegen/MethodBitcode.cc b/src/compiler/codegen/MethodBitcode.cc
index 1c4fdf4..cf990ec 100644
--- a/src/compiler/codegen/MethodBitcode.cc
+++ b/src/compiler/codegen/MethodBitcode.cc
@@ -203,6 +203,34 @@
   return cUnit->irb->CreateCall(intr, src);
 }
 
+void convertMoveException(CompilationUnit* cUnit, RegLocation rlDest)
+{
+  llvm::Function* func = cUnit->intrinsic_helper->GetIntrinsicFunction(
+      greenland::IntrinsicHelper::GetException);
+  llvm::Value* res = cUnit->irb->CreateCall(func);
+  defineValue(cUnit, res, rlDest.origSReg);
+}
+
+void convertThrow(CompilationUnit* cUnit, RegLocation rlSrc)
+{
+  llvm::Value* src = getLLVMValue(cUnit, rlSrc.origSReg);
+  llvm::Function* func = cUnit->intrinsic_helper->GetIntrinsicFunction(
+      greenland::IntrinsicHelper::Throw);
+  cUnit->irb->CreateCall(func, src);
+  cUnit->irb->CreateUnreachable();
+}
+
+void convertThrowVerificationError(CompilationUnit* cUnit, int info1, int info2)
+{
+  llvm::Function* func = cUnit->intrinsic_helper->GetIntrinsicFunction(
+      greenland::IntrinsicHelper::Throw);
+  llvm::SmallVector<llvm::Value*, 2> args;
+  args.push_back(cUnit->irb->getInt32(info1));
+  args.push_back(cUnit->irb->getInt32(info2));
+  cUnit->irb->CreateCall(func, args);
+  cUnit->irb->CreateUnreachable();
+}
+
 void emitSuspendCheck(CompilationUnit* cUnit)
 {
   greenland::IntrinsicHelper::IntrinsicId id =
@@ -474,6 +502,7 @@
   RegLocation rlDest = badLoc;
   RegLocation rlResult = badLoc;
   Instruction::Code opcode = mir->dalvikInsn.opcode;
+  uint32_t vA = mir->dalvikInsn.vA;
   uint32_t vB = mir->dalvikInsn.vB;
   uint32_t vC = mir->dalvikInsn.vC;
 
@@ -855,6 +884,17 @@
       convertNewInstance(cUnit, bb, vB, rlDest);
       break;
 
+   case Instruction::MOVE_EXCEPTION:
+      convertMoveException(cUnit, rlDest);
+      break;
+
+   case Instruction::THROW:
+      convertThrow(cUnit, rlSrc[0]);
+      break;
+
+   case Instruction::THROW_VERIFICATION_ERROR:
+      convertThrowVerificationError(cUnit, vA, vB);
+      break;
 
 #if 0
 
@@ -1136,6 +1176,7 @@
 #endif
 
     default:
+      UNIMPLEMENTED(FATAL) << "Unsupported Dex opcode 0x" << std::hex << opcode;
       res = true;
   }
   if (objectDefinition) {
@@ -1494,13 +1535,7 @@
   SafeMap<llvm::Value*, RegLocation>::iterator it = cUnit->locMap.find(val);
   if (it == cUnit->locMap.end()) {
     std::string valName = val->getName().str();
-    DCHECK(!valName.empty());
-    if (valName[0] == 'v') {
-      int baseSReg = INVALID_SREG;
-      sscanf(valName.c_str(), "v%d_", &baseSReg);
-      res = cUnit->regLocation[baseSReg];
-      cUnit->locMap.Put(val, res);
-    } else {
+    if (valName.empty()) {
       UNIMPLEMENTED(WARNING) << "Need to handle unnamed llvm temps";
       memset(&res, 0, sizeof(res));
       res.location = kLocPhysReg;
@@ -1509,6 +1544,12 @@
       res.sRegLow = INVALID_SREG;
       res.origSReg = INVALID_SREG;
       cUnit->locMap.Put(val, res);
+    } else {
+      DCHECK_EQ(valName[0], 'v');
+      int baseSReg = INVALID_SREG;
+      sscanf(valName.c_str(), "v%d_", &baseSReg);
+      res = cUnit->regLocation[baseSReg];
+      cUnit->locMap.Put(val, res);
     }
   } else {
     res = it->second;
@@ -1773,7 +1814,7 @@
 
 void cvtNewInstance(CompilationUnit* cUnit, llvm::CallInst* callInst)
 {
-  DCHECK(callInst->getNumArgOperands() == 1);
+  DCHECK_EQ(callInst->getNumArgOperands(), 1U);
   llvm::ConstantInt* typeIdxVal =
       llvm::dyn_cast<llvm::ConstantInt>(callInst->getArgOperand(0));
   uint32_t typeIdx = typeIdxVal->getZExtValue();
@@ -1781,10 +1822,47 @@
   genNewInstance(cUnit, typeIdx, rlDest);
 }
 
+void cvtThrowVerificationError(CompilationUnit* cUnit, llvm::CallInst* callInst)
+{
+  DCHECK_EQ(callInst->getNumArgOperands(), 2U);
+  llvm::ConstantInt* info1 =
+      llvm::dyn_cast<llvm::ConstantInt>(callInst->getArgOperand(0));
+  llvm::ConstantInt* info2 =
+      llvm::dyn_cast<llvm::ConstantInt>(callInst->getArgOperand(1));
+  genThrowVerificationError(cUnit, info1->getZExtValue(), info2->getZExtValue());
+}
+
+void cvtThrow(CompilationUnit* cUnit, llvm::CallInst* callInst)
+{
+  DCHECK_EQ(callInst->getNumArgOperands(), 1U);
+  llvm::Value* src = callInst->getArgOperand(0);
+  RegLocation rlSrc = getLoc(cUnit, src);
+  genThrow(cUnit, rlSrc);
+}
+
+void cvtMoveException(CompilationUnit* cUnit, llvm::CallInst* callInst)
+{
+  DCHECK_EQ(callInst->getNumArgOperands(), 0U);
+  int exOffset = Thread::ExceptionOffset().Int32Value();
+  RegLocation rlDest = getLoc(cUnit, callInst);
+  RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+#if defined(TARGET_X86)
+  newLIR2(cUnit, kX86Mov32RT, rlResult.lowReg, exOffset);
+  newLIR2(cUnit, kX86Mov32TI, exOffset, 0);
+#else
+  int resetReg = oatAllocTemp(cUnit);
+  loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
+  loadConstant(cUnit, resetReg, 0);
+  storeWordDisp(cUnit, rSELF, exOffset, resetReg);
+  oatFreeTemp(cUnit, resetReg);
+#endif
+  storeValue(cUnit, rlDest, rlResult);
+}
+
 void cvtSget(CompilationUnit* cUnit, llvm::CallInst* callInst, bool isWide,
              bool isObject)
 {
-  DCHECK(callInst->getNumArgOperands() == 1);
+  DCHECK_EQ(callInst->getNumArgOperands(), 1U);
   llvm::ConstantInt* typeIdxVal =
       llvm::dyn_cast<llvm::ConstantInt>(callInst->getArgOperand(0));
   uint32_t typeIdx = typeIdxVal->getZExtValue();
@@ -2001,6 +2079,15 @@
             case greenland::IntrinsicHelper::SgetObj:
               cvtSget(cUnit, callInst, false /* wide */, true /* Object */);
               break;
+            case greenland::IntrinsicHelper::GetException:
+              cvtMoveException(cUnit, callInst);
+              break;
+            case greenland::IntrinsicHelper::Throw:
+              cvtThrow(cUnit, callInst);
+              break;
+            case greenland::IntrinsicHelper::ThrowVerificationError:
+              cvtThrow(cUnit, callInst);
+              break;
             case greenland::IntrinsicHelper::UnknownId:
               cvtCall(cUnit, callInst, callee);
               break;
@@ -2031,6 +2118,9 @@
       case llvm::Instruction::FDiv: cvtBinFPOp(cUnit, kOpDiv, inst); break;
       case llvm::Instruction::FRem: cvtBinFPOp(cUnit, kOpRem, inst); break;
 
+      case llvm::Instruction::Unreachable:
+        break;  // FIXME: can we really ignore these?
+
       case llvm::Instruction::Invoke:
       case llvm::Instruction::Trunc:
       case llvm::Instruction::ZExt:
@@ -2051,7 +2141,6 @@
       case llvm::Instruction::URem:
       case llvm::Instruction::UDiv:
       case llvm::Instruction::Resume:
-      case llvm::Instruction::Unreachable:
       case llvm::Instruction::Alloca:
       case llvm::Instruction::GetElementPtr:
       case llvm::Instruction::Fence:
diff --git a/src/greenland/intrinsic_func_list.def b/src/greenland/intrinsic_func_list.def
index 70f5512..e2a5557 100644
--- a/src/greenland/intrinsic_func_list.def
+++ b/src/greenland/intrinsic_func_list.def
@@ -108,6 +108,20 @@
                           kVoidTy,
                           _EXPAND_ARG2(kInt32Ty, kInt32Ty))
 
+// void dex_lang_throw(exception_object)
+_EVAL_DEF_INTRINSICS_FUNC(Throw,
+                          dex_lang_throw,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG1(kJavaObjectTy))
+
+// void dex_lang_throw_verification_error(int info1, int info2)
+_EVAL_DEF_INTRINSICS_FUNC(ThrowVerificationError,
+                          dex_lang_throw_verification_error,
+                          kAttrNoThrow,
+                          kVoidTy,
+                          _EXPAND_ARG2(kInt32Ty, kInt32Ty))
+
 //----------------------------------------------------------------------------
 // ConstString
 //----------------------------------------------------------------------------
diff --git a/test/005-args/src/Main.java b/test/005-args/src/Main.java
index 1240ec5..8abb63c 100644
--- a/test/005-args/src/Main.java
+++ b/test/005-args/src/Main.java
@@ -18,8 +18,11 @@
  * Test passing arguments of various sizes
  */
 public class Main {
-    public static void main (String args[]) {
+    public static void args_005() {
         new ArgsTest()
                 .argTest(123, 'q', 3.343434, 0x1122334455667788L, 0.12345f);
     }
+    public static void main (String args[]) {
+        args_005();
+    }
 }
diff --git a/test/007-exceptions/expected.txt b/test/007-exceptions/expected.txt
index 982c777..ef6eaff 100644
--- a/test/007-exceptions/expected.txt
+++ b/test/007-exceptions/expected.txt
@@ -1,8 +1,9 @@
 Got an NPE: second throw
 java.lang.NullPointerException: second throw
-	at Main.catchAndRethrow(Main.java:36)
-	at Main.main(Main.java:23)
+	at Main.catchAndRethrow(Main.java:39)
+	at Main.exceptions_007(Main.java:23)
+	at Main.main(Main.java:31)
 Caused by: java.lang.NullPointerException: first throw
-	at Main.throwNullPointerException(Main.java:43)
-	at Main.catchAndRethrow(Main.java:33)
-	... 1 more
+	at Main.throwNullPointerException(Main.java:46)
+	at Main.catchAndRethrow(Main.java:36)
+	... 2 more
diff --git a/test/007-exceptions/src/Main.java b/test/007-exceptions/src/Main.java
index c7da215..1f76f12 100644
--- a/test/007-exceptions/src/Main.java
+++ b/test/007-exceptions/src/Main.java
@@ -18,7 +18,7 @@
  * Exceptions across method calls
  */
 public class Main {
-    public static void main (String args[]) {
+    public static void exceptions_007() {
         try {
             catchAndRethrow();
         } catch (NullPointerException npe) {
@@ -27,6 +27,9 @@
             npe.printStackTrace();
         }
     }
+    public static void main (String args[]) {
+        exceptions_007();
+    }
 
     private static void catchAndRethrow() {
         try {
diff --git a/test/014-math3/src/Main.java b/test/014-math3/src/Main.java
index f55b17a..07e5be3 100644
--- a/test/014-math3/src/Main.java
+++ b/test/014-math3/src/Main.java
@@ -18,7 +18,7 @@
  * Test math exceptions
  */
 public class Main {
-    public static void main(String args[]) {
+    public static void math_014() {
         int expectedThrows = 2;
         int i;
         long j;
@@ -54,4 +54,7 @@
         else
             System.out.println("testMath3 success");
     }
+    public static void main(String args[]) {
+        math_014();
+    }
 }