Implement java.lang.reflect.Constructor.constructNative.
Change-Id: Iefa92ad1bd89073d4bfa9a80b9e4f0dea90a5849
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_;