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/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,