Implement java.lang.reflect.Constructor.constructNative.

Change-Id: Iefa92ad1bd89073d4bfa9a80b9e4f0dea90a5849
diff --git a/build/Android.common.mk b/build/Android.common.mk
index b921281..ce04683 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -111,6 +111,7 @@
 	src/java_lang_Throwable.cc \
 	src/java_lang_VMClassLoader.cc \
 	src/java_lang_reflect_Array.cc \
+	src/java_lang_reflect_Constructor.cc \
 	src/java_lang_reflect_Field.cc \
 	src/java_lang_reflect_Method.cc \
 	src/java_util_concurrent_atomic_AtomicLong.cc \
diff --git a/src/class_linker.cc b/src/class_linker.cc
index fb47c48..769a336 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -453,6 +453,17 @@
   init_done_ = true;
 }
 
+void ClassLinker::RunRootClinits() {
+  Thread* self = Thread::Current();
+  for (size_t i = 0; i < ClassLinker::kClassRootsMax; ++i) {
+    Class* c = GetClassRoot(ClassRoot(i));
+    if (!c->IsArrayClass() && !c->IsPrimitive()) {
+      EnsureInitialized(GetClassRoot(ClassRoot(i)), true);
+      CHECK(!self->IsExceptionPending());
+    }
+  }
+}
+
 struct ClassLinker::InitFromImageCallbackState {
   ClassLinker* class_linker;
 
diff --git a/src/class_linker.h b/src/class_linker.h
index 09736ce..317490a 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -157,6 +157,10 @@
   // given the restriction that no <clinit> execution is possible.
   bool EnsureInitialized(Class* c, bool can_run_clinit);
 
+  // Initializes classes that have instances in the image but that have
+  // <clinit> methods so they could not be initialized by the compiler.
+  void RunRootClinits();
+
   void RegisterDexFile(const DexFile& dex_file);
   void RegisterDexFile(const DexFile& dex_file, DexCache* dex_cache);
 
diff --git a/src/java_lang_Class.cc b/src/java_lang_Class.cc
index d77e3f0..7d1a4aa 100644
--- a/src/java_lang_Class.cc
+++ b/src/java_lang_Class.cc
@@ -368,6 +368,10 @@
     return NULL;
   }
 
+  if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true)) {
+    return NULL;
+  }
+
   Method* init = c->FindDirectMethod("<init>", "()V");
   if (init == NULL) {
     Thread::Current()->ThrowNewException("Ljava/lang/InstantiationException;",
diff --git a/src/java_lang_reflect_Constructor.cc b/src/java_lang_reflect_Constructor.cc
new file mode 100644
index 0000000..10a8f07
--- /dev/null
+++ b/src/java_lang_reflect_Constructor.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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 "jni_internal.h"
+#include "class_linker.h"
+#include "object.h"
+#include "reflection.h"
+
+#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
+
+namespace art {
+
+namespace {
+
+/*
+ * We get here through Constructor.newInstance().  The Constructor object
+ * would not be available if the constructor weren't public (per the
+ * definition of Class.getConstructor), so we can skip the method access
+ * check.  We can also safely assume the constructor isn't associated
+ * with an interface, array, or primitive class.
+ */
+jobject Constructor_constructNative(JNIEnv* env, jobject javaMethod, jobjectArray javaArgs, jclass javaDeclaringClass, jobjectArray javaParams, jint, jboolean) {
+  Class* c = Decode<Class*>(env, javaDeclaringClass);
+  if (c->IsAbstract()) {
+    Thread::Current()->ThrowNewException("Ljava/lang/InstantiationException;",
+        "Can't instantiate abstract class %s", PrettyDescriptor(c->GetDescriptor()).c_str());
+    return NULL;
+  }
+
+  Object* receiver = c->AllocObject();
+  if (receiver == NULL) {
+    return NULL;
+  }
+
+  jobject javaReceiver = AddLocalReference<jobject>(env, receiver);
+  InvokeMethod(env, javaMethod, javaReceiver, javaArgs, javaParams);
+
+  // Constructors are ()V methods, so we shouldn't touch the result of InvokeMethod.
+  return javaReceiver;
+}
+
+static JNINativeMethod gMethods[] = {
+  NATIVE_METHOD(Constructor, constructNative, "([Ljava/lang/Object;Ljava/lang/Class;[Ljava/lang/Class;IZ)Ljava/lang/Object;"),
+};
+
+}  // namespace
+
+void register_java_lang_reflect_Constructor(JNIEnv* env) {
+  jniRegisterNativeMethods(env, "java/lang/reflect/Constructor", gMethods, NELEM(gMethods));
+}
+
+}  // namespace art
diff --git a/src/java_lang_reflect_Method.cc b/src/java_lang_reflect_Method.cc
index 6ddb436..a988aac 100644
--- a/src/java_lang_reflect_Method.cc
+++ b/src/java_lang_reflect_Method.cc
@@ -25,10 +25,12 @@
 
 namespace {
 
-// We move the DECLARED_SYNCHRONIZED flag into the SYNCHRONIZED
-// position, because the callers of this function are trying to convey
-// the "traditional" meaning of the flags to their callers.
-uint32_t FixupMethodFlags(uint32_t access_flags) {
+jint Method_getMethodModifiers(JNIEnv* env, jclass, jclass javaDeclaringClass, jobject jmethod, jint slot) {
+  Method* m = Decode<Object*>(env, jmethod)->AsMethod();
+  jint access_flags = m->GetAccessFlags();
+  // We move the DECLARED_SYNCHRONIZED flag into the SYNCHRONIZED
+  // position, because the callers of this function are trying to convey
+  // the "traditional" meaning of the flags to their callers.
   access_flags &= ~kAccSynchronized;
   if ((access_flags & kAccDeclaredSynchronized) != 0) {
     access_flags |= kAccSynchronized;
@@ -36,72 +38,8 @@
   return access_flags & kAccMethodFlagsMask;
 }
 
-jint Method_getMethodModifiers(JNIEnv* env, jclass, jclass javaDeclaringClass, jobject jmethod, jint slot) {
-  return FixupMethodFlags(Decode<Object*>(env, jmethod)->AsMethod()->GetAccessFlags());
-}
-
-jobject Method_invokeNative(JNIEnv* env, jobject javaMethod, jobject javaReceiver, jobject javaArgs, jclass javaDeclaringClass, jobject javaParams, jclass, jint, jboolean) {
-  Thread* self = Thread::Current();
-  ScopedThreadStateChange tsc(self, Thread::kRunnable);
-
-  jmethodID mid = env->FromReflectedMethod(javaMethod);
-  Method* m = reinterpret_cast<Method*>(mid);
-  Object* receiver = NULL;
-  if (!m->IsStatic()) {
-    // Check that the receiver is non-null and an instance of the field's declaring class.
-    receiver = Decode<Object*>(env, javaReceiver);
-    Class* declaringClass = Decode<Class*>(env, javaDeclaringClass);
-    if (!VerifyObjectInClass(env, receiver, declaringClass)) {
-      return NULL;
-    }
-
-    // Find the actual implementation of the virtual method.
-    m = receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(m);
-  }
-
-  // Get our arrays of arguments and their types, and check they're the same size.
-  ObjectArray<Object>* objects = Decode<ObjectArray<Object>*>(env, javaArgs);
-  ObjectArray<Class>* classes = Decode<ObjectArray<Class>*>(env, javaParams);
-  int32_t arg_count = (objects != NULL) ? objects->GetLength() : 0;
-  if (arg_count != classes->GetLength()) {
-    self->ThrowNewException("Ljava/lang/IllegalArgumentException;",
-        "wrong number of arguments; expected %d, got %d",
-        classes->GetLength(), arg_count);
-    return NULL;
-  }
-
-  // Translate javaArgs to a jvalue[].
-  UniquePtr<jvalue[]> args(new jvalue[arg_count]);
-  JValue* decoded_args = reinterpret_cast<JValue*>(args.get());
-  for (int32_t i = 0; i < arg_count; ++i) {
-    Object* arg = objects->Get(i);
-    Class* dst_class = classes->Get(i);
-    if (dst_class->IsPrimitive()) {
-      if (!UnboxPrimitive(env, arg, dst_class, decoded_args[i])) {
-        return NULL;
-      }
-    } else {
-      args[i].l = AddLocalReference<jobject>(env, arg);
-    }
-  }
-
-  // Invoke the method.
-  JValue value = InvokeWithJValues(env, javaReceiver, mid, args.get());
-
-  // Wrap any exception with "Ljava/lang/reflect/InvocationTargetException;" and return early.
-  if (self->IsExceptionPending()) {
-    jthrowable th = env->ExceptionOccurred();
-    env->ExceptionClear();
-    jclass exception_class = env->FindClass("java/lang/reflect/InvocationTargetException");
-    jmethodID mid = env->GetMethodID(exception_class, "<init>", "(Ljava/lang/Throwable;)V");
-    jobject exception_instance = env->NewObject(exception_class, mid, th);
-    env->Throw(reinterpret_cast<jthrowable>(exception_instance));
-    return NULL;
-  }
-
-  // Box if necessary and return.
-  BoxPrimitive(env, m->GetReturnType(), value);
-  return AddLocalReference<jobject>(env, value.l);
+jobject Method_invokeNative(JNIEnv* env, jobject javaMethod, jobject javaReceiver, jobject javaArgs, jclass, jobject javaParams, jclass, jint, jboolean) {
+  return InvokeMethod(env, javaMethod, javaReceiver, javaArgs, javaParams);
 }
 
 static JNINativeMethod gMethods[] = {
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 8bc5081..fd6d314 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -2837,7 +2837,7 @@
       return NULL;
     }
   } else {
-    CHECK_GE(c->GetStatus(), Class::kStatusInitializing);
+    CHECK(c->GetStatus() >= Class::kStatusInitializing) << c->GetStatus() << " " << PrettyMethod(m);
   }
 
   std::string detail;
@@ -2848,8 +2848,7 @@
   }
   // throwing can cause libraries_lock to be reacquired
   if (native_method == NULL) {
-    Thread::Current()->ThrowNewException("Ljava/lang/UnsatisfiedLinkError;",
-        "%s", detail.c_str());
+    Thread::Current()->ThrowNewException("Ljava/lang/UnsatisfiedLinkError;", "%s", detail.c_str());
   }
   return native_method;
 }
diff --git a/src/reflection.cc b/src/reflection.cc
index 3edb9f7..c560053 100644
--- a/src/reflection.cc
+++ b/src/reflection.cc
@@ -48,6 +48,75 @@
   InitBoxingMethod(env, gShort_valueOf, JniConstants::shortClass, "(S)Ljava/lang/Short;");
 }
 
+jobject InvokeMethod(JNIEnv* env, jobject javaMethod, jobject javaReceiver, jobject javaArgs, jobject javaParams) {
+  Thread* self = Thread::Current();
+  ScopedThreadStateChange tsc(self, Thread::kRunnable);
+
+  jmethodID mid = env->FromReflectedMethod(javaMethod);
+  Method* m = reinterpret_cast<Method*>(mid);
+
+  Class* declaring_class = m->GetDeclaringClass();
+  if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(declaring_class, true)) {
+    return NULL;
+  }
+
+  Object* receiver = NULL;
+  if (!m->IsStatic()) {
+    // Check that the receiver is non-null and an instance of the field's declaring class.
+    receiver = Decode<Object*>(env, javaReceiver);
+    if (!VerifyObjectInClass(env, receiver, declaring_class)) {
+      return NULL;
+    }
+
+    // Find the actual implementation of the virtual method.
+    m = receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(m);
+  }
+
+  // Get our arrays of arguments and their types, and check they're the same size.
+  ObjectArray<Object>* objects = Decode<ObjectArray<Object>*>(env, javaArgs);
+  ObjectArray<Class>* classes = Decode<ObjectArray<Class>*>(env, javaParams);
+  int32_t arg_count = (objects != NULL) ? objects->GetLength() : 0;
+  if (arg_count != classes->GetLength()) {
+    self->ThrowNewException("Ljava/lang/IllegalArgumentException;",
+        "wrong number of arguments; expected %d, got %d",
+        classes->GetLength(), arg_count);
+    return NULL;
+  }
+
+  // Translate javaArgs to a jvalue[].
+  UniquePtr<jvalue[]> args(new jvalue[arg_count]);
+  JValue* decoded_args = reinterpret_cast<JValue*>(args.get());
+  for (int32_t i = 0; i < arg_count; ++i) {
+    Object* arg = objects->Get(i);
+    Class* dst_class = classes->Get(i);
+    if (dst_class->IsPrimitive()) {
+      if (!UnboxPrimitive(env, arg, dst_class, decoded_args[i])) {
+        return NULL;
+      }
+    } else {
+      args[i].l = AddLocalReference<jobject>(env, arg);
+    }
+  }
+
+  // Invoke the method.
+  JValue value = InvokeWithJValues(env, javaReceiver, mid, args.get());
+
+  // Wrap any exception with "Ljava/lang/reflect/InvocationTargetException;" and return early.
+  if (self->IsExceptionPending()) {
+    jthrowable th = env->ExceptionOccurred();
+    env->ExceptionClear();
+    jclass exception_class = env->FindClass("java/lang/reflect/InvocationTargetException");
+    jmethodID mid = env->GetMethodID(exception_class, "<init>", "(Ljava/lang/Throwable;)V");
+    jobject exception_instance = env->NewObject(exception_class, mid, th);
+    env->Throw(reinterpret_cast<jthrowable>(exception_instance));
+    return NULL;
+  }
+
+  // Box if necessary and return.
+  BoxPrimitive(env, m->GetReturnType(), value);
+  return AddLocalReference<jobject>(env, value.l);
+}
+
 bool VerifyObjectInClass(JNIEnv* env, Object* o, Class* c) {
   if (o == NULL) {
     jniThrowNullPointerException(env, "receiver for non-static field access was null");
diff --git a/src/reflection.h b/src/reflection.h
index 7256754..2d18331 100644
--- a/src/reflection.h
+++ b/src/reflection.h
@@ -31,6 +31,8 @@
 
 bool ConvertPrimitiveValue(Class* src_class, Class* dst_class, const JValue& src, JValue& dst);
 
+jobject InvokeMethod(JNIEnv* env, jobject method, jobject receiver, jobject args, jobject params);
+
 bool VerifyObjectInClass(JNIEnv* env, Object* o, Class* c);
 
 }  // namespace art
diff --git a/src/runtime.cc b/src/runtime.cc
index b1da77d..42bf874 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -365,20 +365,11 @@
 
   Thread::FinishStartup();
 
-  RunImageClinits();
+  class_linker_->RunRootClinits();
 
   StartDaemonThreads();
 }
 
-// initialize classes that have instances in the image but that have
-// <clinit> methods so they could not be initialized by the compiler.
-void Runtime::RunImageClinits() {
-  Class* Field_class = class_linker_->FindSystemClass("Ljava/lang/reflect/Field;");
-  CHECK(Field_class->FindDeclaredDirectMethod("<clinit>", "()V") != NULL);
-  class_linker_->EnsureInitialized(Field_class, true);
-  CHECK(!Thread::Current()->IsExceptionPending());
-}
-
 void Runtime::StartDaemonThreads() {
   signal_catcher_ = new SignalCatcher;
 
@@ -473,7 +464,7 @@
   REGISTER(register_java_lang_VMClassLoader);
   //REGISTER(register_java_lang_reflect_AccessibleObject);
   REGISTER(register_java_lang_reflect_Array);
-  //REGISTER(register_java_lang_reflect_Constructor);
+  REGISTER(register_java_lang_reflect_Constructor);
   REGISTER(register_java_lang_reflect_Field);
   REGISTER(register_java_lang_reflect_Method);
   //REGISTER(register_java_lang_reflect_Proxy);
diff --git a/src/runtime.h b/src/runtime.h
index ee5f524..a6916ac 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -193,7 +193,6 @@
   bool Init(const Options& options, bool ignore_unrecognized);
   void InitNativeMethods();
   void RegisterRuntimeNativeMethods(JNIEnv*);
-  void RunImageClinits();
   void StartDaemonThreads();
 
   std::string boot_class_path_;
diff --git a/test/SystemMethods/SystemMethods.java b/test/SystemMethods/SystemMethods.java
index 429755f..708a053 100644
--- a/test/SystemMethods/SystemMethods.java
+++ b/test/SystemMethods/SystemMethods.java
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+import java.lang.reflect.*;
+import java.util.*;
+
 class SystemMethods {
   public static int test0() {
     System.logI("hello world");
@@ -84,11 +87,14 @@
     return 123;
   }
 
-  private static int i = 4;
-  private static long j = 0x0123456789abcdefL;
-
-  private static float f = 3.14f;
+  private static boolean z = true;
+  private static byte b = 8;
+  private static char c = 'x';
   private static double d = Math.PI;
+  private static float f = 3.14f;
+  private static int i = 32;
+  private static long j = 0x0123456789abcdefL;
+  private static short s = 16;
 
   public static int test4() {
     String s = "int=" + i + " long=" + j;
@@ -119,7 +125,246 @@
     return 123;
   }
 
+  public static void test6() throws Exception {
+    java.lang.reflect.Field f;
+
+    f = SystemMethods.class.getDeclaredField("z");
+    System.out.println(f.getBoolean(null));
+    f = SystemMethods.class.getDeclaredField("b");
+    System.out.println(f.getByte(null));
+    f = SystemMethods.class.getDeclaredField("c");
+    System.out.println(f.getChar(null));
+    f = SystemMethods.class.getDeclaredField("d");
+    System.out.println(f.getDouble(null));
+    f = SystemMethods.class.getDeclaredField("f");
+    System.out.println(f.getFloat(null));
+    f = SystemMethods.class.getDeclaredField("i");
+    System.out.println(f.getInt(null));
+    f = SystemMethods.class.getDeclaredField("j");
+    System.out.println(f.getLong(null));
+    f = SystemMethods.class.getDeclaredField("s");
+    System.out.println(f.getShort(null));
+
+    f = SystemMethods.class.getDeclaredField("z");
+    f.setBoolean(null, false);
+    f = SystemMethods.class.getDeclaredField("b");
+    f.setByte(null, (byte) 7);
+    f = SystemMethods.class.getDeclaredField("c");
+    f.setChar(null, 'y');
+    f = SystemMethods.class.getDeclaredField("d");
+    f.setDouble(null, 2.7);
+    f = SystemMethods.class.getDeclaredField("f");
+    f.setFloat(null, 2.7f);
+    f = SystemMethods.class.getDeclaredField("i");
+    f.setInt(null, 31);
+    f = SystemMethods.class.getDeclaredField("j");
+    f.setLong(null, 63);
+    f = SystemMethods.class.getDeclaredField("s");
+    f.setShort(null, (short) 15);
+
+    f = SystemMethods.class.getDeclaredField("z");
+    System.out.println(f.getBoolean(null));
+    f = SystemMethods.class.getDeclaredField("b");
+    System.out.println(f.getByte(null));
+    f = SystemMethods.class.getDeclaredField("c");
+    System.out.println(f.getChar(null));
+    f = SystemMethods.class.getDeclaredField("d");
+    System.out.println(f.getDouble(null));
+    f = SystemMethods.class.getDeclaredField("f");
+    System.out.println(f.getFloat(null));
+    f = SystemMethods.class.getDeclaredField("i");
+    System.out.println(f.getInt(null));
+    f = SystemMethods.class.getDeclaredField("j");
+    System.out.println(f.getLong(null));
+    f = SystemMethods.class.getDeclaredField("s");
+    System.out.println(f.getShort(null));
+
+    f = SystemMethods.class.getDeclaredField("z");
+    f.set(null, Boolean.valueOf(true));
+    f = SystemMethods.class.getDeclaredField("b");
+    f.set(null, Byte.valueOf((byte) 6));
+    f = SystemMethods.class.getDeclaredField("c");
+    f.set(null, Character.valueOf('z'));
+    f = SystemMethods.class.getDeclaredField("d");
+    f.set(null, Double.valueOf(1.3));
+    f = SystemMethods.class.getDeclaredField("f");
+    f.set(null, Float.valueOf(1.3f));
+    f = SystemMethods.class.getDeclaredField("i");
+    f.set(null, Integer.valueOf(30));
+    f = SystemMethods.class.getDeclaredField("j");
+    f.set(null, Long.valueOf(62));
+    f.set(null, Integer.valueOf(62));
+    f = SystemMethods.class.getDeclaredField("s");
+    f.set(null, Short.valueOf((short) 14));
+
+    f = SystemMethods.class.getDeclaredField("z");
+    System.out.println(f.getBoolean(null));
+    f = SystemMethods.class.getDeclaredField("b");
+    System.out.println(f.getByte(null));
+    f = SystemMethods.class.getDeclaredField("c");
+    System.out.println(f.getChar(null));
+    f = SystemMethods.class.getDeclaredField("d");
+    System.out.println(f.getDouble(null));
+    f = SystemMethods.class.getDeclaredField("f");
+    System.out.println(f.getFloat(null));
+    f = SystemMethods.class.getDeclaredField("i");
+    System.out.println(f.getInt(null));
+    f = SystemMethods.class.getDeclaredField("j");
+    System.out.println(f.getLong(null));
+    f = SystemMethods.class.getDeclaredField("s");
+    System.out.println(f.getShort(null));
+
+    try {
+      f = SystemMethods.class.getDeclaredField("s");
+      f.set(null, Integer.valueOf(14));
+    } catch (Exception ex) {
+      ex.printStackTrace();
+    }
+
+    f = SystemMethods.class.getDeclaredField("z");
+    show(f.get(null));
+    f = SystemMethods.class.getDeclaredField("b");
+    show(f.get(null));
+    f = SystemMethods.class.getDeclaredField("c");
+    show(f.get(null));
+    f = SystemMethods.class.getDeclaredField("d");
+    show(f.get(null));
+    f = SystemMethods.class.getDeclaredField("f");
+    show(f.get(null));
+    f = SystemMethods.class.getDeclaredField("i");
+    show(f.get(null));
+    f = SystemMethods.class.getDeclaredField("j");
+    show(f.get(null));
+    f = SystemMethods.class.getDeclaredField("s");
+    show(f.get(null));
+
+    /*
+    private static boolean z = true;
+    private static byte b = 8;
+    private static char c = 'x';
+    private static double d = Math.PI;
+    private static float f = 3.14f;
+    private static int i = 32;
+    private static long j = 0x0123456789abcdefL;
+    private static short s = 16;
+    */
+  }
+
+  private static void show(Object o) {
+    System.out.println(o + " (" + (o != null ? o.getClass() : "null") + ")");
+  }
+
+  public static void test7() throws Exception {
+    System.out.println(Arrays.toString(String.class.getDeclaredConstructors()));
+    System.out.println(Arrays.toString(String.class.getDeclaredFields()));
+    System.out.println(Arrays.toString(String.class.getDeclaredMethods()));
+
+    System.out.println(Arrays.toString(SystemMethods.class.getInterfaces()));
+    System.out.println(Arrays.toString(String.class.getInterfaces()));
+
+//    System.out.println(SystemMethods.class.getModifiers());
+//    System.out.println(String.class.getModifiers());
+
+    System.out.println(String.class.isAssignableFrom(Object.class));
+    System.out.println(Object.class.isAssignableFrom(String.class));
+
+    System.out.println(String.class.isInstance("hello"));
+    System.out.println(String.class.isInstance(123));
+
+    java.lang.reflect.Method m;
+
+    m = SystemMethods.class.getDeclaredMethod("IV", int.class);
+    System.out.println(Arrays.toString(m.getParameterTypes()));
+    show(m.invoke(null, 4444));
+    System.out.println(Arrays.toString(m.getParameterTypes()));
+
+    m = SystemMethods.class.getDeclaredMethod("IIV", int.class, int.class);
+    System.out.println(Arrays.toString(m.getParameterTypes()));
+    show(m.invoke(null, 1111, 2222));
+
+    m = SystemMethods.class.getDeclaredMethod("III", int.class, int.class);
+    System.out.println(Arrays.toString(m.getParameterTypes()));
+    show(m.invoke(null, 1111, 2222));
+
+    m = SystemMethods.class.getDeclaredMethod("sumArray", int[].class);
+    System.out.println(Arrays.toString(m.getParameterTypes()));
+    show(m.invoke(null, new int[] { 1, 2, 3, 4 }));
+
+    m = SystemMethods.class.getDeclaredMethod("concat", String[].class);
+    System.out.println(Arrays.toString(m.getParameterTypes()));
+    show(m.invoke(null, (Object) new String[] { "h", "e", "l", "l", "o" }));
+
+    m = SystemMethods.class.getDeclaredMethod("ZBCDFIJSV", boolean.class, byte.class, char.class, double.class, float.class, int.class, long.class, short.class);
+    System.out.println(Arrays.toString(m.getParameterTypes()));
+    show(m.invoke(null, true, (byte) 0, '1', 2, 3, 4, 5, (short) 6));
+
+    m = SystemMethods.class.getDeclaredMethod("ZBCDLFIJSV", boolean.class, byte.class, char.class, double.class, String.class, float.class, int.class, long.class, short.class);
+    System.out.println(Arrays.toString(m.getParameterTypes()));
+    show(m.invoke(null, true, (byte) 0, '1', 2, "hello world", 3, 4, 5, (short) 6));
+
+    try {
+      m = SystemMethods.class.getDeclaredMethod("thrower");
+      System.out.println(Arrays.toString(m.getParameterTypes()));
+      show(m.invoke(null));
+      System.out.println("************* should have thrown!");
+    } catch (Exception ex) {
+      ex.printStackTrace();
+    }
+  }
+
+  private static void thrower() {
+    throw new ArithmeticException("surprise!");
+  }
+
+  public static int sumArray(int[] xs) {
+    int result = 0;
+    for (int x : xs) {
+      result += x;
+    }
+    return result;
+  }
+
+  public static String concat(String[] strings) {
+    String result = "";
+    for (String s : strings) {
+      result += s;
+    }
+    return result;
+  }
+
+  public static void IV(int i) {
+    System.out.println(i);
+  }
+
+  public static void IIV(int i, int j) {
+    System.out.println(i + " " + j);
+  }
+
+  public static int III(int i, int j) {
+    System.out.println(i + " " + j);
+    return i + j;
+  }
+
+  public static void ZBCDFIJSV(boolean z, byte b, char c, double d, float f, int i, long l, short s) {
+    System.out.println(z + " " + b + " " + c + " " + d + " " + f + " " + i + " " + l + " " + s);
+  }
+
+  public static void ZBCDLFIJSV(boolean z, byte b, char c, double d, String string, float f, int i, long l, short s) {
+    System.out.println(z + " " + b + " " + c + " " + d + " " + " " + string + " " + f + " " + i + " " + l + " " + s);
+  }
+
+  public static void test8() throws Exception {
+    Constructor<?> ctor;
+
+    ctor = String.class.getConstructor(new Class[0]);
+    show(ctor.newInstance((Object[]) null));
+
+    ctor = String.class.getConstructor(char[].class, int.class, int.class);
+    show(ctor.newInstance(new char[] { 'x', 'y', 'z', '!' }, 1, 2));
+  }
+
   public static void main(String[] args) throws Exception {
-    test5();
+    test7();
+    test8();
   }
 }