Class clean-up.
Move Class code out of native and into Java.
Remove ClassLinker::FindDexFile.
Change-Id: Idd9c4563d2c32e76690675242ff491276ace9848
diff --git a/src/native/java_lang_Class.cc b/src/native/java_lang_Class.cc
index 488df80..59c9bef 100644
--- a/src/native/java_lang_Class.cc
+++ b/src/native/java_lang_Class.cc
@@ -88,147 +88,6 @@
}
}
-// TODO: Remove this redundant struct when GCC annotalysis works correctly on top-level functions.
-struct WorkAroundGccAnnotalysisBug {
-template<typename T>
-static jobjectArray ToArray(const ScopedObjectAccessUnchecked& soa, const char* array_class_name,
- const std::vector<T*>& objects)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- ScopedLocalRef<jclass> array_class(soa.Env(), soa.Env()->FindClass(array_class_name));
- jobjectArray result = soa.Env()->NewObjectArray(objects.size(), array_class.get(), NULL);
- for (size_t i = 0; i < objects.size(); ++i) {
- ScopedLocalRef<jobject> object(soa.Env(), soa.AddLocalReference<jobject>(objects[i]));
- soa.Env()->SetObjectArrayElement(result, i, object.get());
- }
- return result;
-}
-};
-#define ToArray(a, b, c) WorkAroundGccAnnotalysisBug::ToArray(a, b, c)
-
-static bool IsVisibleConstructor(AbstractMethod* m, bool public_only) {
- if (public_only && !m->IsPublic()) {
- return false;
- }
- if (m->IsStatic()) {
- return false;
- }
- return m->IsConstructor();
-}
-
-static jobjectArray Class_getDeclaredConstructors(JNIEnv* env, jclass javaClass, jboolean publicOnly) {
- ScopedObjectAccess soa(env);
- Class* c = DecodeClass(soa, javaClass);
- std::vector<AbstractMethod*> constructors; // TODO: Use Constructor instead of AbstractMethod
- for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
- AbstractMethod* m = c->GetDirectMethod(i);
- if (IsVisibleConstructor(m, publicOnly)) {
- constructors.push_back(m);
- }
- }
-
- return ToArray(soa, "java/lang/reflect/Constructor", constructors);
-}
-
-static bool IsVisibleField(Field* f, bool public_only) {
- if (public_only && !f->IsPublic()) {
- return false;
- }
- return true;
-}
-
-static jobjectArray Class_getDeclaredFields(JNIEnv* env, jclass javaClass, jboolean publicOnly) {
- ScopedObjectAccess soa(env);
- Class* c = DecodeClass(soa, javaClass);
- std::vector<Field*> fields;
- FieldHelper fh;
- for (size_t i = 0; i < c->NumInstanceFields(); ++i) {
- Field* f = c->GetInstanceField(i);
- fh.ChangeField(f);
- if (IsVisibleField(f, publicOnly)) {
- if (fh.GetType() == NULL) {
- DCHECK(env->ExceptionOccurred());
- return NULL;
- }
- fields.push_back(f);
- }
- if (env->ExceptionOccurred()) {
- return NULL;
- }
- }
- for (size_t i = 0; i < c->NumStaticFields(); ++i) {
- Field* f = c->GetStaticField(i);
- fh.ChangeField(f);
- if (IsVisibleField(f, publicOnly)) {
- if (fh.GetType() == NULL) {
- DCHECK(env->ExceptionOccurred());
- return NULL;
- }
- fields.push_back(f);
- }
- if (env->ExceptionOccurred()) {
- return NULL;
- }
- }
-
- return ToArray(soa, "java/lang/reflect/Field", fields);
-}
-
-static bool IsVisibleMethod(AbstractMethod* m, bool public_only) {
- if (public_only && !m->IsPublic()) {
- return false;
- }
- if (m->IsConstructor()) {
- return false;
- }
- if (m->IsMiranda()) {
- return false;
- }
- return true;
-}
-
-static jobjectArray Class_getDeclaredMethods(JNIEnv* env, jclass javaClass, jboolean publicOnly) {
- ScopedObjectAccess soa(env);
- Class* c = DecodeClass(soa, javaClass);
- if (c == NULL) {
- return NULL;
- }
-
- std::vector<AbstractMethod*> methods;
- MethodHelper mh;
- for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
- AbstractMethod* m = c->GetVirtualMethod(i);
- mh.ChangeMethod(m);
- if (IsVisibleMethod(m, publicOnly)) {
- // TODO: the use of GetParameterTypes creates an unused array here.
- if (mh.GetReturnType() == NULL || mh.GetParameterTypes(soa.Self()) == NULL) {
- DCHECK(env->ExceptionOccurred());
- return NULL;
- }
- methods.push_back(m);
- }
- if (env->ExceptionOccurred()) {
- return NULL;
- }
- }
- for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
- AbstractMethod* m = c->GetDirectMethod(i);
- mh.ChangeMethod(m);
- if (IsVisibleMethod(m, publicOnly)) {
- // TODO: the use of GetParameterTypes creates an unused array here.
- if (mh.GetReturnType() == NULL || mh.GetParameterTypes(soa.Self()) == NULL) {
- DCHECK(env->ExceptionOccurred());
- return NULL;
- }
- methods.push_back(m);
- }
- if (env->ExceptionOccurred()) {
- return NULL;
- }
- }
-
- return ToArray(soa, "java/lang/reflect/Method", methods);
-}
-
static jobject Class_getDex(JNIEnv* env, jobject javaClass) {
ScopedObjectAccess soa(env);
Class* c = DecodeClass(soa, javaClass);
@@ -237,109 +96,11 @@
if (dex_cache == NULL) {
return NULL;
}
-
- return Runtime::Current()->GetClassLinker()->FindDexFile(dex_cache).GetDexObject(env);
-}
-
-static bool MethodMatches(MethodHelper* mh, const std::string& name, ObjectArray<Class>* arg_array)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- if (name != mh->GetName()) {
- return false;
- }
- const DexFile::TypeList* m_type_list = mh->GetParameterTypeList();
- uint32_t m_type_list_size = m_type_list == NULL ? 0 : m_type_list->Size();
- uint32_t sig_length = arg_array->GetLength();
-
- if (m_type_list_size != sig_length) {
- return false;
- }
-
- for (uint32_t i = 0; i < sig_length; i++) {
- if (mh->GetClassFromTypeIdx(m_type_list->GetTypeItem(i).type_idx_) != arg_array->Get(i)) {
- return false;
- }
- }
- return true;
-}
-
-static AbstractMethod* FindConstructorOrMethodInArray(ObjectArray<AbstractMethod>* methods,
- const std::string& name,
- ObjectArray<Class>* arg_array)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- if (methods == NULL) {
+ const DexFile* dex_file = dex_cache->GetDexFile();
+ if (dex_file == NULL) {
return NULL;
}
- AbstractMethod* result = NULL;
- MethodHelper mh;
- for (int32_t i = 0; i < methods->GetLength(); ++i) {
- AbstractMethod* method = methods->Get(i);
- mh.ChangeMethod(method);
- if (method->IsMiranda() || !MethodMatches(&mh, name, arg_array)) {
- continue;
- }
-
- result = method;
-
- // Covariant return types permit the class to define multiple
- // methods with the same name and parameter types. Prefer to return
- // a non-synthetic method in such situations. We may still return
- // a synthetic method to handle situations like escalated visibility.
- if (!method->IsSynthetic()) {
- break;
- }
- }
- return result;
-}
-
-static jobject Class_getDeclaredConstructorOrMethod(JNIEnv* env, jclass javaClass, jstring javaName,
- jobjectArray javaArgs) {
- ScopedObjectAccess soa(env);
- Class* c = DecodeClass(soa, javaClass);
- std::string name(soa.Decode<String*>(javaName)->ToModifiedUtf8());
- ObjectArray<Class>* arg_array = soa.Decode<ObjectArray<Class>*>(javaArgs);
-
- AbstractMethod* m = FindConstructorOrMethodInArray(c->GetDirectMethods(), name, arg_array);
- if (m == NULL) {
- m = FindConstructorOrMethodInArray(c->GetVirtualMethods(), name, arg_array);
- }
-
- if (m != NULL) {
- return soa.AddLocalReference<jobject>(m);
- } else {
- return NULL;
- }
-}
-
-static jobject Class_getDeclaredFieldNative(JNIEnv* env, jclass java_class, jobject jname) {
- ScopedObjectAccess soa(env);
- Class* c = DecodeClass(soa, java_class);
- String* name = soa.Decode<String*>(jname);
- DCHECK(name->GetClass()->IsStringClass());
-
- FieldHelper fh;
- for (size_t i = 0; i < c->NumInstanceFields(); ++i) {
- Field* f = c->GetInstanceField(i);
- fh.ChangeField(f);
- if (name->Equals(fh.GetName())) {
- if (fh.GetType() == NULL) {
- DCHECK(env->ExceptionOccurred());
- return NULL;
- }
- return soa.AddLocalReference<jclass>(f);
- }
- }
- for (size_t i = 0; i < c->NumStaticFields(); ++i) {
- Field* f = c->GetStaticField(i);
- fh.ChangeField(f);
- if (name->Equals(fh.GetName())) {
- if (fh.GetType() == NULL) {
- DCHECK(env->ExceptionOccurred());
- return NULL;
- }
- return soa.AddLocalReference<jclass>(f);
- }
- }
- return NULL;
+ return dex_file->GetDexObject(env);
}
static jstring Class_getNameNative(JNIEnv* env, jobject javaThis) {
@@ -354,91 +115,12 @@
return soa.AddLocalReference<jobjectArray>(c->GetInterfaces()->Clone(soa.Self()));
}
-static jboolean Class_isAssignableFrom(JNIEnv* env, jobject javaLhs, jclass javaRhs) {
- ScopedObjectAccess soa(env);
- Class* lhs = DecodeClass(soa, javaLhs);
- Class* rhs = soa.Decode<Class*>(javaRhs); // Can be null.
- if (rhs == NULL) {
- soa.Self()->ThrowNewException("Ljava/lang/NullPointerException;", "class == null");
- return JNI_FALSE;
- }
- return lhs->IsAssignableFrom(rhs) ? JNI_TRUE : JNI_FALSE;
-}
-
-static jobject Class_newInstanceImpl(JNIEnv* env, jobject javaThis) {
- ScopedObjectAccess soa(env);
- Class* c = DecodeClass(soa, javaThis);
- if (c->IsPrimitive() || c->IsInterface() || c->IsArrayClass() || c->IsAbstract()) {
- soa.Self()->ThrowNewExceptionF("Ljava/lang/InstantiationException;",
- "Class %s can not be instantiated", PrettyDescriptor(ClassHelper(c).GetDescriptor()).c_str());
- return NULL;
- }
-
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
- return NULL;
- }
-
- AbstractMethod* init = c->FindDeclaredDirectMethod("<init>", "()V");
- if (init == NULL) {
- soa.Self()->ThrowNewExceptionF("Ljava/lang/InstantiationException;",
- "Class %s has no default <init>()V constructor", PrettyDescriptor(ClassHelper(c).GetDescriptor()).c_str());
- return NULL;
- }
-
- // Verify access from the call site.
- //
- // First, make sure the method invoking Class.newInstance() has permission
- // to access the class.
- //
- // Second, make sure it has permission to invoke the constructor. The
- // constructor must be public or, if the caller is in the same package,
- // have package scope.
-
- NthCallerVisitor visitor(soa.Self()->GetManagedStack(), soa.Self()->GetTraceStack(), 2);
- visitor.WalkStack();
- Class* caller_class = visitor.caller->GetDeclaringClass();
-
- ClassHelper caller_ch(caller_class);
- if (!caller_class->CanAccess(c)) {
- soa.Self()->ThrowNewExceptionF("Ljava/lang/IllegalAccessException;",
- "Class %s is not accessible from class %s",
- PrettyDescriptor(ClassHelper(c).GetDescriptor()).c_str(),
- PrettyDescriptor(caller_ch.GetDescriptor()).c_str());
- return NULL;
- }
- if (!caller_class->CanAccessMember(init->GetDeclaringClass(), init->GetAccessFlags())) {
- soa.Self()->ThrowNewExceptionF("Ljava/lang/IllegalAccessException;",
- "%s is not accessible from class %s",
- PrettyMethod(init).c_str(),
- PrettyDescriptor(caller_ch.GetDescriptor()).c_str());
- return NULL;
- }
-
- Object* new_obj = c->AllocObject(soa.Self());
- if (new_obj == NULL) {
- DCHECK(soa.Self()->IsExceptionPending());
- return NULL;
- }
-
- // invoke constructor; unlike reflection calls, we don't wrap exceptions
- jclass java_class = soa.AddLocalReference<jclass>(c);
- jmethodID mid = soa.EncodeMethod(init);
- return env->NewObject(java_class, mid);
-}
-
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(Class, classForName, "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"),
NATIVE_METHOD(Class, getAnnotationDirectoryOffset, "()I"),
- NATIVE_METHOD(Class, getDeclaredConstructorOrMethod, "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Member;"),
- NATIVE_METHOD(Class, getDeclaredConstructors, "(Z)[Ljava/lang/reflect/Constructor;"),
- NATIVE_METHOD(Class, getDeclaredFieldNative, "(Ljava/lang/String;)Ljava/lang/reflect/Field;"),
- NATIVE_METHOD(Class, getDeclaredFields, "(Z)[Ljava/lang/reflect/Field;"),
- NATIVE_METHOD(Class, getDeclaredMethods, "(Z)[Ljava/lang/reflect/Method;"),
NATIVE_METHOD(Class, getDex, "()Lcom/android/dex/Dex;"),
NATIVE_METHOD(Class, getNameNative, "()Ljava/lang/String;"),
NATIVE_METHOD(Class, getProxyInterfaces, "()[Ljava/lang/Class;"),
- NATIVE_METHOD(Class, isAssignableFrom, "(Ljava/lang/Class;)Z"),
- NATIVE_METHOD(Class, newInstanceImpl, "()Ljava/lang/Object;"),
};
void register_java_lang_Class(JNIEnv* env) {