Implement reflective method invocation.

Change-Id: Ib3af9d7e00bf226398610b5ac6efbfe3eb2d15e8
diff --git a/src/java_lang_reflect_Field.cc b/src/java_lang_reflect_Field.cc
index c6abe53..5584da3 100644
--- a/src/java_lang_reflect_Field.cc
+++ b/src/java_lang_reflect_Field.cc
@@ -17,6 +17,7 @@
 #include "jni_internal.h"
 #include "class_linker.h"
 #include "object.h"
+#include "reflection.h"
 
 #include "JniConstants.h" // Last to avoid problems with LOG redefinition.
 
@@ -28,240 +29,6 @@
   return Decode<Object*>(env, jfield)->AsField()->GetAccessFlags() & kAccFieldFlagsMask;
 }
 
-// TODO: we'll need this for Method too.
-bool VerifyObjectInClass(JNIEnv* env, Object* o, Class* c) {
-  if (o == NULL) {
-    jniThrowNullPointerException(env, "receiver for non-static field access was null");
-    return false;
-  }
-  if (!o->InstanceOf(c)) {
-    std::string expectedClassName(PrettyDescriptor(c->GetDescriptor()));
-    std::string actualClassName(PrettyTypeOf(o));
-    jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
-        "expected receiver of type %s, but got %s",
-        expectedClassName.c_str(), actualClassName.c_str());
-    return false;
-  }
-  return true;
-}
-
-/*
- * Convert primitive, boxed data from "srcPtr" to "dstPtr".
- *
- * Section v2 2.6 lists the various conversions and promotions.  We
- * allow the "widening" and "identity" conversions, but don't allow the
- * "narrowing" conversions.
- *
- * Allowed:
- *  byte to short, int, long, float, double
- *  short to int, long, float double
- *  char to int, long, float, double
- *  int to long, float, double
- *  long to float, double
- *  float to double
- * Values of types byte, char, and short are "internally" widened to int.
- *
- * Returns the width in 32-bit words of the destination primitive, or
- * -1 if the conversion is not allowed.
- */
-bool ConvertPrimitiveValue(Class* src_class, Class* dst_class, const JValue& src, JValue& dst) {
-  Class::PrimitiveType srcType = src_class->GetPrimitiveType();
-  Class::PrimitiveType dstType = dst_class->GetPrimitiveType();
-  switch (dstType) {
-  case Class::kPrimBoolean:
-  case Class::kPrimChar:
-  case Class::kPrimByte:
-    if (srcType == dstType) {
-      dst.i = src.i;
-      return true;
-    }
-    break;
-  case Class::kPrimShort:
-    if (srcType == Class::kPrimByte || srcType == Class::kPrimShort) {
-      dst.i = src.i;
-      return true;
-    }
-    break;
-  case Class::kPrimInt:
-    if (srcType == Class::kPrimByte || srcType == Class::kPrimChar ||
-        srcType == Class::kPrimShort || srcType == Class::kPrimInt) {
-      dst.i = src.i;
-      return true;
-    }
-    break;
-  case Class::kPrimLong:
-    if (srcType == Class::kPrimByte || srcType == Class::kPrimChar ||
-        srcType == Class::kPrimShort || srcType == Class::kPrimInt) {
-      dst.j = src.i;
-      return true;
-    } else if (srcType == Class::kPrimLong) {
-      dst.j = src.j;
-      return true;
-    }
-    break;
-  case Class::kPrimFloat:
-    if (srcType == Class::kPrimByte || srcType == Class::kPrimChar ||
-        srcType == Class::kPrimShort || srcType == Class::kPrimInt) {
-      dst.f = src.i;
-      return true;
-    } else if (srcType == Class::kPrimLong) {
-      dst.f = src.j;
-      return true;
-    } else if (srcType == Class::kPrimFloat) {
-      dst.i = src.i;
-      return true;
-    }
-    break;
-  case Class::kPrimDouble:
-    if (srcType == Class::kPrimByte || srcType == Class::kPrimChar ||
-        srcType == Class::kPrimShort || srcType == Class::kPrimInt) {
-      dst.d = src.i;
-      return true;
-    } else if (srcType == Class::kPrimLong) {
-      dst.d = src.j;
-      return true;
-    } else if (srcType == Class::kPrimFloat) {
-      dst.d = src.f;
-      return true;
-    } else if (srcType == Class::kPrimDouble) {
-      dst.j = src.j;
-      return true;
-    }
-    break;
-  default:
-    break;
-  }
-  Thread::Current()->ThrowNewException("Ljava/lang/IllegalArgumentException;",
-      "invalid primitive conversion from %s to %s",
-      PrettyDescriptor(src_class->GetDescriptor()).c_str(),
-      PrettyDescriptor(dst_class->GetDescriptor()).c_str());
-  return false;
-}
-
-bool UnboxPrimitive(JNIEnv* env, Object* o, Class* dst_class, JValue& unboxed_value) {
-  if (dst_class->GetPrimitiveType() == Class::kPrimNot) {
-    if (o != NULL && !o->InstanceOf(dst_class)) {
-      jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
-          "expected object of type %s, but got %s",
-          PrettyDescriptor(dst_class->GetDescriptor()).c_str(),
-          PrettyTypeOf(o).c_str());
-      return false;
-    }
-    unboxed_value.l = o;
-    return true;
-  } else if (dst_class->GetPrimitiveType() == Class::kPrimVoid) {
-    Thread::Current()->ThrowNewException("Ljava/lang/IllegalArgumentException;",
-        "can't unbox to void");
-    return false;
-  }
-
-  if (o == NULL) {
-    Thread::Current()->ThrowNewException("Ljava/lang/IllegalArgumentException;",
-        "null passed for boxed primitive type");
-    return false;
-  }
-
-  JValue boxed_value = { 0 };
-  const String* src_descriptor = o->GetClass()->GetDescriptor();
-  Class* src_class = NULL;
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  Field* primitive_field = o->GetClass()->GetIFields()->Get(0);
-  if (src_descriptor->Equals("Ljava/lang/Boolean;")) {
-    src_class = class_linker->FindPrimitiveClass('Z');
-    boxed_value.z = primitive_field->GetBoolean(o);
-  } else if (src_descriptor->Equals("Ljava/lang/Byte;")) {
-    src_class = class_linker->FindPrimitiveClass('B');
-    boxed_value.b = primitive_field->GetByte(o);
-  } else if (src_descriptor->Equals("Ljava/lang/Character;")) {
-    src_class = class_linker->FindPrimitiveClass('C');
-    boxed_value.c = primitive_field->GetChar(o);
-  } else if (src_descriptor->Equals("Ljava/lang/Float;")) {
-    src_class = class_linker->FindPrimitiveClass('F');
-    boxed_value.f = primitive_field->GetFloat(o);
-  } else if (src_descriptor->Equals("Ljava/lang/Double;")) {
-    src_class = class_linker->FindPrimitiveClass('D');
-    boxed_value.d = primitive_field->GetDouble(o);
-  } else if (src_descriptor->Equals("Ljava/lang/Integer;")) {
-    src_class = class_linker->FindPrimitiveClass('I');
-    boxed_value.i = primitive_field->GetInt(o);
-  } else if (src_descriptor->Equals("Ljava/lang/Long;")) {
-    src_class = class_linker->FindPrimitiveClass('J');
-    boxed_value.j = primitive_field->GetLong(o);
-  } else if (src_descriptor->Equals("Ljava/lang/Short;")) {
-    src_class = class_linker->FindPrimitiveClass('S');
-    boxed_value.s = primitive_field->GetShort(o);
-  } else {
-    Thread::Current()->ThrowNewException("Ljava/lang/IllegalArgumentException;",
-        "%s is not a boxed primitive type", PrettyDescriptor(src_descriptor).c_str());
-    return false;
-  }
-
-  return ConvertPrimitiveValue(src_class, dst_class, boxed_value, unboxed_value);
-}
-
-Method* gBoolean_valueOf;
-Method* gByte_valueOf;
-Method* gCharacter_valueOf;
-Method* gDouble_valueOf;
-Method* gFloat_valueOf;
-Method* gInteger_valueOf;
-Method* gLong_valueOf;
-Method* gShort_valueOf;
-
-void InitBoxingMethod(JNIEnv* env, Method*& m, jclass c, const char* method_signature) {
-  m = DecodeMethod(env->GetStaticMethodID(c, "valueOf", method_signature));
-}
-
-void BoxPrimitive(JNIEnv* env, Class* src_class, JValue& value) {
-  if (!src_class->IsPrimitive()) {
-    return;
-  }
-
-  Method* m = NULL;
-  UniquePtr<byte[]> args(new byte[8]);
-  memset(&args[0], 0, 8);
-  switch (src_class->GetPrimitiveType()) {
-  case Class::kPrimBoolean:
-    m = gBoolean_valueOf;
-    *reinterpret_cast<uint32_t*>(&args[0]) = value.z;
-    break;
-  case Class::kPrimByte:
-    m = gByte_valueOf;
-    *reinterpret_cast<uint32_t*>(&args[0]) = value.b;
-    break;
-  case Class::kPrimChar:
-    m = gCharacter_valueOf;
-    *reinterpret_cast<uint32_t*>(&args[0]) = value.c;
-    break;
-  case Class::kPrimDouble:
-    m = gDouble_valueOf;
-    *reinterpret_cast<double*>(&args[0]) = value.d;
-    break;
-  case Class::kPrimFloat:
-    m = gFloat_valueOf;
-    *reinterpret_cast<float*>(&args[0]) = value.f;
-    break;
-  case Class::kPrimInt:
-    m = gInteger_valueOf;
-    *reinterpret_cast<uint32_t*>(&args[0]) = value.i;
-    break;
-  case Class::kPrimLong:
-    m = gLong_valueOf;
-    *reinterpret_cast<uint64_t*>(&args[0]) = value.j;
-    break;
-  case Class::kPrimShort:
-    m = gShort_valueOf;
-    *reinterpret_cast<uint32_t*>(&args[0]) = value.s;
-    break;
-  default:
-    LOG(FATAL) << PrettyClass(src_class);
-  }
-
-  Thread* self = Thread::Current();
-  ScopedThreadStateChange tsc(self, Thread::kRunnable);
-  m->Invoke(self, NULL, args.get(), &value);
-}
-
 bool GetFieldValue(Object* o, Field* f, JValue& value, bool allow_references) {
   switch (f->GetType()->GetPrimitiveType()) {
   case Class::kPrimBoolean:
@@ -305,7 +72,7 @@
 }
 
 JValue GetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jchar targetDescriptor) {
-  Field* f = reinterpret_cast<Field*>(env->FromReflectedField(javaField));
+  Field* f = DecodeField(env->FromReflectedField(javaField));
 
   // Check that the receiver is non-null and an instance of the field's declaring class.
   Object* o = Decode<Object*>(env, javaObj);
@@ -406,7 +173,7 @@
 }
 
 void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jchar targetDescriptor, const JValue& new_value) {
-  Field* f = reinterpret_cast<Field*>(env->FromReflectedField(javaField));
+  Field* f = DecodeField(env->FromReflectedField(javaField));
 
   // Check that the receiver is non-null and an instance of the field's declaring class.
   Object* o = Decode<Object*>(env, javaObj);
@@ -478,7 +245,7 @@
 }
 
 void Field_setField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jclass, jint, jboolean, jobject javaValue) {
-  Field* f = reinterpret_cast<Field*>(env->FromReflectedField(javaField));
+  Field* f = DecodeField(env->FromReflectedField(javaField));
 
   // Unbox the value, if necessary.
   Object* boxed_value = Decode<Object*>(env, javaValue);
@@ -501,7 +268,7 @@
 }
 
 jobject Field_getField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jclass, jint, jboolean) {
-  Field* f = reinterpret_cast<Field*>(env->FromReflectedField(javaField));
+  Field* f = DecodeField(env->FromReflectedField(javaField));
 
   // Check that the receiver is non-null and an instance of the field's declaring class.
   Object* o = Decode<Object*>(env, javaObj);
@@ -549,14 +316,7 @@
 }  // namespace
 
 void register_java_lang_reflect_Field(JNIEnv* env) {
-  InitBoxingMethod(env, gBoolean_valueOf, JniConstants::booleanClass, "(Z)Ljava/lang/Boolean;");
-  InitBoxingMethod(env, gByte_valueOf, JniConstants::byteClass, "(B)Ljava/lang/Byte;");
-  InitBoxingMethod(env, gCharacter_valueOf, JniConstants::characterClass, "(C)Ljava/lang/Character;");
-  InitBoxingMethod(env, gDouble_valueOf, JniConstants::doubleClass, "(D)Ljava/lang/Double;");
-  InitBoxingMethod(env, gFloat_valueOf, JniConstants::floatClass, "(F)Ljava/lang/Float;");
-  InitBoxingMethod(env, gInteger_valueOf, JniConstants::integerClass, "(I)Ljava/lang/Integer;");
-  InitBoxingMethod(env, gLong_valueOf, JniConstants::longClass, "(J)Ljava/lang/Long;");
-  InitBoxingMethod(env, gShort_valueOf, JniConstants::shortClass, "(S)Ljava/lang/Short;");
+  InitBoxingMethods(env); // TODO: move to Runtime?
   jniRegisterNativeMethods(env, "java/lang/reflect/Field", gMethods, NELEM(gMethods));
 }