Various fixes to the interpreter. First 23 run-test tests pass.

- Factored out code to throw stack overflow error into its own method.
- Increased kStackOverflowReservedBytes to 10kB to support interpreter.
- Reordered return type checks to prevent type resolution with an
  exception pending.
- Fixed field checks so they pass if the field is static or the object
  is the declaring class.
- Suppressed using the interpreter for proxy methods.

Change-Id: Ide73ec928ab0aa7b31229c4e69679a35dd948e43
diff --git a/src/compiler_llvm/runtime_support_llvm.cc b/src/compiler_llvm/runtime_support_llvm.cc
index 28f9335..371b32a 100644
--- a/src/compiler_llvm/runtime_support_llvm.cc
+++ b/src/compiler_llvm/runtime_support_llvm.cc
@@ -150,13 +150,7 @@
 void art_throw_stack_overflow_from_code()
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   Thread* thread = art_get_current_thread_from_code();
-  if (Runtime::Current()->IsMethodTracingActive()) {
-    InstrumentationMethodUnwindFromCode(thread);
-  }
-  thread->SetStackEndForStackOverflow();  // Allow space on the stack for constructor to execute.
-  thread->ThrowNewExceptionF("Ljava/lang/StackOverflowError;", "stack size %s",
-                             PrettySize(thread->GetStackSize()).c_str());
-  thread->ResetDefaultStackEnd();  // Return to default stack size.
+  ThrowStackOverflowError(thread);
 }
 
 void art_throw_exception_from_code(Object* exception)
diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc
index d8031c1..0a66a21 100644
--- a/src/interpreter/interpreter.cc
+++ b/src/interpreter/interpreter.cc
@@ -405,7 +405,9 @@
   } else {
     UnstartedRuntimeInvoke(self, target_method, receiver, arg_array.get(), result);
   }
-  if (!mh.GetReturnType()->IsPrimitive() && result->GetL() != NULL) {
+  // Check the return type if the result is non-null. We do the GetReturnType
+  // after the null check to avoid resolution when there's an exception pending.
+  if (result->GetL() != NULL && !mh.GetReturnType()->IsPrimitive()) {
     CHECK(mh.GetReturnType()->IsAssignableFrom(result->GetL()->GetClass()));
   }
   mh.ChangeMethod(shadow_frame.GetMethod());
@@ -1747,6 +1749,11 @@
 void EnterInterpreterFromInvoke(Thread* self, AbstractMethod* method, Object* receiver,
                                 JValue* args, JValue* result) {
   DCHECK_EQ(self, Thread::Current());
+  if (__builtin_frame_address(0) < self->GetStackEnd()) {
+    ThrowStackOverflowError(self);
+    return;
+  }
+
   MethodHelper mh(method);
   const DexFile::CodeItem* code_item = mh.GetCodeItem();
   uint16_t num_regs;
diff --git a/src/oat/runtime/support_throw.cc b/src/oat/runtime/support_throw.cc
index 420b442..21adc52 100644
--- a/src/oat/runtime/support_throw.cc
+++ b/src/oat/runtime/support_throw.cc
@@ -91,27 +91,7 @@
 extern "C" void artThrowStackOverflowFromCode(Thread* self, AbstractMethod** sp)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
-  CHECK(!self->IsHandlingStackOverflow()) << "Recursive stack overflow.";
-  // Remove extra entry pushed onto second stack during method tracing.
-  if (Runtime::Current()->IsMethodTracingActive()) {
-    InstrumentationMethodUnwindFromCode(self);
-  }
-  self->SetStackEndForStackOverflow();  // Allow space on the stack for constructor to execute.
-  JNIEnvExt* env = self->GetJniEnv();
-  std::string msg("stack size ");
-  msg += PrettySize(self->GetStackSize());
-  // Use low-level JNI routine and pre-baked error class to avoid class linking operations that
-  // would consume more stack.
-  int rc = ::art::ThrowNewException(env, WellKnownClasses::java_lang_StackOverflowError,
-                                    msg.c_str(), NULL);
-  if (rc != JNI_OK) {
-    // TODO: ThrowNewException failed presumably because of an OOME, we continue to throw the OOME
-    //       or die in the CHECK below. We may want to throw a pre-baked StackOverflowError
-    //       instead.
-    LOG(ERROR) << "Couldn't throw new StackOverflowError because JNI ThrowNew failed.";
-    CHECK(self->IsExceptionPending());
-  }
-  self->ResetDefaultStackEnd();  // Return to default stack size.
+  ThrowStackOverflowError(self);
   self->DeliverException();
 }
 
diff --git a/src/object.cc b/src/object.cc
index dce475f..147b882 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -233,37 +233,37 @@
 
 uint32_t Field::Get32(const Object* object) const {
   DCHECK(object != NULL) << PrettyField(this);
-  DCHECK(IsStatic() == (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
+  DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
   return object->GetField32(GetOffset(), IsVolatile());
 }
 
 void Field::Set32(Object* object, uint32_t new_value) const {
   DCHECK(object != NULL) << PrettyField(this);
-  DCHECK(IsStatic() == (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
+  DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
   object->SetField32(GetOffset(), new_value, IsVolatile());
 }
 
 uint64_t Field::Get64(const Object* object) const {
   DCHECK(object != NULL) << PrettyField(this);
-  DCHECK(IsStatic() == (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
+  DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
   return object->GetField64(GetOffset(), IsVolatile());
 }
 
 void Field::Set64(Object* object, uint64_t new_value) const {
   DCHECK(object != NULL) << PrettyField(this);
-  DCHECK(IsStatic() == (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
+  DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
   object->SetField64(GetOffset(), new_value, IsVolatile());
 }
 
 Object* Field::GetObj(const Object* object) const {
   DCHECK(object != NULL) << PrettyField(this);
-  DCHECK(IsStatic() == (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
+  DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
   return object->GetFieldObject<Object*>(GetOffset(), IsVolatile());
 }
 
 void Field::SetObj(Object* object, const Object* new_value) const {
   DCHECK(object != NULL) << PrettyField(this);
-  DCHECK(IsStatic() == (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
+  DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
   object->SetFieldObject(GetOffset(), new_value, IsVolatile());
 }
 
@@ -663,7 +663,7 @@
       result->SetJ(0);
     }
   } else {
-    bool interpret = self->ReadFlag(kEnterInterpreter) && !IsNative();
+    bool interpret = self->ReadFlag(kEnterInterpreter) && !IsNative() && !IsProxyMethod();
     const bool kLogInvocationStartAndReturn = false;
     if (!interpret && GetCode() != NULL && stub != NULL) {
       if (kLogInvocationStartAndReturn) {
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 7ee1960..92c5e3a 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -343,4 +343,28 @@
   return klass;
 }
 
+void ThrowStackOverflowError(Thread* self) {
+  CHECK(!self->IsHandlingStackOverflow()) << "Recursive stack overflow.";
+  // Remove extra entry pushed onto second stack during method tracing.
+  if (Runtime::Current()->IsMethodTracingActive()) {
+    InstrumentationMethodUnwindFromCode(self);
+  }
+  self->SetStackEndForStackOverflow();  // Allow space on the stack for constructor to execute.
+  JNIEnvExt* env = self->GetJniEnv();
+  std::string msg("stack size ");
+  msg += PrettySize(self->GetStackSize());
+  // Use low-level JNI routine and pre-baked error class to avoid class linking operations that
+  // would consume more stack.
+  int rc = ::art::ThrowNewException(env, WellKnownClasses::java_lang_StackOverflowError,
+                                    msg.c_str(), NULL);
+  if (rc != JNI_OK) {
+    // TODO: ThrowNewException failed presumably because of an OOME, we continue to throw the OOME
+    //       or die in the CHECK below. We may want to throw a pre-baked StackOverflowError
+    //       instead.
+    LOG(ERROR) << "Couldn't throw new StackOverflowError because JNI ThrowNew failed.";
+    CHECK(self->IsExceptionPending());
+  }
+  self->ResetDefaultStackEnd();  // Return to default stack size.
+}
+
 }  // namespace art
diff --git a/src/runtime_support.h b/src/runtime_support.h
index e54e05b..d0a6209 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -231,6 +231,8 @@
                                      bool can_run_clinit, bool verify_access)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+extern void ThrowStackOverflowError(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
 static inline String* ResolveStringFromCode(const AbstractMethod* referrer, uint32_t string_idx)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
diff --git a/src/thread.h b/src/thread.h
index be7c673..4e1f0e7 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -106,11 +106,7 @@
 class PACKED Thread {
  public:
   // Space to throw a StackOverflowError in.
-#if !defined(ART_USE_LLVM_COMPILER)
-  static const size_t kStackOverflowReservedBytes = 4 * KB;
-#else  // LLVM_x86 requires more memory to throw stack overflow exception.
-  static const size_t kStackOverflowReservedBytes = 8 * KB;
-#endif
+  static const size_t kStackOverflowReservedBytes = 10 * KB;
 
   // Creates a new native thread corresponding to the given managed peer.
   // Used to implement Thread.start.
@@ -448,10 +444,14 @@
   }
 
   // Size of stack less any space reserved for stack overflow
-  size_t GetStackSize() {
+  size_t GetStackSize() const {
     return stack_size_ - (stack_end_ - stack_begin_);
   }
 
+  byte* GetStackEnd() const {
+    return stack_end_;
+  }
+
   // Set the stack end to that to be used during a stack overflow
   void SetStackEndForStackOverflow() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);