/* src/native/vm/reflect.c - helper functions for java/lang/reflect Copyright (C) 2007, 2008 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include #include "native/jni.h" #include "native/llni.h" #include "native/native.h" /* keep this order of the native includes */ #include "native/include/java_lang_String.h" #if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) # include "native/include/java_nio_ByteBuffer.h" /* required by j.l.CL */ #endif #include "native/include/java_lang_ClassLoader.h" #include "native/include/java_lang_Object.h" #include "native/include/java_lang_Class.h" #include "native/include/java_lang_reflect_Constructor.h" #include "native/include/java_lang_reflect_Field.h" #include "native/include/java_lang_reflect_Method.h" #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) # include "native/include/java_lang_reflect_VMConstructor.h" # include "native/include/java_lang_reflect_VMField.h" # include "native/include/java_lang_reflect_VMMethod.h" #endif #if defined(ENABLE_ANNOTATIONS) && defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) # include "vm/vm.hpp" # include "native/include/sun_reflect_ConstantPool.h" #endif #include "native/vm/reflect.h" #include "vm/access.h" #include "vm/builtin.h" #include "vm/exceptions.hpp" #include "vm/global.h" #include "vm/initialize.h" #include "vm/string.hpp" #include "vmcore/globals.hpp" #include "vmcore/method.h" /* reflect_constructor_new ***************************************************** Allocates a new java.lang.reflect.Constructor object and initializes the fields with the method passed. *******************************************************************************/ java_lang_reflect_Constructor *reflect_constructor_new(methodinfo *m) { java_handle_t *o; java_lang_reflect_Constructor *rc; int32_t slot; #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) java_lang_reflect_VMConstructor *rvmc; #endif /* Allocate a java.lang.reflect.Constructor object. */ o = builtin_new(class_java_lang_reflect_Constructor); if (o == NULL) return NULL; /* Initialize instance fields. */ rc = (java_lang_reflect_Constructor *) o; /* Calculate the slot. */ slot = m - m->clazz->methods; #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) /* Allocate a java.lang.reflect.VMConstructor object. */ o = builtin_new(class_java_lang_reflect_VMConstructor); if (o == NULL) return NULL; rvmc = (java_lang_reflect_VMConstructor *) o; /* Link the two Java objects. */ LLNI_field_set_ref(rc, cons, rvmc); LLNI_field_set_ref(rvmc, cons, rc); /* Set Java object instance fields. */ LLNI_field_set_cls(rvmc, clazz, m->clazz); LLNI_field_set_val(rvmc, slot, slot); LLNI_field_set_ref(rvmc, annotations, method_get_annotations(m)); LLNI_field_set_ref(rvmc, parameterAnnotations, method_get_parameterannotations(m)); #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) /* Set Java object instance fields. */ LLNI_field_set_cls(rc, clazz , m->clazz); LLNI_field_set_ref(rc, parameterTypes , method_get_parametertypearray(m)); LLNI_field_set_ref(rc, exceptionTypes , method_get_exceptionarray(m)); LLNI_field_set_val(rc, modifiers , m->flags & ACC_CLASS_REFLECT_MASK); LLNI_field_set_val(rc, slot , slot); LLNI_field_set_ref(rc, signature , m->signature ? (java_lang_String *) javastring_new(m->signature) : NULL); LLNI_field_set_ref(rc, annotations , method_get_annotations(m)); LLNI_field_set_ref(rc, parameterAnnotations, method_get_parameterannotations(m)); #else # error unknown classpath configuration #endif return rc; } /* reflect_field_new *********************************************************** Allocates a new java.lang.reflect.Field object and initializes the fields with the field passed. *******************************************************************************/ java_lang_reflect_Field *reflect_field_new(fieldinfo *f) { java_handle_t *o; java_lang_reflect_Field *rf; int32_t slot; #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) java_lang_reflect_VMField *rvmf; #endif /* Allocate a java.lang.reflect.Field object. */ o = builtin_new(class_java_lang_reflect_Field); if (o == NULL) return NULL; /* initialize instance fields */ rf = (java_lang_reflect_Field *) o; /* Calculate the slot. */ slot = f - f->clazz->fields; #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) /* Allocate a java.lang.reflect.VMField object. */ o = builtin_new(class_java_lang_reflect_VMField); if (o == NULL) return NULL; rvmf = (java_lang_reflect_VMField *) o; /* Link the two Java objects. */ LLNI_field_set_ref(rf, f, rvmf); LLNI_field_set_ref(rvmf, f, rf); /* Set the Java object fields. */ LLNI_field_set_cls(rvmf, clazz, f->clazz); /* The name needs to be interned */ /* XXX implement me better! */ LLNI_field_set_ref(rvmf, name, (java_lang_String *) javastring_intern(javastring_new(f->name))); LLNI_field_set_val(rvmf, slot, slot); LLNI_field_set_ref(rvmf, annotations, field_get_annotations(f)); #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) /* Set the Java object fields. */ LLNI_field_set_cls(rf, clazz, f->clazz); /* The name needs to be interned */ /* XXX implement me better! */ LLNI_field_set_ref(rf, name, (java_lang_String *) javastring_intern(javastring_new(f->name))); LLNI_field_set_cls(rf, type, (java_lang_Class *) field_get_type(f)); LLNI_field_set_val(rf, modifiers, f->flags); LLNI_field_set_val(rf, slot, slot); LLNI_field_set_ref(rf, signature, f->signature ? (java_lang_String *) javastring_new(f->signature) : NULL); LLNI_field_set_ref(rf, annotations, field_get_annotations(f)); #else # error unknown classpath configuration #endif return rf; } /* reflect_method_new ********************************************************** Allocates a new java.lang.reflect.Method object and initializes the fields with the method passed. *******************************************************************************/ java_lang_reflect_Method *reflect_method_new(methodinfo *m) { java_handle_t *o; java_lang_reflect_Method *rm; int32_t slot; #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) java_lang_reflect_VMMethod *rvmm; #endif /* Allocate a java.lang.reflect.Method object. */ o = builtin_new(class_java_lang_reflect_Method); if (o == NULL) return NULL; /* initialize instance fields */ rm = (java_lang_reflect_Method *) o; /* Calculate the slot. */ slot = m - m->clazz->methods; #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) /* Allocate a java.lang.reflect.VMMethod object. */ o = builtin_new(class_java_lang_reflect_VMMethod); if (o == NULL) return NULL; rvmm = (java_lang_reflect_VMMethod *) o; /* Link the two Java objects. */ LLNI_field_set_ref(rm, m, rvmm); LLNI_field_set_ref(rvmm, m, rm); /* Set Java object instance fields. */ LLNI_field_set_cls(rvmm, clazz, m->clazz); /* The name needs to be interned */ /* XXX implement me better! */ LLNI_field_set_ref(rvmm, name, (java_lang_String *) javastring_intern(javastring_new(m->name))); LLNI_field_set_val(rvmm, slot, slot); LLNI_field_set_ref(rvmm, annotations, method_get_annotations(m)); LLNI_field_set_ref(rvmm, parameterAnnotations, method_get_parameterannotations(m)); LLNI_field_set_ref(rvmm, annotationDefault, method_get_annotationdefault(m)); #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) LLNI_field_set_cls(rm, clazz, m->clazz); /* The name needs to be interned */ /* XXX implement me better! */ LLNI_field_set_ref(rm, name, (java_lang_String *) javastring_intern(javastring_new(m->name))); LLNI_field_set_ref(rm, parameterTypes, method_get_parametertypearray(m)); LLNI_field_set_cls(rm, returnType, (java_lang_Class *) method_returntype_get(m)); LLNI_field_set_ref(rm, exceptionTypes, method_get_exceptionarray(m)); LLNI_field_set_val(rm, modifiers, m->flags & ACC_CLASS_REFLECT_MASK); LLNI_field_set_val(rm, slot, slot); LLNI_field_set_ref(rm, signature, m->signature ? (java_lang_String *) javastring_new(m->signature) : NULL); LLNI_field_set_ref(rm, annotations, method_get_annotations(m)); LLNI_field_set_ref(rm, parameterAnnotations, method_get_parameterannotations(m)); LLNI_field_set_ref(rm, annotationDefault, method_get_annotationdefault(m)); #else # error unknown classpath configuration #endif return rm; } /* reflect_invoke ************************************************************** Invoke a method on the given object with the given arguments. For instance methods OBJ must be != NULL and the method is looked up in the vftbl of the object. For static methods, OBJ is ignored. *******************************************************************************/ static java_handle_t *reflect_invoke(methodinfo *m, java_handle_t *o, java_handle_objectarray_t *params) { methodinfo *resm; java_handle_t *ro; int argcount; int paramcount; /* Sanity check. */ assert(m != NULL); argcount = m->parseddesc->paramcount; paramcount = argcount; /* If method is non-static, remove the `this' pointer. */ if (!(m->flags & ACC_STATIC)) paramcount--; /* For instance methods the object has to be an instance of the class the method belongs to. For static methods the obj parameter is ignored. */ if (!(m->flags & ACC_STATIC) && o && (!builtin_instanceof(o, m->clazz))) { exceptions_throw_illegalargumentexception(); return NULL; } /* check if we got the right number of arguments */ if (((params == NULL) && (paramcount != 0)) || (params && (LLNI_array_size(params) != paramcount))) { exceptions_throw_illegalargumentexception(); return NULL; } /* for instance methods we need an object */ if (!(m->flags & ACC_STATIC) && (o == NULL)) { /* XXX not sure if that is the correct exception */ exceptions_throw_nullpointerexception(); return NULL; } /* for static methods, zero object to make subsequent code simpler */ if (m->flags & ACC_STATIC) o = NULL; if (o != NULL) { /* for instance methods we must do a vftbl lookup */ resm = method_vftbl_lookup(LLNI_vftbl_direct(o), m); } else { /* for static methods, just for convenience */ resm = m; } ro = vm_call_method_objectarray(resm, o, params); return ro; } /* reflect_constructor_newinstance ******************************************** Creates an Java object instance of the given constructor. ARGUMENTS: m .......... methodinfo of the constructor args ....... constructor arguments override ... override security checks RETURN: constructed Java object *******************************************************************************/ java_handle_t *reflect_constructor_newinstance(methodinfo *m, java_handle_objectarray_t *args, bool override) { java_handle_t *o; /* Should we bypass security the checks (AccessibleObject)? */ if (override == false) { /* This method is always called like this: [0] java.lang.reflect.Constructor.constructNative (Native Method) [1] java.lang.reflect.Constructor.newInstance [2] */ if (!access_check_method(m, 2)) return NULL; } /* Create a Java object. */ o = builtin_new(m->clazz); if (o == NULL) return NULL; /* Call initializer. */ (void) reflect_invoke(m, o, args); return o; } /* reflect_method_invoke ******************************************************* Invokes the given method. ARGUMENTS: m .......... methodinfo args ....... method arguments override ... override security checks RETURN: return value of the method *******************************************************************************/ java_handle_t *reflect_method_invoke(methodinfo *m, java_handle_t *o, java_handle_objectarray_t *args, bool override) { java_handle_t *ro; /* Should we bypass security the checks (AccessibleObject)? */ if (override == false) { #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) /* This method is always called like this: [0] java.lang.reflect.Method.invokeNative (Native Method) [1] java.lang.reflect.Method.invoke (Method.java:329) [2] */ if (!access_check_method(m, 2)) return NULL; #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) /* We only pass 1 here as stacktrace_get_caller_class, which is called from access_check_method, skips java.lang.reflect.Method.invoke(). */ if (!access_check_method(m, 1)) return NULL; #else # error unknown classpath configuration #endif } /* Check if method class is initialized. */ if (!(m->clazz->state & CLASS_INITIALIZED)) if (!initialize_class(m->clazz)) return NULL; /* Call the Java method. */ ro = reflect_invoke(m, o, args); return ro; } #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) && defined(ENABLE_ANNOTATIONS) /* reflect_get_declaredannotations ********************************************* Calls the annotation parser with the unparsed annotations and returnes the parsed annotations as a map. IN: annotations........the unparsed annotations declaringClass.....the class in which the annotated element is declared referer............the calling class (for the 'referer' parameter of vm_call_method()) RETURN VALUE: The parsed annotations as a java.util.Map, Annotation>. *******************************************************************************/ struct java_util_Map* reflect_get_declaredannotations( java_handle_bytearray_t *annotations, classinfo *declaringClass, classinfo *referer) { static methodinfo *m_parseAnnotations = NULL; /* parser method (chached, therefore static) */ utf *utf_parseAnnotations = NULL; /* parser method name */ utf *utf_desc = NULL; /* parser method descriptor (signature) */ sun_reflect_ConstantPool *constantPool = NULL; /* constant pool of the declaring class */ java_lang_Object *constantPoolOop = (java_lang_Object*)declaringClass; /* constantPoolOop field of the constant pool */ /* object (sun.reflect.ConstantPool) */ constantPool = (sun_reflect_ConstantPool*)native_new_and_init( class_sun_reflect_ConstantPool); if(constantPool == NULL) { /* out of memory */ return NULL; } LLNI_field_set_ref(constantPool, constantPoolOop, constantPoolOop); /* only resolve the parser method the first time */ if (m_parseAnnotations == NULL) { utf_parseAnnotations = utf_new_char("parseAnnotations"); utf_desc = utf_new_char( "([BLsun/reflect/ConstantPool;Ljava/lang/Class;)" "Ljava/util/Map;"); if (utf_parseAnnotations == NULL || utf_desc == NULL) { /* out of memory */ return NULL; } m_parseAnnotations = class_resolveclassmethod( class_sun_reflect_annotation_AnnotationParser, utf_parseAnnotations, utf_desc, referer, true); if (m_parseAnnotations == NULL) { /* method not found */ return NULL; } } return (struct java_util_Map*)vm_call_method( m_parseAnnotations, NULL, annotations, constantPool, declaringClass); } /* reflect_get_parameterannotations ******************************************* Calls the annotation parser with the unparsed parameter annotations of a method and returnes the parsed parameter annotations in a 2 dimensional array. IN: parameterAnnotations....the unparsed parameter annotations slot....................the slot of the method declaringClass..........the class in which the annotated element is declared referer.................the calling class (for the 'referer' parameter of vm_call_method()) RETURN VALUE: The parsed parameter annotations in a 2 dimensional array. *******************************************************************************/ java_handle_objectarray_t* reflect_get_parameterannotations( java_handle_t *parameterAnnotations, methodinfo *m, classinfo *referer) { /* This method in java would be basically the following. * We don't do it in java because we don't want to make a * public method with wich you can get a ConstantPool, because * with that you could read any kind of constants (even private * ones). * * ConstantPool constPool = new ConstantPool(); * constPool.constantPoolOop = method.getDeclaringClass(); * return sun.reflect.AnnotationParser.parseParameterAnnotations( * parameterAnnotations, * constPool, * method.getDeclaringClass(), * method.getParameterTypes().length); */ static methodinfo *m_parseParameterAnnotations = NULL; /* parser method (cached, therefore static) */ utf *utf_parseParameterAnnotations = NULL; /* parser method name */ utf *utf_desc = NULL; /* parser method descriptor (signature) */ sun_reflect_ConstantPool *constantPool = NULL; /* constant pool of the declaring class */ int32_t numParameters = -1; /* parameter count of the annotated method */ /* get parameter count */ numParameters = method_get_parametercount(m); if (numParameters < 0) { /* error parsing descriptor */ return NULL; } /* get ConstantPool */ constantPool = (sun_reflect_ConstantPool*)native_new_and_init( class_sun_reflect_ConstantPool); if(constantPool == NULL) { /* out of memory */ return NULL; } // XXX I'm not sure what the correct LLNI macro would be. LLNI_field_set_cls(constantPool, constantPoolOop, (java_lang_Object*) m->clazz); /* only resolve the parser method the first time */ if (m_parseParameterAnnotations == NULL) { utf_parseParameterAnnotations = utf_new_char("parseParameterAnnotations"); utf_desc = utf_new_char( "([BLsun/reflect/ConstantPool;Ljava/lang/Class;I)" "[[Ljava/lang/annotation/Annotation;"); if (utf_parseParameterAnnotations == NULL || utf_desc == NULL) { /* out of memory */ return NULL; } /* get parser method */ m_parseParameterAnnotations = class_resolveclassmethod( class_sun_reflect_annotation_AnnotationParser, utf_parseParameterAnnotations, utf_desc, referer, true); if (m_parseParameterAnnotations == NULL) { /* method not found */ return NULL; } } return (java_handle_objectarray_t*)vm_call_method( m_parseParameterAnnotations, NULL, parameterAnnotations, constantPool, m->clazz, numParameters); } #endif /* * These are local overrides for various environment variables in Emacs. * Please do not remove this and leave it at the end of the file, where * Emacs will automagically detect them. * --------------------------------------------------------------------- * Local variables: * mode: c * indent-tabs-mode: t * c-basic-offset: 4 * tab-width: 4 * End: * vim:noexpandtab:sw=4:ts=4: */