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.h"
65 #include "vm/global.h"
66 #include "vm/initialize.h"
67 #include "vm/stringlocal.h"
69 #include "vmcore/method.h"
72 /* reflect_constructor_new *****************************************************
74 Allocates a new java.lang.reflect.Constructor object and
75 initializes the fields with the method passed.
77 *******************************************************************************/
79 java_lang_reflect_Constructor *reflect_constructor_new(methodinfo *m)
82 java_lang_reflect_Constructor *rc;
85 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
86 java_lang_reflect_VMConstructor *rvmc;
89 /* Allocate a java.lang.reflect.Constructor object. */
91 o = builtin_new(class_java_lang_reflect_Constructor);
96 /* Initialize instance fields. */
98 rc = (java_lang_reflect_Constructor *) o;
100 /* Calculate the slot. */
102 slot = m - m->clazz->methods;
104 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
106 /* Allocate a java.lang.reflect.VMConstructor object. */
108 o = builtin_new(class_java_lang_reflect_VMConstructor);
113 rvmc = (java_lang_reflect_VMConstructor *) o;
115 /* Link the two Java objects. */
117 LLNI_field_set_ref(rc, cons, rvmc);
118 LLNI_field_set_ref(rvmc, cons, rc);
120 /* Set Java object instance fields. */
122 LLNI_field_set_cls(rvmc, clazz, m->clazz);
123 LLNI_field_set_val(rvmc, slot, slot);
124 LLNI_field_set_ref(rvmc, annotations, method_get_annotations(m));
125 LLNI_field_set_ref(rvmc, parameterAnnotations, method_get_parameterannotations(m));
127 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
129 /* Set Java object instance fields. */
131 LLNI_field_set_cls(rc, clazz , m->clazz);
132 LLNI_field_set_ref(rc, parameterTypes , method_get_parametertypearray(m));
133 LLNI_field_set_ref(rc, exceptionTypes , method_get_exceptionarray(m));
134 LLNI_field_set_val(rc, modifiers , m->flags & ACC_CLASS_REFLECT_MASK);
135 LLNI_field_set_val(rc, slot , slot);
136 LLNI_field_set_ref(rc, signature , m->signature ? (java_lang_String *) javastring_new(m->signature) : NULL);
137 LLNI_field_set_ref(rc, annotations , method_get_annotations(m));
138 LLNI_field_set_ref(rc, parameterAnnotations, method_get_parameterannotations(m));
141 # error unknown classpath configuration
148 /* reflect_field_new ***********************************************************
150 Allocates a new java.lang.reflect.Field object and initializes the
151 fields with the field passed.
153 *******************************************************************************/
155 java_lang_reflect_Field *reflect_field_new(fieldinfo *f)
158 java_lang_reflect_Field *rf;
161 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
162 java_lang_reflect_VMField *rvmf;
165 /* Allocate a java.lang.reflect.Field object. */
167 o = builtin_new(class_java_lang_reflect_Field);
172 /* initialize instance fields */
174 rf = (java_lang_reflect_Field *) o;
176 /* Calculate the slot. */
178 slot = f - f->clazz->fields;
180 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
182 /* Allocate a java.lang.reflect.VMField object. */
184 o = builtin_new(class_java_lang_reflect_VMField);
189 rvmf = (java_lang_reflect_VMField *) o;
191 /* Link the two Java objects. */
193 LLNI_field_set_ref(rf, f, rvmf);
194 LLNI_field_set_ref(rvmf, f, rf);
196 /* Set the Java object fields. */
198 LLNI_field_set_cls(rvmf, clazz, f->clazz);
200 /* The name needs to be interned */
201 /* XXX implement me better! */
203 LLNI_field_set_ref(rvmf, name, (java_lang_String *) javastring_intern(javastring_new(f->name)));
204 LLNI_field_set_val(rvmf, slot, slot);
205 LLNI_field_set_ref(rvmf, annotations, field_get_annotations(f));
207 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
209 /* Set the Java object fields. */
211 LLNI_field_set_cls(rf, clazz, f->clazz);
213 /* The name needs to be interned */
214 /* XXX implement me better! */
216 LLNI_field_set_ref(rf, name, (java_lang_String *) javastring_intern(javastring_new(f->name)));
217 LLNI_field_set_cls(rf, type, (java_lang_Class *) field_get_type(f));
218 LLNI_field_set_val(rf, modifiers, f->flags);
219 LLNI_field_set_val(rf, slot, slot);
220 LLNI_field_set_ref(rf, signature, f->signature ? (java_lang_String *) javastring_new(f->signature) : NULL);
221 LLNI_field_set_ref(rf, annotations, field_get_annotations(f));
224 # error unknown classpath configuration
231 /* reflect_method_new **********************************************************
233 Allocates a new java.lang.reflect.Method object and initializes the
234 fields with the method passed.
236 *******************************************************************************/
238 java_lang_reflect_Method *reflect_method_new(methodinfo *m)
241 java_lang_reflect_Method *rm;
244 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
245 java_lang_reflect_VMMethod *rvmm;
248 /* Allocate a java.lang.reflect.Method object. */
250 o = builtin_new(class_java_lang_reflect_Method);
255 /* initialize instance fields */
257 rm = (java_lang_reflect_Method *) o;
259 /* Calculate the slot. */
261 slot = m - m->clazz->methods;
263 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
265 /* Allocate a java.lang.reflect.VMMethod object. */
267 o = builtin_new(class_java_lang_reflect_VMMethod);
272 rvmm = (java_lang_reflect_VMMethod *) o;
274 /* Link the two Java objects. */
276 LLNI_field_set_ref(rm, m, rvmm);
277 LLNI_field_set_ref(rvmm, m, rm);
279 /* Set Java object instance fields. */
281 LLNI_field_set_cls(rvmm, clazz, m->clazz);
283 /* The name needs to be interned */
284 /* XXX implement me better! */
286 LLNI_field_set_ref(rvmm, name, (java_lang_String *) javastring_intern(javastring_new(m->name)));
287 LLNI_field_set_val(rvmm, slot, slot);
288 LLNI_field_set_ref(rvmm, annotations, method_get_annotations(m));
289 LLNI_field_set_ref(rvmm, parameterAnnotations, method_get_parameterannotations(m));
290 LLNI_field_set_ref(rvmm, annotationDefault, method_get_annotationdefault(m));
292 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
294 LLNI_field_set_cls(rm, clazz, m->clazz);
296 /* The name needs to be interned */
297 /* XXX implement me better! */
299 LLNI_field_set_ref(rm, name, (java_lang_String *) javastring_intern(javastring_new(m->name)));
300 LLNI_field_set_ref(rm, parameterTypes, method_get_parametertypearray(m));
301 LLNI_field_set_cls(rm, returnType, (java_lang_Class *) method_returntype_get(m));
302 LLNI_field_set_ref(rm, exceptionTypes, method_get_exceptionarray(m));
303 LLNI_field_set_val(rm, modifiers, m->flags & ACC_CLASS_REFLECT_MASK);
304 LLNI_field_set_val(rm, slot, slot);
305 LLNI_field_set_ref(rm, signature, m->signature ? (java_lang_String *) javastring_new(m->signature) : NULL);
306 LLNI_field_set_ref(rm, annotations, method_get_annotations(m));
307 LLNI_field_set_ref(rm, parameterAnnotations, method_get_parameterannotations(m));
308 LLNI_field_set_ref(rm, annotationDefault, method_get_annotationdefault(m));
311 # error unknown classpath configuration
318 /* reflect_invoke **************************************************************
320 Invoke a method on the given object with the given arguments.
322 For instance methods OBJ must be != NULL and the method is looked up
323 in the vftbl of the object.
325 For static methods, OBJ is ignored.
327 *******************************************************************************/
329 static java_handle_t *reflect_invoke(methodinfo *m, java_handle_t *o, java_handle_objectarray_t *params)
340 argcount = m->parseddesc->paramcount;
341 paramcount = argcount;
343 /* If method is non-static, remove the `this' pointer. */
345 if (!(m->flags & ACC_STATIC))
348 /* For instance methods the object has to be an instance of the
349 class the method belongs to. For static methods the obj
350 parameter is ignored. */
352 if (!(m->flags & ACC_STATIC) && o && (!builtin_instanceof(o, m->clazz))) {
353 exceptions_throw_illegalargumentexception();
357 /* check if we got the right number of arguments */
359 if (((params == NULL) && (paramcount != 0)) ||
360 (params && (LLNI_array_size(params) != paramcount)))
362 exceptions_throw_illegalargumentexception();
366 /* for instance methods we need an object */
368 if (!(m->flags & ACC_STATIC) && (o == NULL)) {
369 /* XXX not sure if that is the correct exception */
370 exceptions_throw_nullpointerexception();
374 /* for static methods, zero object to make subsequent code simpler */
375 if (m->flags & ACC_STATIC)
379 /* for instance methods we must do a vftbl lookup */
380 resm = method_vftbl_lookup(LLNI_vftbl_direct(o), m);
383 /* for static methods, just for convenience */
387 ro = vm_call_method_objectarray(resm, o, params);
393 /* reflect_constructor_newinstance ********************************************
395 Creates an Java object instance of the given constructor.
398 m .......... methodinfo of the constructor
399 args ....... constructor arguments
400 override ... override security checks
403 constructed Java object
405 *******************************************************************************/
407 java_handle_t *reflect_constructor_newinstance(methodinfo *m, java_handle_objectarray_t *args, bool override)
411 /* Should we bypass security the checks (AccessibleObject)? */
413 if (override == false) {
414 /* This method is always called like this:
415 [0] java.lang.reflect.Constructor.constructNative (Native Method)
416 [1] java.lang.reflect.Constructor.newInstance
420 if (!access_check_method(m, 2))
424 /* Create a Java object. */
426 o = builtin_new(m->clazz);
431 /* Call initializer. */
433 (void) reflect_invoke(m, o, args);
439 /* reflect_method_invoke *******************************************************
441 Invokes the given method.
444 m .......... methodinfo
445 args ....... method arguments
446 override ... override security checks
449 return value of the method
451 *******************************************************************************/
453 java_handle_t *reflect_method_invoke(methodinfo *m, java_handle_t *o, java_handle_objectarray_t *args, bool override)
457 /* Should we bypass security the checks (AccessibleObject)? */
459 if (override == false) {
460 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
461 /* This method is always called like this:
462 [0] java.lang.reflect.Method.invokeNative (Native Method)
463 [1] java.lang.reflect.Method.invoke (Method.java:329)
467 if (!access_check_method(m, 2))
469 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
470 /* We only pass 1 here as stacktrace_get_caller_class, which
471 is called from access_check_method, skips
472 java.lang.reflect.Method.invoke(). */
474 if (!access_check_method(m, 1))
477 # error unknown classpath configuration
481 /* Check if method class is initialized. */
483 if (!(m->clazz->state & CLASS_INITIALIZED))
484 if (!initialize_class(m->clazz))
487 /* Call the Java method. */
489 ro = reflect_invoke(m, o, args);
495 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) && defined(ENABLE_ANNOTATIONS)
496 /* reflect_get_declaredannotatios *********************************************
498 Calls the annotation parser with the unparsed annotations and returnes
499 the parsed annotations as a map.
502 annotations........the unparsed annotations
503 declaringClass.....the class in which the annotated element is declared
504 referer............the calling class (for the 'referer' parameter of
508 The parsed annotations as a
509 java.util.Map<Class<? extends Annotation>, Annotation>.
511 *******************************************************************************/
513 struct java_util_Map* reflect_get_declaredannotatios(
514 java_handle_bytearray_t *annotations,
515 java_lang_Class *declaringClass,
518 static methodinfo *m_parseAnnotations = NULL;
519 /* parser method (chached, therefore static) */
520 utf *utf_parseAnnotations = NULL;
521 /* parser method name */
522 utf *utf_desc = NULL;
523 /* parser method descriptor (signature) */
524 sun_reflect_ConstantPool *constantPool = NULL;
525 /* constant pool of the declaring class */
526 java_lang_Object *constantPoolOop = (java_lang_Object*)declaringClass;
527 /* constantPoolOop field of the constant pool */
528 /* object (sun.reflect.ConstantPool) */
531 (sun_reflect_ConstantPool*)native_new_and_init(
532 class_sun_reflect_ConstantPool);
534 if(constantPool == NULL) {
539 LLNI_field_set_ref(constantPool, constantPoolOop, constantPoolOop);
541 /* only resolve the parser method the first time */
542 if (m_parseAnnotations == NULL) {
543 utf_parseAnnotations = utf_new_char("parseAnnotations");
544 utf_desc = utf_new_char(
545 "([BLsun/reflect/ConstantPool;Ljava/lang/Class;)"
548 if (utf_parseAnnotations == NULL || utf_desc == NULL) {
553 m_parseAnnotations = class_resolveclassmethod(
554 class_sun_reflect_annotation_AnnotationParser,
555 utf_parseAnnotations,
560 if (m_parseAnnotations == NULL) {
561 /* method not found */
566 return (struct java_util_Map*)vm_call_method(
567 m_parseAnnotations, NULL, annotations,
568 constantPool, declaringClass);
572 /* reflect_get_parameterannotations *******************************************
574 Calls the annotation parser with the unparsed parameter annotations of
575 a method and returnes the parsed parameter annotations in a 2 dimensional
579 parameterAnnotations....the unparsed parameter annotations
580 slot....................the slot of the method
581 declaringClass..........the class in which the annotated element is
583 referer.................the calling class (for the 'referer' parameter
587 The parsed parameter annotations in a 2 dimensional array.
589 *******************************************************************************/
591 java_handle_objectarray_t* reflect_get_parameterannotations(
592 java_handle_t *parameterAnnotations,
594 java_lang_Class *declaringClass,
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 java_lang_Object *constantPoolOop = (java_lang_Object*)declaringClass;
620 /* constantPoolOop field of the constant pool object */
622 /* classinfo of the decaring class */
623 methodinfo *m = NULL;
624 /* method info of the annotated method */
625 int32_t numParameters = -1;
626 /* parameter count of the annotated method */
628 /* get parameter count */
630 c = LLNI_classinfo_unwrap(declaringClass);
631 m = &(c->methods[slot]);
633 numParameters = method_get_parametercount(m);
635 if (numParameters < 0) {
636 /* error parsing descriptor */
640 /* get ConstantPool */
643 (sun_reflect_ConstantPool*)native_new_and_init(
644 class_sun_reflect_ConstantPool);
646 if(constantPool == NULL) {
651 LLNI_field_set_ref(constantPool, constantPoolOop, constantPoolOop);
653 /* only resolve the parser method the first time */
654 if (m_parseParameterAnnotations == NULL) {
655 utf_parseParameterAnnotations = utf_new_char("parseParameterAnnotations");
656 utf_desc = utf_new_char(
657 "([BLsun/reflect/ConstantPool;Ljava/lang/Class;I)"
658 "[[Ljava/lang/annotation/Annotation;");
660 if (utf_parseParameterAnnotations == NULL || utf_desc == NULL) {
665 /* get parser method */
667 m_parseParameterAnnotations = class_resolveclassmethod(
668 class_sun_reflect_annotation_AnnotationParser,
669 utf_parseParameterAnnotations,
674 if (m_parseParameterAnnotations == NULL)
676 /* method not found */
681 return (java_handle_objectarray_t*)vm_call_method(
682 m_parseParameterAnnotations, NULL, parameterAnnotations,
683 constantPool, declaringClass, numParameters);
689 * These are local overrides for various environment variables in Emacs.
690 * Please do not remove this and leave it at the end of the file, where
691 * Emacs will automagically detect them.
692 * ---------------------------------------------------------------------
695 * indent-tabs-mode: t
699 * vim:noexpandtab:sw=4:ts=4: