1 /* src/native/vm/reflect.c - helper functions for java/lang/reflect
3 Copyright (C) 2007, 2008
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
6 This file is part of CACAO.
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2, or (at
11 your option) any later version.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
30 #include "native/jni.h"
31 #include "native/llni.h"
32 #include "native/native.h"
34 /* keep this order of the native includes */
36 #include "native/include/java_lang_String.h"
38 #if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
39 # include "native/include/java_nio_ByteBuffer.h" /* required by j.l.CL */
41 #include "native/include/java_lang_ClassLoader.h"
43 #include "native/include/java_lang_Object.h"
44 #include "native/include/java_lang_Class.h"
45 #include "native/include/java_lang_reflect_Constructor.h"
46 #include "native/include/java_lang_reflect_Field.h"
47 #include "native/include/java_lang_reflect_Method.h"
49 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
50 # include "native/include/java_lang_reflect_VMConstructor.h"
51 # include "native/include/java_lang_reflect_VMField.h"
52 # include "native/include/java_lang_reflect_VMMethod.h"
55 #if defined(ENABLE_ANNOTATIONS) && defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
57 # include "native/include/sun_reflect_ConstantPool.h"
60 #include "native/vm/reflect.h"
62 #include "vm/access.h"
63 #include "vm/builtin.h"
64 #include "vm/exceptions.hpp"
65 #include "vm/global.h"
66 #include "vm/initialize.h"
67 #include "vm/string.hpp"
69 #include "vmcore/globals.hpp"
70 #include "vmcore/method.h"
73 /* reflect_constructor_new *****************************************************
75 Allocates a new java.lang.reflect.Constructor object and
76 initializes the fields with the method passed.
78 *******************************************************************************/
80 java_lang_reflect_Constructor *reflect_constructor_new(methodinfo *m)
83 java_lang_reflect_Constructor *rc;
86 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
87 java_lang_reflect_VMConstructor *rvmc;
90 /* Allocate a java.lang.reflect.Constructor object. */
92 o = builtin_new(class_java_lang_reflect_Constructor);
97 /* Initialize instance fields. */
99 rc = (java_lang_reflect_Constructor *) o;
101 /* Calculate the slot. */
103 slot = m - m->clazz->methods;
105 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
107 /* Allocate a java.lang.reflect.VMConstructor object. */
109 o = builtin_new(class_java_lang_reflect_VMConstructor);
114 rvmc = (java_lang_reflect_VMConstructor *) o;
116 /* Link the two Java objects. */
118 LLNI_field_set_ref(rc, cons, rvmc);
119 LLNI_field_set_ref(rvmc, cons, rc);
121 /* Set Java object instance fields. */
123 LLNI_field_set_cls(rvmc, clazz, m->clazz);
124 LLNI_field_set_val(rvmc, slot, slot);
125 LLNI_field_set_ref(rvmc, annotations, method_get_annotations(m));
126 LLNI_field_set_ref(rvmc, parameterAnnotations, method_get_parameterannotations(m));
128 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
130 /* Set Java object instance fields. */
132 LLNI_field_set_cls(rc, clazz , m->clazz);
133 LLNI_field_set_ref(rc, parameterTypes , method_get_parametertypearray(m));
134 LLNI_field_set_ref(rc, exceptionTypes , method_get_exceptionarray(m));
135 LLNI_field_set_val(rc, modifiers , m->flags & ACC_CLASS_REFLECT_MASK);
136 LLNI_field_set_val(rc, slot , slot);
137 LLNI_field_set_ref(rc, signature , m->signature ? (java_lang_String *) javastring_new(m->signature) : NULL);
138 LLNI_field_set_ref(rc, annotations , method_get_annotations(m));
139 LLNI_field_set_ref(rc, parameterAnnotations, method_get_parameterannotations(m));
142 # error unknown classpath configuration
149 /* reflect_field_new ***********************************************************
151 Allocates a new java.lang.reflect.Field object and initializes the
152 fields with the field passed.
154 *******************************************************************************/
156 java_lang_reflect_Field *reflect_field_new(fieldinfo *f)
159 java_lang_reflect_Field *rf;
162 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
163 java_lang_reflect_VMField *rvmf;
166 /* Allocate a java.lang.reflect.Field object. */
168 o = builtin_new(class_java_lang_reflect_Field);
173 /* initialize instance fields */
175 rf = (java_lang_reflect_Field *) o;
177 /* Calculate the slot. */
179 slot = f - f->clazz->fields;
181 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
183 /* Allocate a java.lang.reflect.VMField object. */
185 o = builtin_new(class_java_lang_reflect_VMField);
190 rvmf = (java_lang_reflect_VMField *) o;
192 /* Link the two Java objects. */
194 LLNI_field_set_ref(rf, f, rvmf);
195 LLNI_field_set_ref(rvmf, f, rf);
197 /* Set the Java object fields. */
199 LLNI_field_set_cls(rvmf, clazz, f->clazz);
201 /* The name needs to be interned */
202 /* XXX implement me better! */
204 LLNI_field_set_ref(rvmf, name, (java_lang_String *) javastring_intern(javastring_new(f->name)));
205 LLNI_field_set_val(rvmf, slot, slot);
206 LLNI_field_set_ref(rvmf, annotations, field_get_annotations(f));
208 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
210 /* Set the Java object fields. */
212 LLNI_field_set_cls(rf, clazz, f->clazz);
214 /* The name needs to be interned */
215 /* XXX implement me better! */
217 LLNI_field_set_ref(rf, name, (java_lang_String *) javastring_intern(javastring_new(f->name)));
218 LLNI_field_set_cls(rf, type, (java_lang_Class *) field_get_type(f));
219 LLNI_field_set_val(rf, modifiers, f->flags);
220 LLNI_field_set_val(rf, slot, slot);
221 LLNI_field_set_ref(rf, signature, f->signature ? (java_lang_String *) javastring_new(f->signature) : NULL);
222 LLNI_field_set_ref(rf, annotations, field_get_annotations(f));
225 # error unknown classpath configuration
232 /* reflect_method_new **********************************************************
234 Allocates a new java.lang.reflect.Method object and initializes the
235 fields with the method passed.
237 *******************************************************************************/
239 java_lang_reflect_Method *reflect_method_new(methodinfo *m)
242 java_lang_reflect_Method *rm;
245 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
246 java_lang_reflect_VMMethod *rvmm;
249 /* Allocate a java.lang.reflect.Method object. */
251 o = builtin_new(class_java_lang_reflect_Method);
256 /* initialize instance fields */
258 rm = (java_lang_reflect_Method *) o;
260 /* Calculate the slot. */
262 slot = m - m->clazz->methods;
264 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
266 /* Allocate a java.lang.reflect.VMMethod object. */
268 o = builtin_new(class_java_lang_reflect_VMMethod);
273 rvmm = (java_lang_reflect_VMMethod *) o;
275 /* Link the two Java objects. */
277 LLNI_field_set_ref(rm, m, rvmm);
278 LLNI_field_set_ref(rvmm, m, rm);
280 /* Set Java object instance fields. */
282 LLNI_field_set_cls(rvmm, clazz, m->clazz);
284 /* The name needs to be interned */
285 /* XXX implement me better! */
287 LLNI_field_set_ref(rvmm, name, (java_lang_String *) javastring_intern(javastring_new(m->name)));
288 LLNI_field_set_val(rvmm, slot, slot);
289 LLNI_field_set_ref(rvmm, annotations, method_get_annotations(m));
290 LLNI_field_set_ref(rvmm, parameterAnnotations, method_get_parameterannotations(m));
291 LLNI_field_set_ref(rvmm, annotationDefault, method_get_annotationdefault(m));
293 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
295 LLNI_field_set_cls(rm, clazz, m->clazz);
297 /* The name needs to be interned */
298 /* XXX implement me better! */
300 LLNI_field_set_ref(rm, name, (java_lang_String *) javastring_intern(javastring_new(m->name)));
301 LLNI_field_set_ref(rm, parameterTypes, method_get_parametertypearray(m));
302 LLNI_field_set_cls(rm, returnType, (java_lang_Class *) method_returntype_get(m));
303 LLNI_field_set_ref(rm, exceptionTypes, method_get_exceptionarray(m));
304 LLNI_field_set_val(rm, modifiers, m->flags & ACC_CLASS_REFLECT_MASK);
305 LLNI_field_set_val(rm, slot, slot);
306 LLNI_field_set_ref(rm, signature, m->signature ? (java_lang_String *) javastring_new(m->signature) : NULL);
307 LLNI_field_set_ref(rm, annotations, method_get_annotations(m));
308 LLNI_field_set_ref(rm, parameterAnnotations, method_get_parameterannotations(m));
309 LLNI_field_set_ref(rm, annotationDefault, method_get_annotationdefault(m));
312 # error unknown classpath configuration
319 /* reflect_invoke **************************************************************
321 Invoke a method on the given object with the given arguments.
323 For instance methods OBJ must be != NULL and the method is looked up
324 in the vftbl of the object.
326 For static methods, OBJ is ignored.
328 *******************************************************************************/
330 static java_handle_t *reflect_invoke(methodinfo *m, java_handle_t *o, java_handle_objectarray_t *params)
341 argcount = m->parseddesc->paramcount;
342 paramcount = argcount;
344 /* If method is non-static, remove the `this' pointer. */
346 if (!(m->flags & ACC_STATIC))
349 /* For instance methods the object has to be an instance of the
350 class the method belongs to. For static methods the obj
351 parameter is ignored. */
353 if (!(m->flags & ACC_STATIC) && o && (!builtin_instanceof(o, m->clazz))) {
354 exceptions_throw_illegalargumentexception();
358 /* check if we got the right number of arguments */
360 if (((params == NULL) && (paramcount != 0)) ||
361 (params && (LLNI_array_size(params) != paramcount)))
363 exceptions_throw_illegalargumentexception();
367 /* for instance methods we need an object */
369 if (!(m->flags & ACC_STATIC) && (o == NULL)) {
370 /* XXX not sure if that is the correct exception */
371 exceptions_throw_nullpointerexception();
375 /* for static methods, zero object to make subsequent code simpler */
376 if (m->flags & ACC_STATIC)
380 /* for instance methods we must do a vftbl lookup */
381 resm = method_vftbl_lookup(LLNI_vftbl_direct(o), m);
384 /* for static methods, just for convenience */
388 ro = vm_call_method_objectarray(resm, o, params);
394 /* reflect_constructor_newinstance ********************************************
396 Creates an Java object instance of the given constructor.
399 m .......... methodinfo of the constructor
400 args ....... constructor arguments
401 override ... override security checks
404 constructed Java object
406 *******************************************************************************/
408 java_handle_t *reflect_constructor_newinstance(methodinfo *m, java_handle_objectarray_t *args, bool override)
412 /* Should we bypass security the checks (AccessibleObject)? */
414 if (override == false) {
415 /* This method is always called like this:
416 [0] java.lang.reflect.Constructor.constructNative (Native Method)
417 [1] java.lang.reflect.Constructor.newInstance
421 if (!access_check_method(m, 2))
425 /* Create a Java object. */
427 o = builtin_new(m->clazz);
432 /* Call initializer. */
434 (void) reflect_invoke(m, o, args);
440 /* reflect_method_invoke *******************************************************
442 Invokes the given method.
445 m .......... methodinfo
446 args ....... method arguments
447 override ... override security checks
450 return value of the method
452 *******************************************************************************/
454 java_handle_t *reflect_method_invoke(methodinfo *m, java_handle_t *o, java_handle_objectarray_t *args, bool override)
458 /* Should we bypass security the checks (AccessibleObject)? */
460 if (override == false) {
461 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
462 /* This method is always called like this:
463 [0] java.lang.reflect.Method.invokeNative (Native Method)
464 [1] java.lang.reflect.Method.invoke (Method.java:329)
468 if (!access_check_method(m, 2))
470 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
471 /* We only pass 1 here as stacktrace_get_caller_class, which
472 is called from access_check_method, skips
473 java.lang.reflect.Method.invoke(). */
475 if (!access_check_method(m, 1))
478 # error unknown classpath configuration
482 /* Check if method class is initialized. */
484 if (!(m->clazz->state & CLASS_INITIALIZED))
485 if (!initialize_class(m->clazz))
488 /* Call the Java method. */
490 ro = reflect_invoke(m, o, args);
496 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) && defined(ENABLE_ANNOTATIONS)
497 /* reflect_get_declaredannotations *********************************************
499 Calls the annotation parser with the unparsed annotations and returnes
500 the parsed annotations as a map.
503 annotations........the unparsed annotations
504 declaringClass.....the class in which the annotated element is declared
505 referer............the calling class (for the 'referer' parameter of
509 The parsed annotations as a
510 java.util.Map<Class<? extends Annotation>, Annotation>.
512 *******************************************************************************/
514 struct java_util_Map* reflect_get_declaredannotations(
515 java_handle_bytearray_t *annotations,
516 classinfo *declaringClass,
519 static methodinfo *m_parseAnnotations = NULL;
520 /* parser method (chached, therefore static) */
521 utf *utf_parseAnnotations = NULL;
522 /* parser method name */
523 utf *utf_desc = NULL;
524 /* parser method descriptor (signature) */
525 sun_reflect_ConstantPool *constantPool = NULL;
526 /* constant pool of the declaring class */
527 java_lang_Object *constantPoolOop = (java_lang_Object*)declaringClass;
528 /* constantPoolOop field of the constant pool */
529 /* object (sun.reflect.ConstantPool) */
532 (sun_reflect_ConstantPool*)native_new_and_init(
533 class_sun_reflect_ConstantPool);
535 if(constantPool == NULL) {
540 LLNI_field_set_ref(constantPool, constantPoolOop, constantPoolOop);
542 /* only resolve the parser method the first time */
543 if (m_parseAnnotations == NULL) {
544 utf_parseAnnotations = utf_new_char("parseAnnotations");
545 utf_desc = utf_new_char(
546 "([BLsun/reflect/ConstantPool;Ljava/lang/Class;)"
549 if (utf_parseAnnotations == NULL || utf_desc == NULL) {
554 m_parseAnnotations = class_resolveclassmethod(
555 class_sun_reflect_annotation_AnnotationParser,
556 utf_parseAnnotations,
561 if (m_parseAnnotations == NULL) {
562 /* method not found */
567 return (struct java_util_Map*)vm_call_method(
568 m_parseAnnotations, NULL, annotations,
569 constantPool, declaringClass);
573 /* reflect_get_parameterannotations *******************************************
575 Calls the annotation parser with the unparsed parameter annotations of
576 a method and returnes the parsed parameter annotations in a 2 dimensional
580 parameterAnnotations....the unparsed parameter annotations
581 slot....................the slot of the method
582 declaringClass..........the class in which the annotated element is
584 referer.................the calling class (for the 'referer' parameter
588 The parsed parameter annotations in a 2 dimensional array.
590 *******************************************************************************/
592 java_handle_objectarray_t* reflect_get_parameterannotations(
593 java_handle_t *parameterAnnotations,
597 /* This method in java would be basically the following.
598 * We don't do it in java because we don't want to make a
599 * public method with wich you can get a ConstantPool, because
600 * with that you could read any kind of constants (even private
603 * ConstantPool constPool = new ConstantPool();
604 * constPool.constantPoolOop = method.getDeclaringClass();
605 * return sun.reflect.AnnotationParser.parseParameterAnnotations(
606 * parameterAnnotations,
608 * method.getDeclaringClass(),
609 * method.getParameterTypes().length);
611 static methodinfo *m_parseParameterAnnotations = NULL;
612 /* parser method (cached, therefore static) */
613 utf *utf_parseParameterAnnotations = NULL;
614 /* parser method name */
615 utf *utf_desc = NULL;
616 /* parser method descriptor (signature) */
617 sun_reflect_ConstantPool *constantPool = NULL;
618 /* constant pool of the declaring class */
619 int32_t numParameters = -1;
620 /* parameter count of the annotated method */
622 /* get parameter count */
624 numParameters = method_get_parametercount(m);
626 if (numParameters < 0) {
627 /* error parsing descriptor */
631 /* get ConstantPool */
634 (sun_reflect_ConstantPool*)native_new_and_init(
635 class_sun_reflect_ConstantPool);
637 if(constantPool == NULL) {
642 // XXX I'm not sure what the correct LLNI macro would be.
643 LLNI_field_set_cls(constantPool, constantPoolOop, (java_lang_Object*) m->clazz);
645 /* only resolve the parser method the first time */
646 if (m_parseParameterAnnotations == NULL) {
647 utf_parseParameterAnnotations = utf_new_char("parseParameterAnnotations");
648 utf_desc = utf_new_char(
649 "([BLsun/reflect/ConstantPool;Ljava/lang/Class;I)"
650 "[[Ljava/lang/annotation/Annotation;");
652 if (utf_parseParameterAnnotations == NULL || utf_desc == NULL) {
657 /* get parser method */
659 m_parseParameterAnnotations = class_resolveclassmethod(
660 class_sun_reflect_annotation_AnnotationParser,
661 utf_parseParameterAnnotations,
666 if (m_parseParameterAnnotations == NULL)
668 /* method not found */
673 return (java_handle_objectarray_t*)vm_call_method(
674 m_parseParameterAnnotations, NULL, parameterAnnotations,
675 constantPool, m->clazz, numParameters);
681 * These are local overrides for various environment variables in Emacs.
682 * Please do not remove this and leave it at the end of the file, where
683 * Emacs will automagically detect them.
684 * ---------------------------------------------------------------------
687 * indent-tabs-mode: t
691 * vim:noexpandtab:sw=4:ts=4: