Refactor runtime support.

Change-Id: Id7470a4105838150d5ceb73ab2c8c83e739660df
diff --git a/src/oat/runtime/support_throw.cc b/src/oat/runtime/support_throw.cc
new file mode 100644
index 0000000..9f46b2b
--- /dev/null
+++ b/src/oat/runtime/support_throw.cc
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2012 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "callee_save_frame.h"
+#include "dex_verifier.h"
+#include "object.h"
+#include "object_utils.h"
+#include "runtime_support.h"
+#include "thread.h"
+
+namespace art {
+
+// Deliver an exception that's pending on thread helping set up a callee save frame on the way.
+extern "C" void artDeliverPendingExceptionFromCode(Thread* thread, Method** sp) {
+  FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
+  thread->DeliverException();
+}
+
+// Called by generated call to throw an exception.
+extern "C" void artDeliverExceptionFromCode(Throwable* exception, Thread* thread, Method** sp) {
+  /*
+   * exception may be NULL, in which case this routine should
+   * throw NPE.  NOTE: this is a convenience for generated code,
+   * which previously did the null check inline and constructed
+   * and threw a NPE if NULL.  This routine responsible for setting
+   * exception_ in thread and delivering the exception.
+   */
+  FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
+  if (exception == NULL) {
+    thread->ThrowNewException("Ljava/lang/NullPointerException;", "throw with null exception");
+  } else {
+    thread->SetException(exception);
+  }
+  thread->DeliverException();
+}
+
+// Called by generated call to throw a NPE exception.
+extern "C" void artThrowNullPointerExceptionFromCode(Thread* self, Method** sp) {
+  FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
+  Frame fr = self->GetTopOfStack();
+  uintptr_t throw_native_pc = fr.GetReturnPC();
+  fr.Next();
+  Method* throw_method = fr.GetMethod();
+  uint32_t dex_pc = throw_method->ToDexPC(throw_native_pc - 2);
+  const DexFile::CodeItem* code = MethodHelper(throw_method).GetCodeItem();
+  CHECK_LT(dex_pc, code->insns_size_in_code_units_);
+  const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
+  DecodedInstruction dec_insn(instr);
+  switch (instr->Opcode()) {
+    case Instruction::INVOKE_DIRECT:
+    case Instruction::INVOKE_DIRECT_RANGE:
+      ThrowNullPointerExceptionForMethodAccess(self, throw_method, dec_insn.vB, kDirect);
+      break;
+    case Instruction::INVOKE_VIRTUAL:
+    case Instruction::INVOKE_VIRTUAL_RANGE:
+      ThrowNullPointerExceptionForMethodAccess(self, throw_method, dec_insn.vB, kVirtual);
+      break;
+    case Instruction::IGET:
+    case Instruction::IGET_WIDE:
+    case Instruction::IGET_OBJECT:
+    case Instruction::IGET_BOOLEAN:
+    case Instruction::IGET_BYTE:
+    case Instruction::IGET_CHAR:
+    case Instruction::IGET_SHORT: {
+      Field* field =
+          Runtime::Current()->GetClassLinker()->ResolveField(dec_insn.vC, throw_method, false);
+      ThrowNullPointerExceptionForFieldAccess(self, field, true /* read */);
+      break;
+    }
+    case Instruction::IPUT:
+    case Instruction::IPUT_WIDE:
+    case Instruction::IPUT_OBJECT:
+    case Instruction::IPUT_BOOLEAN:
+    case Instruction::IPUT_BYTE:
+    case Instruction::IPUT_CHAR:
+    case Instruction::IPUT_SHORT: {
+      Field* field =
+          Runtime::Current()->GetClassLinker()->ResolveField(dec_insn.vC, throw_method, false);
+      ThrowNullPointerExceptionForFieldAccess(self, field, false /* write */);
+      break;
+    }
+    case Instruction::AGET:
+    case Instruction::AGET_WIDE:
+    case Instruction::AGET_OBJECT:
+    case Instruction::AGET_BOOLEAN:
+    case Instruction::AGET_BYTE:
+    case Instruction::AGET_CHAR:
+    case Instruction::AGET_SHORT:
+      self->ThrowNewException("Ljava/lang/NullPointerException;",
+                              "Attempt to read from null array");
+      break;
+    case Instruction::APUT:
+    case Instruction::APUT_WIDE:
+    case Instruction::APUT_OBJECT:
+    case Instruction::APUT_BOOLEAN:
+    case Instruction::APUT_BYTE:
+    case Instruction::APUT_CHAR:
+    case Instruction::APUT_SHORT:
+      self->ThrowNewException("Ljava/lang/NullPointerException;",
+                              "Attempt to write to null array");
+      break;
+    default: {
+      const DexFile& dex_file = Runtime::Current()->GetClassLinker()
+          ->FindDexFile(throw_method->GetDeclaringClass()->GetDexCache());
+      std::string message("Null pointer exception during instruction '");
+      message += instr->DumpString(&dex_file);
+      message += "'";
+      self->ThrowNewException("Ljava/lang/NullPointerException;", message.c_str());
+      break;
+    }
+  }
+  self->DeliverException();
+}
+
+// Called by generated call to throw an arithmetic divide by zero exception.
+extern "C" void artThrowDivZeroFromCode(Thread* thread, Method** sp) {
+  FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
+  thread->ThrowNewException("Ljava/lang/ArithmeticException;", "divide by zero");
+  thread->DeliverException();
+}
+
+// Called by generated call to throw an array index out of bounds exception.
+extern "C" void artThrowArrayBoundsFromCode(int index, int limit, Thread* thread, Method** sp) {
+  FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
+  thread->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;",
+                             "length=%d; index=%d", limit, index);
+  thread->DeliverException();
+}
+
+extern "C" void artThrowStackOverflowFromCode(Thread* thread, Method** sp) {
+  FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
+  // Remove extra entry pushed onto second stack during method tracing
+  if (Runtime::Current()->IsMethodTracingActive()) {
+    TraceMethodUnwindFromCode(thread);
+  }
+  thread->SetStackEndForStackOverflow();  // Allow space on the stack for constructor to execute
+  thread->ThrowNewExceptionF("Ljava/lang/StackOverflowError;",
+      "stack size %zdkb; default stack size: %zdkb",
+      thread->GetStackSize() / KB, Runtime::Current()->GetDefaultStackSize() / KB);
+  thread->ResetDefaultStackEnd();  // Return to default stack size
+  thread->DeliverException();
+}
+
+extern "C" void artThrowNoSuchMethodFromCode(int32_t method_idx, Thread* self, Method** sp) {
+  FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
+  Frame frame = self->GetTopOfStack();  // We need the calling method as context for the method_idx
+  frame.Next();
+  Method* method = frame.GetMethod();
+  self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
+      MethodNameFromIndex(method, method_idx, verifier::VERIFY_ERROR_REF_METHOD, false).c_str());
+  self->DeliverException();
+}
+
+static std::string ClassNameFromIndex(Method* method, uint32_t ref,
+                                      verifier::VerifyErrorRefType ref_type, bool access) {
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  const DexFile& dex_file = class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache());
+
+  uint16_t type_idx = 0;
+  if (ref_type == verifier::VERIFY_ERROR_REF_FIELD) {
+    const DexFile::FieldId& id = dex_file.GetFieldId(ref);
+    type_idx = id.class_idx_;
+  } else if (ref_type == verifier::VERIFY_ERROR_REF_METHOD) {
+    const DexFile::MethodId& id = dex_file.GetMethodId(ref);
+    type_idx = id.class_idx_;
+  } else if (ref_type == verifier::VERIFY_ERROR_REF_CLASS) {
+    type_idx = ref;
+  } else {
+    CHECK(false) << static_cast<int>(ref_type);
+  }
+
+  std::string class_name(PrettyDescriptor(dex_file.StringByTypeIdx(type_idx)));
+  if (!access) {
+    return class_name;
+  }
+
+  std::string result;
+  result += "tried to access class ";
+  result += class_name;
+  result += " from class ";
+  result += PrettyDescriptor(method->GetDeclaringClass());
+  return result;
+}
+
+extern "C" void artThrowVerificationErrorFromCode(int32_t kind, int32_t ref, Thread* self, Method** sp) {
+  FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
+  Frame frame = self->GetTopOfStack();  // We need the calling method as context to interpret 'ref'
+  frame.Next();
+  Method* method = frame.GetMethod();
+
+  verifier::VerifyErrorRefType ref_type =
+      static_cast<verifier::VerifyErrorRefType>(kind >> verifier::kVerifyErrorRefTypeShift);
+
+  const char* exception_class = "Ljava/lang/VerifyError;";
+  std::string msg;
+
+  switch (static_cast<verifier::VerifyError>(kind & ~(0xff << verifier::kVerifyErrorRefTypeShift))) {
+  case verifier::VERIFY_ERROR_NO_CLASS:
+    exception_class = "Ljava/lang/NoClassDefFoundError;";
+    msg = ClassNameFromIndex(method, ref, ref_type, false);
+    break;
+  case verifier::VERIFY_ERROR_NO_FIELD:
+    exception_class = "Ljava/lang/NoSuchFieldError;";
+    msg = FieldNameFromIndex(method, ref, ref_type, false);
+    break;
+  case verifier::VERIFY_ERROR_NO_METHOD:
+    exception_class = "Ljava/lang/NoSuchMethodError;";
+    msg = MethodNameFromIndex(method, ref, ref_type, false);
+    break;
+  case verifier::VERIFY_ERROR_ACCESS_CLASS:
+    exception_class = "Ljava/lang/IllegalAccessError;";
+    msg = ClassNameFromIndex(method, ref, ref_type, true);
+    break;
+  case verifier::VERIFY_ERROR_ACCESS_FIELD:
+    exception_class = "Ljava/lang/IllegalAccessError;";
+    msg = FieldNameFromIndex(method, ref, ref_type, true);
+    break;
+  case verifier::VERIFY_ERROR_ACCESS_METHOD:
+    exception_class = "Ljava/lang/IllegalAccessError;";
+    msg = MethodNameFromIndex(method, ref, ref_type, true);
+    break;
+  case verifier::VERIFY_ERROR_CLASS_CHANGE:
+    exception_class = "Ljava/lang/IncompatibleClassChangeError;";
+    msg = ClassNameFromIndex(method, ref, ref_type, false);
+    break;
+  case verifier::VERIFY_ERROR_INSTANTIATION:
+    exception_class = "Ljava/lang/InstantiationError;";
+    msg = ClassNameFromIndex(method, ref, ref_type, false);
+    break;
+  case verifier::VERIFY_ERROR_BAD_CLASS_SOFT:
+  case verifier::VERIFY_ERROR_BAD_CLASS_HARD:
+    // Generic VerifyError; use default exception, no message.
+    break;
+  case verifier::VERIFY_ERROR_NONE:
+    CHECK(false);
+    break;
+  }
+  self->ThrowNewException(exception_class, msg.c_str());
+  self->DeliverException();
+}
+
+}  // namespace art