Move from code field routines to runtime support.

Add support for exceptions from these routines. Use a macro for pending
exception delivery. Fix bug in object_test where the signature of a
FromCode function had changed.

Change-Id: If486eff8659e5f6bb38d95b1139e8981656e4fb0
diff --git a/src/asm_support.h b/src/asm_support.h
index 305e17d..19a930d 100644
--- a/src/asm_support.h
+++ b/src/asm_support.h
@@ -10,6 +10,8 @@
 #define SUSPEND_CHECK_INTERVAL (1000)
 // Offset of field Thread::suspend_count_ verified in InitCpu
 #define THREAD_SUSPEND_COUNT_OFFSET 388
+// Offset of field Thread::suspend_count_ verified in InitCpu
+#define THREAD_EXCEPTION_OFFSET 384
 
 #elif defined(__i386__)
 // Offset of field Thread::self_ verified in InitCpu
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 025f9e3..264b669 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -9,6 +9,7 @@
 #include "dex_cache.h"
 #include "dex_file.h"
 #include "heap.h"
+#include "runtime_support.h"
 
 namespace art {
 
@@ -924,8 +925,6 @@
   EXPECT_EQ(Aj2, A->FindVirtualMethodForVirtualOrInterface(Jj2));
 }
 
-extern Class* InitializeStaticStorage(uint32_t type_idx, const Method* referrer, Thread* self);
-
 TEST_F(ClassLinkerTest, InitializeStaticStorageFromCode) {
   // pretend we are trying to get the static storage for the StaticsFromCode class.
 
diff --git a/src/object.cc b/src/object.cc
index 9f225d7..58ffa6b 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -123,60 +123,6 @@
   GetType(); // Sets type_ as a side-effect. May throw.
 }
 
-Field* Field::FindInstanceFieldFromCode(uint32_t field_idx, const Method* referrer) {
-  return FindFieldFromCode(field_idx, referrer, false);
-}
-
-Field* Field::FindStaticFieldFromCode(uint32_t field_idx, const Method* referrer) {
-  return FindFieldFromCode(field_idx, referrer, true);
-}
-
-Field* Field::FindFieldFromCode(uint32_t field_idx, const Method* referrer, bool is_static) {
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  Field* f = class_linker->ResolveField(field_idx, referrer, is_static);
-  if (f != NULL) {
-    Class* c = f->GetDeclaringClass();
-    // If the class is already initializing, we must be inside <clinit>, or
-    // we'd still be waiting for the lock.
-    if (c->GetStatus() == Class::kStatusInitializing || class_linker->EnsureInitialized(c, true)) {
-      return f;
-    }
-  }
-  UNIMPLEMENTED(FATAL) << "throw an error and unwind";
-  return NULL;
-}
-
-uint32_t Field::Get32StaticFromCode(uint32_t field_idx, const Method* referrer) {
-  Field* field = FindStaticFieldFromCode(field_idx, referrer);
-  DCHECK(field->GetType()->PrimitiveSize() == sizeof(int32_t));
-  return field->Get32(NULL);
-}
-void Field::Set32StaticFromCode(uint32_t field_idx, const Method* referrer, uint32_t new_value) {
-  Field* field = FindStaticFieldFromCode(field_idx, referrer);
-  DCHECK(field->GetType()->PrimitiveSize() == sizeof(int32_t));
-  field->Set32(NULL, new_value);
-}
-uint64_t Field::Get64StaticFromCode(uint32_t field_idx, const Method* referrer) {
-  Field* field = FindStaticFieldFromCode(field_idx, referrer);
-  DCHECK(field->GetType()->PrimitiveSize() == sizeof(int64_t));
-  return field->Get64(NULL);
-}
-void Field::Set64StaticFromCode(uint32_t field_idx, const Method* referrer, uint64_t new_value) {
-  Field* field = FindStaticFieldFromCode(field_idx, referrer);
-  DCHECK(field->GetType()->PrimitiveSize() == sizeof(int64_t));
-  field->Set64(NULL, new_value);
-}
-Object* Field::GetObjStaticFromCode(uint32_t field_idx, const Method* referrer) {
-  Field* field = FindStaticFieldFromCode(field_idx, referrer);
-  DCHECK(!field->GetType()->IsPrimitive());
-  return field->GetObj(NULL);
-}
-void Field::SetObjStaticFromCode(uint32_t field_idx, const Method* referrer, Object* new_value) {
-  Field* field = FindStaticFieldFromCode(field_idx, referrer);
-  DCHECK(!field->GetType()->IsPrimitive());
-  field->SetObj(NULL, new_value);
-}
-
 uint32_t Field::Get32(const Object* object) const {
   CHECK((object == NULL) == IsStatic());
   if (IsStatic()) {
diff --git a/src/object.h b/src/object.h
index d8eb179..80a4ce9 100644
--- a/src/object.h
+++ b/src/object.h
@@ -471,10 +471,6 @@
     return MemberOffset(OFFSETOF_MEMBER(Field, offset_));
   }
 
-  static Field* FindInstanceFieldFromCode(uint32_t field_idx, const Method* referrer);
-  static Field* FindStaticFieldFromCode(uint32_t field_idx, const Method* referrer);
-  static Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, bool is_static);
-
   MemberOffset GetOffsetDuringLinking() const;
 
   void SetOffset(MemberOffset num_bytes);
@@ -499,20 +495,13 @@
   Object* GetObject(const Object* object) const;
   void SetObject(Object* object, const Object* l) const;
 
-  // Slow path routines for static field access when field was unresolved at
-  // compile time
-  static uint32_t Get32StaticFromCode(uint32_t field_idx,
-                                      const Method* referrer);
-  static void Set32StaticFromCode(uint32_t field_idx, const Method* referrer,
-                                  uint32_t new_value);
-  static uint64_t Get64StaticFromCode(uint32_t field_idx,
-                                      const Method* referrer);
-  static void Set64StaticFromCode(uint32_t field_idx, const Method* referrer,
-                                  uint64_t new_value);
-  static Object* GetObjStaticFromCode(uint32_t field_idx,
-                                      const Method* referrer);
-  static void SetObjStaticFromCode(uint32_t field_idx, const Method* referrer,
-                                   Object* new_value);
+  // raw field accesses
+  uint32_t Get32(const Object* object) const;
+  void Set32(Object* object, uint32_t new_value) const;
+  uint64_t Get64(const Object* object) const;
+  void Set64(Object* object, uint64_t new_value) const;
+  Object* GetObj(const Object* object) const;
+  void SetObj(Object* object, const Object* new_value) const;
 
   static Class* GetJavaLangReflectField() {
     DCHECK(java_lang_reflect_Field_ != NULL);
@@ -529,14 +518,6 @@
   void InitJavaFields();
 
  private:
-  // private implementation of field access using raw data
-  uint32_t Get32(const Object* object) const;
-  void Set32(Object* object, uint32_t new_value) const;
-  uint64_t Get64(const Object* object) const;
-  void Set64(Object* object, uint64_t new_value) const;
-  Object* GetObj(const Object* object) const;
-  void SetObj(Object* object, const Object* new_value) const;
-
   void InitJavaFieldsLocked();
 
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
diff --git a/src/object_test.cc b/src/object_test.cc
index 6979b75..6b1f818 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -10,6 +10,7 @@
 #include "common_test.h"
 #include "dex_file.h"
 #include "heap.h"
+#include "runtime_support.h"
 
 namespace art {
 
@@ -162,14 +163,12 @@
   TestPrimitiveArray<ShortArray>(class_linker_);
 }
 
-extern "C" Array* artCheckAndAllocArrayFromCode(uint32_t type_idx, Method* method,
-                                                int32_t component_count);
 TEST_F(ObjectTest, CheckAndAllocArrayFromCode) {
   // pretend we are trying to call 'new char[3]' from String.toCharArray
   Class* java_util_Arrays = class_linker_->FindSystemClass("Ljava/util/Arrays;");
   Method* sort = java_util_Arrays->FindDirectMethod("sort", "([I)V");
   uint32_t type_idx = FindTypeIdxByDescriptor(*java_lang_dex_file_.get(), "[I");
-  Object* array = artCheckAndAllocArrayFromCode(type_idx, sort, 3);
+  Object* array = CheckAndAllocArrayFromCode(type_idx, sort, 3, Thread::Current());
   EXPECT_TRUE(array->IsArrayInstance());
   EXPECT_EQ(3, array->AsArray()->GetLength());
   EXPECT_TRUE(array->GetClass()->IsArrayClass());
@@ -185,15 +184,16 @@
   Class* klass = class_linker_->FindClass("LStaticsFromCode;", class_loader);
   Method* clinit = klass->FindDirectMethod("<clinit>", "()V");
   uint32_t field_idx = FindFieldIdxByDescriptorAndName(*dex_file, "LStaticsFromCode;", "s0");
-  Object* s0 = Field::GetObjStaticFromCode(field_idx, clinit);
+  Field* field = FindFieldFromCode(field_idx, clinit, true);
+  Object* s0 = field->GetObj(NULL);
   EXPECT_EQ(NULL, s0);
 
   CharArray* char_array = CharArray::Alloc(0);
-  Field::SetObjStaticFromCode(field_idx, clinit, char_array);
-  EXPECT_EQ(char_array, Field::GetObjStaticFromCode(field_idx, clinit));
+  field->SetObj(NULL, char_array);
+  EXPECT_EQ(char_array, field->GetObj(NULL));
 
-  Field::SetObjStaticFromCode(field_idx, clinit, NULL);
-  EXPECT_EQ(NULL, Field::GetObjStaticFromCode(field_idx, clinit));
+  field->SetObj(NULL, NULL);
+  EXPECT_EQ(NULL, field->GetObj(NULL));
 
   // TODO: more exhaustive tests of all 6 cases of Field::*FromCode
 }
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 6a11e11..db6cbf0 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -22,6 +22,7 @@
 
 // Place a special frame at the TOS that will save the callee saves for the given type
 static void  FinishCalleeSaveFrameSetup(Thread* self, Method** sp, Runtime::CalleeSaveType type) {
+  // Be aware the store below may well stomp on an incoming argument
   *sp = Runtime::Current()->GetCalleeSaveMethod(type);
   self->SetTopOfStack(sp, 0);
 }
@@ -398,10 +399,135 @@
      */
 }
 
+Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, bool is_static) {
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  Field* f = class_linker->ResolveField(field_idx, referrer, is_static);
+  if (f != NULL) {
+    Class* c = f->GetDeclaringClass();
+    // If the class is already initializing, we must be inside <clinit>, or
+    // we'd still be waiting for the lock.
+    if (c->GetStatus() == Class::kStatusInitializing || class_linker->EnsureInitialized(c, true)) {
+      return f;
+    }
+  }
+  DCHECK(Thread::Current()->IsExceptionPending()); // Throw exception and unwind
+  return NULL;
+}
+
+extern "C" Field* artFindInstanceFieldFromCode(uint32_t field_idx, const Method* referrer,
+                                               Thread* self, Method** sp) {
+  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+  return FindFieldFromCode(field_idx, referrer, false);
+}
+
+extern "C" uint32_t artGet32StaticFromCode(uint32_t field_idx, const Method* referrer,
+                                           Thread* self, Method** sp) {
+  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+  Field* field = FindFieldFromCode(field_idx, referrer, true);
+  if (field != NULL) {
+    Class* type = field->GetType();
+    if (!type->IsPrimitive() || type->PrimitiveSize() != sizeof(int64_t)) {
+      self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
+                               "Attempted read of 32-bit primitive on field '%s'",
+                               PrettyField(field, true).c_str());
+    } else {
+      return field->Get32(NULL);
+    }
+  }
+  return 0;  // Will throw exception by checking with Thread::Current
+}
+
+extern "C" uint64_t artGet64StaticFromCode(uint32_t field_idx, const Method* referrer,
+                                           Thread* self, Method** sp) {
+  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+  Field* field = FindFieldFromCode(field_idx, referrer, true);
+  if (field != NULL) {
+    Class* type = field->GetType();
+    if (!type->IsPrimitive() || type->PrimitiveSize() != sizeof(int64_t)) {
+      self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
+                               "Attempted read of 64-bit primitive on field '%s'",
+                               PrettyField(field, true).c_str());
+    } else {
+      return field->Get64(NULL);
+    }
+  }
+  return 0;  // Will throw exception by checking with Thread::Current
+}
+
+extern "C" Object* artGetObjStaticFromCode(uint32_t field_idx, const Method* referrer,
+                                           Thread* self, Method** sp) {
+  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+  Field* field = FindFieldFromCode(field_idx, referrer, true);
+  if (field != NULL) {
+    Class* type = field->GetType();
+    if (type->IsPrimitive()) {
+      self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
+                               "Attempted read of reference on primitive field '%s'",
+                               PrettyField(field, true).c_str());
+    } else {
+      return field->GetObj(NULL);
+    }
+  }
+  return NULL;  // Will throw exception by checking with Thread::Current
+}
+
+extern "C" int artSet32StaticFromCode(uint32_t field_idx, const Method* referrer,
+                                       uint32_t new_value, Thread* self, Method** sp) {
+  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+  Field* field = FindFieldFromCode(field_idx, referrer, true);
+  if (field != NULL) {
+    Class* type = field->GetType();
+    if (!type->IsPrimitive() || type->PrimitiveSize() != sizeof(int32_t)) {
+      self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
+                               "Attempted write of 32-bit primitive to field '%s'",
+                               PrettyField(field, true).c_str());
+    } else {
+      field->Set32(NULL, new_value);
+      return 0;  // success
+    }
+  }
+  return -1;  // failure
+}
+
+extern "C" int artSet64StaticFromCode(uint32_t field_idx, const Method* referrer,
+                                      uint64_t new_value, Thread* self, Method** sp) {
+  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+  Field* field = FindFieldFromCode(field_idx, referrer, true);
+  if (field != NULL) {
+    Class* type = field->GetType();
+    if (!type->IsPrimitive() || type->PrimitiveSize() != sizeof(int64_t)) {
+      self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
+                               "Attempted write of 64-bit primitive to field '%s'",
+                               PrettyField(field, true).c_str());
+    } else {
+      field->Set64(NULL, new_value);
+      return 0;  // success
+    }
+  }
+  return -1;  // failure
+}
+
+extern "C" int artSetObjStaticFromCode(uint32_t field_idx, const Method* referrer,
+                                       Object* new_value, Thread* self, Method** sp) {
+  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+  Field* field = FindFieldFromCode(field_idx, referrer, true);
+  if (field != NULL) {
+    Class* type = field->GetType();
+    if (type->IsPrimitive()) {
+      self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
+                               "Attempted write of reference to primitive field '%s'",
+                               PrettyField(field, true).c_str());
+    } else {
+      field->SetObj(NULL, new_value);
+      return 0;  // success
+    }
+  }
+  return -1;  // failure
+}
+
 // Given the context of a calling Method, use its DexCache to resolve a type to a Class. If it
 // cannot be resolved, throw an error. If it can, use it to create an instance.
 extern "C" Object* artAllocObjectFromCode(uint32_t type_idx, Method* method, Thread* self, Method** sp) {
-  // Place a special frame at the TOS that will save all callee saves
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
   Runtime* runtime = Runtime::Current();
@@ -419,12 +545,10 @@
   return klass->AllocObject();
 }
 
-// Helper function to alloc array for OP_FILLED_NEW_ARRAY
-extern "C" Array* artCheckAndAllocArrayFromCode(uint32_t type_idx, Method* method,
-                                               int32_t component_count, Thread* self, Method** sp) {
+Array* CheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
+                                     Thread* self) {
   if (component_count < 0) {
-    Thread::Current()->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d",
-                                         component_count);
+    self->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d", component_count);
     return NULL;  // Failure
   }
   Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
@@ -452,6 +576,13 @@
   }
 }
 
+// Helper function to alloc array for OP_FILLED_NEW_ARRAY
+extern "C" Array* artCheckAndAllocArrayFromCode(uint32_t type_idx, Method* method,
+                                               int32_t component_count, Thread* self, Method** sp) {
+  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+  return CheckAndAllocArrayFromCode(type_idx, method, component_count, self);
+}
+
 // Given the context of a calling Method, use its DexCache to resolve a type to an array Class. If
 // it cannot be resolved, throw an error. If it can, use it to create an array.
 extern "C" Array* artAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 0a70c61..d05ece0 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -10,11 +10,15 @@
 
 namespace art {
 
+extern Array* CheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
+                                         Thread* self);
 extern void DebugMe(Method* method, uint32_t info);
 extern Object* DecodeJObjectInThread(Thread* thread, jobject obj);
+extern Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, bool is_static);
 extern void* FindNativeMethod(Thread* thread);
 extern void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method** sp);
 void* UnresolvedDirectMethodTrampolineFromCode(int32_t, void*, Thread*, Runtime::TrampolineType);
+extern Class* InitializeStaticStorage(uint32_t type_idx, const Method* referrer, Thread* self);
 extern Class* InitializeTypeFromCode(uint32_t type_idx, Method* method);
 extern void ResolveMethodFromCode(Method* method, uint32_t method_idx);
 extern void LockObjectFromCode(Thread* thread, Object* obj);
@@ -23,7 +27,6 @@
 extern int64_t F2L(float f);
 
 }  // namespace art
-
 /* Helper for both JNI and regular compiled code */
 extern "C" void art_deliver_exception_from_code(void*);
 
@@ -34,9 +37,17 @@
   extern "C" void* art_check_and_alloc_array_from_code(uint32_t, void*, int32_t);
   extern "C" void art_can_put_array_element_from_code(void*, void*);
   extern "C" void art_check_cast_from_code(void*, void*);
+  extern "C" void* art_find_instance_field_from_code(uint32_t, void*);
+  extern "C" void* art_find_static_field_from_code(uint32_t, void*);
+  extern "C" int32_t art_get32_static_from_code(uint32_t, void*);
+  extern "C" int64_t art_get64_static_from_code(uint32_t, void*);
+  extern "C" void* art_get_obj_static_from_code(uint32_t, void*);
   extern "C" void art_handle_fill_data_from_code(void*, void*);
   extern "C" void* art_initialize_static_storage_from_code(uint32_t, void*);
   extern "C" void art_invoke_interface_trampoline(uint32_t, void*);
+  extern "C" int art_set32_static_from_code(uint32_t, void*, int32_t);
+  extern "C" int art_set64_static_from_code(uint32_t, void*, int64_t);
+  extern "C" int art_set_obj_static_from_code(uint32_t, void*, void*);
   extern "C" void art_test_suspend();
   extern "C" void art_throw_array_bounds_from_code(int32_t index, int32_t limit);
   extern "C" void art_throw_div_zero_from_code();
diff --git a/src/runtime_support_asm.S b/src/runtime_support_asm.S
index 5b70fb7..d86d1fb 100644
--- a/src/runtime_support_asm.S
+++ b/src/runtime_support_asm.S
@@ -52,6 +52,17 @@
     pop {r1-r3, r5-r8, r10-r11, lr}  @ 10 words of callee saves
 .endm
 
+    /*
+     * Macro that set calls through to artDeliverPendingExceptionFromCode, where the pending
+     * exception is Thread::Current()->exception_
+     */
+.macro DELIVER_PENDING_EXCEPTION
+    SETUP_CALLEE_SAVE_FRAME                    @ save callee saves for throw
+    mov    r0, r9                              @ pass Thread::Current
+    mov    r1, sp                              @ pass SP
+    b      artDeliverPendingExceptionFromCode  @ artDeliverPendingExceptionFromCode(Thread*, SP)
+.endm
+
     .global art_deliver_exception_from_code
     /*
      * Called by managed code, saves mosts registers (forms basis of long jump context) and passes
@@ -156,10 +167,7 @@
     RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
     cmp    r0, #0                                 @ did we find the target?
     bxne   r12                                    @ tail call to target if so
-    SETUP_CALLEE_SAVE_FRAME                       @ set up for throwing exception
-    mov    r0, r9                                 @ pass Thread::Current
-    mov    r1, sp                                 @ pass SP
-    b      artDeliverPendingExceptionFromCode     @ artDeliverPendingExceptionFromCode(Thread*, SP)
+    DELIVER_PENDING_EXCEPTION
 
     .global art_handle_fill_data_from_code
     .extern artHandleFillArrayDataFromCode
@@ -175,10 +183,7 @@
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
     cmp    r0, #0                          @ success?
     moveq  pc, lr                          @ return on success
-    SETUP_CALLEE_SAVE_FRAME                @ set up for throwing exception
-    mov    r0, r9                          @ pass Thread::Current
-    mov    r1, sp                          @ pass SP
-    b      artDeliverPendingExceptionFromCode  @ artDeliverPendingExceptionFromCode(Thread*, SP)
+    DELIVER_PENDING_EXCEPTION
 
     .global art_lock_object_from_code
     .extern artLockObjectFromCode
@@ -205,10 +210,7 @@
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
     cmp    r0, #0                   @ success?
     moveq  pc, lr                   @ return on success
-    SETUP_CALLEE_SAVE_FRAME         @ set up for throwing exception
-    mov    r0, r9                   @ pass Thread::Current
-    mov    r1, sp                   @ pass SP
-    b      artDeliverPendingExceptionFromCode @ artDeliverPendingExceptionFromCode(Thread*, SP)
+    DELIVER_PENDING_EXCEPTION
 
     .global art_check_cast_from_code
     .extern artCheckCastFromCode
@@ -223,10 +225,7 @@
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
     cmp    r0, #0                       @ success?
     moveq  pc, lr                       @ return on success
-    SETUP_CALLEE_SAVE_FRAME             @ set up for throwing exception
-    mov    r0, r9                       @ pass Thread::Current
-    mov    r1, sp                       @ pass SP
-    b      artDeliverPendingExceptionFromCode  @ artDeliverPendingExceptionFromCode(Thread*, SP)
+    DELIVER_PENDING_EXCEPTION
 
     .global art_can_put_array_element_from_code
     .extern artCanPutArrayElementFromCode
@@ -244,10 +243,7 @@
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
     cmp    r0, #0                         @ success?
     moveq  pc, lr                         @ return on success
-    SETUP_CALLEE_SAVE_FRAME               @ set up for throwing exception
-    mov    r0, r9                         @ pass Thread::Current
-    mov    r1, sp                         @ pass SP
-    b      artDeliverPendingExceptionFromCode @ artDeliverPendingExceptionFromCode(Thread*, SP)
+    DELIVER_PENDING_EXCEPTION
 
     .global art_initialize_static_storage_from_code
     .extern artInitializeStaticStorageFromCode
@@ -265,10 +261,117 @@
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
     cmp    r0, #0                              @ success if result is non-null
     movne  pc, lr                              @ return on success
-    SETUP_CALLEE_SAVE_FRAME                    @ set up for throwing exception
-    mov    r0, r9                              @ pass Thread::Current
-    mov    r1, sp                              @ pass SP
-    b      artDeliverPendingExceptionFromCode  @ artDeliverPendingExceptionFromCode(Thread*, SP)
+    DELIVER_PENDING_EXCEPTION
+
+    .global art_find_instance_field_from_code
+    .extern artFindInstanceFieldFromCode
+    /*
+     * Called by managed code to resolve a field of an object
+     */
+art_find_instance_field_from_code:
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
+    mov    r2, r9                        @ pass Thread::Current
+    mov    r3, sp                        @ pass SP
+    bl     artFindInstanceFieldFromCode  @ (uint32_t field_idx, const Method* referrer, Thread*, SP)
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    cmp    r0, #0                        @ success if result is non-null
+    movne  pc, lr                        @ return on success
+    DELIVER_PENDING_EXCEPTION
+
+    .global art_get32_static_from_code
+    .extern artGet32StaticFromCode
+    /*
+     * Called by managed code to resolve a static field and load a 32-bit primitive value
+     */
+art_get32_static_from_code:
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
+    mov    r2, r9                        @ pass Thread::Current
+    mov    r3, sp                        @ pass SP
+    bl     artGet32StaticFromCode        @ (uint32_t field_idx, const Method* referrer, Thread*, SP)
+    ldr    r12, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    cmp    r12, #0                       @ success if no exception is pending
+    moveq  pc, lr                        @ return on success
+    DELIVER_PENDING_EXCEPTION
+
+    .global art_get64_static_from_code
+    .extern artGet64StaticFromCode
+    /*
+     * Called by managed code to resolve a static field and load a 64-bit primitive value
+     */
+art_get64_static_from_code:
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
+    mov    r2, r9                        @ pass Thread::Current
+    mov    r3, sp                        @ pass SP
+    bl     artGet64StaticFromCode        @ (uint32_t field_idx, const Method* referrer, Thread*, SP)
+    ldr    r12, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    cmp    r12, #0                       @ success if no exception is pending
+    moveq  pc, lr                        @ return on success
+    DELIVER_PENDING_EXCEPTION
+
+    .global art_get_obj_static_from_code
+    .extern artGetObjStaticFromCode
+    /*
+     * Called by managed code to resolve a static field and load an object reference
+     */
+art_get_obj_static_from_code:
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
+    mov    r2, r9                        @ pass Thread::Current
+    mov    r3, sp                        @ pass SP
+    bl     artGetObjStaticFromCode       @ (uint32_t field_idx, const Method* referrer, Thread*, SP)
+    ldr    r12, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    cmp    r12, #0                       @ success if no exception is pending
+    moveq  pc, lr                        @ return on success
+    DELIVER_PENDING_EXCEPTION
+
+    .global art_set32_static_from_code
+    .extern artSet32StaticFromCode
+    /*
+     * Called by managed code to resolve a static field and store a 32-bit primitive value
+     */
+art_set32_static_from_code:
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
+    mov    r3, r9                        @ pass Thread::Current
+    str    sp, [sp, #0]                  @ pass SP
+    bl     artSet32StaticFromCode        @ (field_idx, referrer, new_val, Thread*, SP)
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    cmp    r0, #0                        @ success if result is 0
+    moveq  pc, lr                        @ return on success
+    DELIVER_PENDING_EXCEPTION
+
+    .global art_set64_static_from_code
+    .extern artSet32StaticFromCode
+    /*
+     * Called by managed code to resolve a static field and store a 64-bit primitive value
+     */
+art_set64_static_from_code:
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
+    mov    r12, sp                       @ save SP
+    sub    sp, #8                        @ grow frame for alignment with stack args
+    push   {r9, r12}                     @ pass Thread::Current and SP
+    bl     artSet64StaticFromCode        @ (field_idx, referrer, new_val, Thread*, SP)
+    add    sp, #16                       @ release out args
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME   @ TODO: we can clearly save an add here
+    cmp    r0, #0                        @ success if result is 0
+    moveq  pc, lr                        @ return on success
+    DELIVER_PENDING_EXCEPTION
+
+    .global art_set_obj_static_from_code
+    .extern artSetObjStaticFromCode
+    /*
+     * Called by managed code to resolve a static field and store an object reference
+     */
+art_set_obj_static_from_code:
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
+    mov    r3, r9                        @ pass Thread::Current
+    str    sp, [sp, #0]                  @ pass SP
+    bl     artSetObjStaticFromCode       @ (field_idx, referrer, new_val, Thread*, SP)
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    cmp    r0, #0                        @ success if result is 0
+    moveq  pc, lr                        @ return on success
+    DELIVER_PENDING_EXCEPTION
 
     .global art_alloc_object_from_code
     .extern artAllocObjectFromCode
@@ -283,10 +386,7 @@
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
     cmp    r0, #0                     @ success if result is non-null
     movne  pc, lr                     @ return on success
-    SETUP_CALLEE_SAVE_FRAME           @ set up for throwing exception
-    mov    r0, r9                     @ pass Thread::Current
-    mov    r1, sp                     @ pass SP
-    b      artDeliverPendingExceptionFromCode  @ artDeliverPendingExceptionFromCode(Thread*, SP)
+    DELIVER_PENDING_EXCEPTION
 
     .global art_alloc_array_from_code
     .extern artAllocArrayFromCode
@@ -302,10 +402,7 @@
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
     cmp    r0, #0                     @ success if result is non-null
     movne  pc, lr                     @ return on success
-    SETUP_CALLEE_SAVE_FRAME           @ set up for throwing exception
-    mov    r0, r9                     @ pass Thread::Current
-    mov    r1, sp                     @ pass SP
-    b      artDeliverPendingExceptionFromCode  @ artDeliverPendingExceptionFromCode(Thread*, SP)
+    DELIVER_PENDING_EXCEPTION
 
     .global art_check_and_alloc_array_from_code
     .extern artCheckAndAllocArrayFromCode
@@ -319,12 +416,9 @@
     @ artCheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t count, Thread* , SP)
     bl     artCheckAndAllocArrayFromCode
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
-    cmp    r0, #0                         @ success if result is non-null
-    movne  pc, lr                         @ return on success
-    SETUP_CALLEE_SAVE_FRAME               @ set up for throwing exception
-    mov    r0, r9                         @ pass Thread::Current
-    mov    r1, sp                         @ pass SP
-    b      artDeliverPendingExceptionFromCode  @ artDeliverPendingExceptionFromCode(Thread*, SP)
+    cmp    r0, #0                     @ success if result is non-null
+    movne  pc, lr                     @ return on success
+    DELIVER_PENDING_EXCEPTION
 
     .global art_test_suspend
     .extern artCheckSuspendFromCode
diff --git a/src/thread.cc b/src/thread.cc
index b3dbcb6..079954b 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -110,9 +110,16 @@
   pCanPutArrayElementFromCode = art_can_put_array_element_from_code;
   pCheckAndAllocArrayFromCode = art_check_and_alloc_array_from_code;
   pCheckCastFromCode = art_check_cast_from_code;
+  pFindInstanceFieldFromCode = art_find_instance_field_from_code;
+  pGet32Static = art_get32_static_from_code;
+  pGet64Static = art_get64_static_from_code;
+  pGetObjStatic = art_get_obj_static_from_code;
   pHandleFillArrayDataFromCode = art_handle_fill_data_from_code;
   pInitializeStaticStorage = art_initialize_static_storage_from_code;
   pInvokeInterfaceTrampoline = art_invoke_interface_trampoline;
+  pSet32Static = art_set32_static_from_code;
+  pSet64Static = art_set64_static_from_code;
+  pSetObjStatic = art_set_obj_static_from_code;
   pTestSuspendFromCode = art_test_suspend;
   pThrowArrayBoundsFromCode = art_throw_array_bounds_from_code;
   pThrowDivZeroFromCode = art_throw_div_zero_from_code;
@@ -130,16 +137,9 @@
   pF2l = F2L;
   pD2l = D2L;
   pMemcpy = memcpy;
-  pGet32Static = Field::Get32StaticFromCode;
-  pSet32Static = Field::Set32StaticFromCode;
-  pGet64Static = Field::Get64StaticFromCode;
-  pSet64Static = Field::Set64StaticFromCode;
-  pGetObjStatic = Field::GetObjStaticFromCode;
-  pSetObjStatic = Field::SetObjStaticFromCode;
   pInitializeTypeFromCode = InitializeTypeFromCode;
   pResolveMethodFromCode = ResolveMethodFromCode;
   pInstanceofNonTrivialFromCode = Class::IsAssignableFromCode;
-  pFindInstanceFieldFromCode = Field::FindInstanceFieldFromCode;
   pCheckSuspendFromCode = artCheckSuspendFromJni;
   pFindNativeMethod = FindNativeMethod;
   pDecodeJObjectInThread = DecodeJObjectInThread;
diff --git a/src/thread.h b/src/thread.h
index c66e77e..12302ad 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -116,31 +116,32 @@
   int (*pIdiv)(int, int);
   long long (*pLmul)(long long, long long);
   long long (*pLdivmod)(long long, long long);
-  void* (*pUnresolvedDirectMethodTrampolineFromCode)(int32_t, void*, Thread*,
-      Runtime::TrampolineType);
   void* (*pAllocObjectFromCode)(uint32_t, void*);
   void* (*pAllocArrayFromCode)(uint32_t, void*, int32_t);
-  void* (*pCheckAndAllocArrayFromCode)(uint32_t, void*, int32_t);
-  uint32_t (*pGet32Static)(uint32_t, const Method*);
-  void (*pSet32Static)(uint32_t, const Method*, uint32_t);
-  uint64_t (*pGet64Static)(uint32_t, const Method*);
-  void (*pSet64Static)(uint32_t, const Method*, uint64_t);
-  Object* (*pGetObjStatic)(uint32_t, const Method*);
-  void (*pSetObjStatic)(uint32_t, const Method*, Object*);
   void (*pCanPutArrayElementFromCode)(void*, void*);
-  uint32_t (*pInstanceofNonTrivialFromCode) (const Class*, const Class*);
+  void* (*pCheckAndAllocArrayFromCode)(uint32_t, void*, int32_t);
   void (*pCheckCastFromCode) (void*, void*);
-  Method* (*pFindInterfaceMethodInCache)(Class*, uint32_t, const Method*, struct DvmDex*);
-  void (*pUnlockObjectFromCode)(void*);
-  void (*pLockObjectFromCode)(void*);
-  void (*pDeliverException)(void*);
-  void (*pHandleFillArrayDataFromCode)(void*, void*);
-  Class* (*pInitializeTypeFromCode)(uint32_t, Method*);
-  void (*pResolveMethodFromCode)(Method*, uint32_t);
-  void (*pInvokeInterfaceTrampoline)(uint32_t, void*);
-  void* (*pInitializeStaticStorage)(uint32_t, void*);
-  Field* (*pFindInstanceFieldFromCode)(uint32_t, const Method*);
   void (*pCheckSuspendFromCode)(Thread*);
+  Object* (*pDecodeJObjectInThread)(Thread* thread, jobject obj);
+  void (*pDeliverException)(void*);
+  void* (*pFindInstanceFieldFromCode)(uint32_t, void*);
+  Method* (*pFindInterfaceMethodInCache)(Class*, uint32_t, const Method*, struct DvmDex*);
+  void* (*pFindNativeMethod)(Thread* thread);
+  int32_t (*pGet32Static)(uint32_t, void*);
+  int64_t (*pGet64Static)(uint32_t, void*);
+  void* (*pGetObjStatic)(uint32_t, void*);
+  void (*pHandleFillArrayDataFromCode)(void*, void*);
+  void* (*pInitializeStaticStorage)(uint32_t, void*);
+  uint32_t (*pInstanceofNonTrivialFromCode) (const Class*, const Class*);
+  void (*pInvokeInterfaceTrampoline)(uint32_t, void*);
+  Class* (*pInitializeTypeFromCode)(uint32_t, Method*);
+  void (*pLockObjectFromCode)(void*);
+  void (*pObjectInit)(Object*);
+  void (*pResolveMethodFromCode)(Method*, uint32_t);
+  String* (*pResolveStringFromCode)(Method*, int32_t);
+  int (*pSet32Static)(uint32_t, void*, int32_t);
+  int (*pSet64Static)(uint32_t, void*, int64_t);
+  int (*pSetObjStatic)(uint32_t, void*, void*);
   void (*pTestSuspendFromCode)();
   void (*pThrowStackOverflowFromCode)(void*);
   void (*pThrowNullPointerFromCode)();
@@ -150,10 +151,9 @@
   void (*pThrowNegArraySizeFromCode)(int32_t);
   void (*pThrowNoSuchMethodFromCode)(int32_t);
   void (*pThrowAbstractMethodErrorFromCode)(Method* method, Thread* thread, Method** sp);
-  void* (*pFindNativeMethod)(Thread* thread);
-  Object* (*pDecodeJObjectInThread)(Thread* thread, jobject obj);
-  String* (*pResolveStringFromCode)(Method*, int32_t);
-  void (*pObjectInit)(Object*);
+  void (*pUnlockObjectFromCode)(void*);
+  void* (*pUnresolvedDirectMethodTrampolineFromCode)(int32_t, void*, Thread*,
+                                                     Runtime::TrampolineType);
 
   class StackVisitor {
    public:
diff --git a/src/thread_arm.cc b/src/thread_arm.cc
index a7efc1a..0196eb8 100644
--- a/src/thread_arm.cc
+++ b/src/thread_arm.cc
@@ -9,6 +9,7 @@
 
 void Thread::InitCpu() {
   CHECK_EQ(THREAD_SUSPEND_COUNT_OFFSET, OFFSETOF_MEMBER(Thread, suspend_count_));
+  CHECK_EQ(THREAD_EXCEPTION_OFFSET, OFFSETOF_MEMBER(Thread, exception_));
 }
 
 }  // namespace art