c62382e47e3b75585fc9057139e1dfc587e142ba
[cacao.git] / src / native / vm / reflect.c
1 /* src/native/vm/reflect.c - helper functions for java/lang/reflect
2
3    Copyright (C) 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
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.
12
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.
17
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
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <stdint.h>
29
30 #include "native/jni.h"
31 #include "native/llni.h"
32 #include "native/native.h"
33
34 /* keep this order of the native includes */
35
36 #include "native/include/java_lang_String.h"
37
38 #if defined(WITH_CLASSPATH_SUN)
39 # include "native/include/java_nio_ByteBuffer.h"        /* required by j.l.CL */
40 #endif
41 #include "native/include/java_lang_ClassLoader.h"
42
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"
48
49 #if defined(WITH_CLASSPATH_GNU)
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"
53 #endif
54
55 #if defined(ENABLE_ANNOTATIONS) && defined(WITH_CLASSPATH_GNU)
56 # include "vm/vm.h"
57 # include "native/include/sun_reflect_ConstantPool.h"
58 #endif
59
60 #include "native/vm/reflect.h"
61
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"
68
69 #include "vmcore/method.h"
70
71
72 /* reflect_constructor_new *****************************************************
73
74    Allocates a new java.lang.reflect.Constructor object and
75    initializes the fields with the method passed.
76
77 *******************************************************************************/
78
79 java_lang_reflect_Constructor *reflect_constructor_new(methodinfo *m)
80 {
81         java_handle_t                   *o;
82         java_lang_reflect_Constructor   *rc;
83         int32_t                          slot;
84
85 #if defined(WITH_CLASSPATH_GNU)
86         java_lang_reflect_VMConstructor *rvmc;
87 #endif
88
89         /* Allocate a java.lang.reflect.Constructor object. */
90
91         o = builtin_new(class_java_lang_reflect_Constructor);
92
93         if (o == NULL)
94                 return NULL;
95
96         /* Initialize instance fields. */
97
98         rc = (java_lang_reflect_Constructor *) o;
99
100         /* Calculate the slot. */
101
102         slot = m - m->clazz->methods;
103
104 #if defined(WITH_CLASSPATH_GNU)
105
106         /* Allocate a java.lang.reflect.VMConstructor object. */
107
108         o = builtin_new(class_java_lang_reflect_VMConstructor);
109
110         if (o == NULL)
111                 return NULL;
112
113         rvmc = (java_lang_reflect_VMConstructor *) o;
114
115         /* Link the two Java objects. */
116
117         LLNI_field_set_ref(rc,   cons, rvmc);
118         LLNI_field_set_ref(rvmc, cons, rc);
119
120         /* Set Java object instance fields. */
121
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));
126
127 #elif defined(WITH_CLASSPATH_SUN)
128
129         /* Set Java object instance fields. */
130
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));
139
140 #else
141 # error unknown classpath configuration
142 #endif
143
144         return rc;
145 }
146
147
148 /* reflect_field_new ***********************************************************
149
150    Allocates a new java.lang.reflect.Field object and initializes the
151    fields with the field passed.
152
153 *******************************************************************************/
154
155 java_lang_reflect_Field *reflect_field_new(fieldinfo *f)
156 {
157         java_handle_t             *o;
158         java_lang_reflect_Field   *rf;
159         int32_t                    slot;
160
161 #if defined(WITH_CLASSPATH_GNU)
162         java_lang_reflect_VMField *rvmf;
163 #endif
164
165         /* Allocate a java.lang.reflect.Field object. */
166
167         o = builtin_new(class_java_lang_reflect_Field);
168
169         if (o == NULL)
170                 return NULL;
171
172         /* initialize instance fields */
173
174         rf = (java_lang_reflect_Field *) o;
175
176         /* Calculate the slot. */
177
178         slot = f - f->class->fields;
179
180 #if defined(WITH_CLASSPATH_GNU)
181
182         /* Allocate a java.lang.reflect.VMField object. */
183
184         o = builtin_new(class_java_lang_reflect_VMField);
185
186         if (o == NULL)
187                 return NULL;
188
189         rvmf = (java_lang_reflect_VMField *) o;
190
191         /* Link the two Java objects. */
192
193         LLNI_field_set_ref(rf,   f, rvmf);
194         LLNI_field_set_ref(rvmf, f, rf);
195
196         /* Set the Java object fields. */
197
198         LLNI_field_set_cls(rvmf, clazz,       f->class);
199
200         /* The name needs to be interned */
201         /* XXX implement me better! */
202
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));
206
207 #elif defined(WITH_CLASSPATH_SUN)
208
209         /* Set the Java object fields. */
210
211         LLNI_field_set_cls(rf, clazz,       f->class);
212
213         /* The name needs to be interned */
214         /* XXX implement me better! */
215
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));
222
223 #else
224 # error unknown classpath configuration
225 #endif
226
227         return rf;
228 }
229
230
231 /* reflect_method_new **********************************************************
232
233    Allocates a new java.lang.reflect.Method object and initializes the
234    fields with the method passed.
235
236 *******************************************************************************/
237
238 java_lang_reflect_Method *reflect_method_new(methodinfo *m)
239 {
240         java_handle_t              *o;
241         java_lang_reflect_Method   *rm;
242         int32_t                     slot;
243
244 #if defined(WITH_CLASSPATH_GNU)
245         java_lang_reflect_VMMethod *rvmm;
246 #endif
247
248         /* Allocate a java.lang.reflect.Method object. */
249
250         o = builtin_new(class_java_lang_reflect_Method);
251
252         if (o == NULL)
253                 return NULL;
254
255         /* initialize instance fields */
256
257         rm = (java_lang_reflect_Method *) o;
258
259         /* Calculate the slot. */
260
261         slot = m - m->clazz->methods;
262
263 #if defined(WITH_CLASSPATH_GNU)
264
265         /* Allocate a java.lang.reflect.VMMethod object. */
266
267         o = builtin_new(class_java_lang_reflect_VMMethod);
268
269         if (o == NULL)
270                 return NULL;
271
272         rvmm = (java_lang_reflect_VMMethod *) o;
273
274         /* Link the two Java objects. */
275
276         LLNI_field_set_ref(rm,   m, rvmm);
277         LLNI_field_set_ref(rvmm, m, rm);
278
279         /* Set Java object instance fields. */
280
281         LLNI_field_set_cls(rvmm, clazz,                m->clazz);
282
283         /* The name needs to be interned */
284         /* XXX implement me better! */
285
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));
291
292 #elif defined(WITH_CLASSPATH_SUN)
293
294         LLNI_field_set_cls(rm, clazz,                m->clazz);
295
296         /* The name needs to be interned */
297         /* XXX implement me better! */
298
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));
309
310 #else
311 # error unknown classpath configuration
312 #endif
313
314         return rm;
315 }
316
317
318 /* reflect_invoke **************************************************************
319
320    Invoke a method on the given object with the given arguments.
321
322    For instance methods OBJ must be != NULL and the method is looked up
323    in the vftbl of the object.
324
325    For static methods, OBJ is ignored.
326
327 *******************************************************************************/
328
329 static java_handle_t *reflect_invoke(methodinfo *m, java_handle_t *o, java_handle_objectarray_t *params)
330 {
331         methodinfo    *resm;
332         java_handle_t *ro;
333         int            argcount;
334         int            paramcount;
335
336         /* Sanity check. */
337
338         assert(m != NULL);
339
340         argcount = m->parseddesc->paramcount;
341         paramcount = argcount;
342
343         /* If method is non-static, remove the `this' pointer. */
344
345         if (!(m->flags & ACC_STATIC))
346                 paramcount--;
347
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. */
351
352         if (!(m->flags & ACC_STATIC) && o && (!builtin_instanceof(o, m->clazz))) {
353                 exceptions_throw_illegalargumentexception();
354                 return NULL;
355         }
356
357         /* check if we got the right number of arguments */
358
359         if (((params == NULL) && (paramcount != 0)) ||
360                 (params && (LLNI_array_size(params) != paramcount))) 
361         {
362                 exceptions_throw_illegalargumentexception();
363                 return NULL;
364         }
365
366         /* for instance methods we need an object */
367
368         if (!(m->flags & ACC_STATIC) && (o == NULL)) {
369                 /* XXX not sure if that is the correct exception */
370                 exceptions_throw_nullpointerexception();
371                 return NULL;
372         }
373
374         /* for static methods, zero object to make subsequent code simpler */
375         if (m->flags & ACC_STATIC)
376                 o = NULL;
377
378         if (o != NULL) {
379                 /* for instance methods we must do a vftbl lookup */
380                 resm = method_vftbl_lookup(LLNI_vftbl_direct(o), m);
381         }
382         else {
383                 /* for static methods, just for convenience */
384                 resm = m;
385         }
386
387         ro = vm_call_method_objectarray(resm, o, params);
388
389         return ro;
390 }
391
392
393 /* reflect_constructor_newinstance ********************************************
394
395    Creates an Java object instance of the given constructor.
396
397    ARGUMENTS:
398       m .......... methodinfo of the constructor
399       args ....... constructor arguments
400       override ... override security checks
401
402    RETURN:
403       constructed Java object
404
405 *******************************************************************************/
406
407 java_handle_t *reflect_constructor_newinstance(methodinfo *m, java_handle_objectarray_t *args, bool override)
408 {
409         java_handle_t *o;
410
411         /* Should we bypass security the checks (AccessibleObject)? */
412
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
417                        [2] <caller>
418                 */
419
420                 if (!access_check_method(m, 2))
421                         return NULL;
422         }
423
424         /* Create a Java object. */
425
426         o = builtin_new(m->clazz);
427
428         if (o == NULL)
429                 return NULL;
430         
431         /* Call initializer. */
432
433         (void) reflect_invoke(m, o, args);
434
435         return o;
436 }
437
438
439 /* reflect_method_invoke *******************************************************
440
441    Invokes the given method.
442
443    ARGUMENTS:
444       m .......... methodinfo
445       args ....... method arguments
446       override ... override security checks
447
448    RETURN:
449       return value of the method
450
451 *******************************************************************************/
452
453 java_handle_t *reflect_method_invoke(methodinfo *m, java_handle_t *o, java_handle_objectarray_t *args, bool override)
454 {
455         java_handle_t *ro;
456
457         /* Should we bypass security the checks (AccessibleObject)? */
458
459         if (override == false) {
460 #if defined(WITH_CLASSPATH_GNU)
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)
464                        [2] <caller>
465                 */
466
467                 if (!access_check_method(m, 2))
468                         return NULL;
469 #elif defined(WITH_CLASSPATH_SUN)
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(). */
473
474                 if (!access_check_method(m, 1))
475                         return NULL;
476 #endif
477         }
478
479         /* Check if method class is initialized. */
480
481         if (!(m->clazz->state & CLASS_INITIALIZED))
482                 if (!initialize_class(m->clazz))
483                         return NULL;
484
485         /* Call the Java method. */
486
487         ro = reflect_invoke(m, o, args);
488
489         return ro;
490 }
491
492
493 #if defined(WITH_CLASSPATH_GNU) && defined(ENABLE_ANNOTATIONS)
494 /* reflect_get_declaredannotatios *********************************************
495
496    Calls the annotation parser with the unparsed annotations and returnes
497    the parsed annotations as a map.
498    
499    IN:
500        annotations........the unparsed annotations
501        declaringClass.....the class in which the annotated element is declared
502        referer............the calling class (for the 'referer' parameter of
503                           vm_call_method())
504
505    RETURN VALUE:
506        The parsed annotations as a
507            java.util.Map<Class<? extends Annotation>, Annotation>.
508
509 *******************************************************************************/
510
511 struct java_util_Map* reflect_get_declaredannotatios(
512         java_handle_bytearray_t *annotations,
513         java_lang_Class         *declaringClass,
514         classinfo               *referer)
515 {
516         static methodinfo        *m_parseAnnotations   = NULL;
517                                     /* parser method (chached, therefore static)  */
518         utf                      *utf_parseAnnotations = NULL;
519                                     /* parser method name                         */
520         utf                      *utf_desc             = NULL;
521                                     /* parser method descriptor (signature)       */
522         sun_reflect_ConstantPool *constantPool         = NULL;
523                                     /* constant pool of the declaring class       */
524         java_lang_Object         *constantPoolOop      = (java_lang_Object*)declaringClass;
525                                     /* constantPoolOop field of the constant pool */
526                                     /* object (sun.reflect.ConstantPool)          */
527
528         constantPool = 
529                 (sun_reflect_ConstantPool*)native_new_and_init(
530                         class_sun_reflect_ConstantPool);
531                 
532         if(constantPool == NULL) {
533                 /* out of memory */
534                 return NULL;
535         }
536                 
537         LLNI_field_set_ref(constantPool, constantPoolOop, constantPoolOop);
538                 
539         /* only resolve the parser method the first time */
540         if (m_parseAnnotations == NULL) {
541                 utf_parseAnnotations = utf_new_char("parseAnnotations");
542                 utf_desc = utf_new_char(
543                         "([BLsun/reflect/ConstantPool;Ljava/lang/Class;)"
544                         "Ljava/util/Map;");
545
546                 if (utf_parseAnnotations == NULL || utf_desc == NULL) {
547                         /* out of memory */
548                         return NULL;
549                 }
550                 
551                 m_parseAnnotations = class_resolveclassmethod(
552                         class_sun_reflect_annotation_AnnotationParser,
553                         utf_parseAnnotations,
554                         utf_desc,
555                         referer,
556                         true);
557         
558                 if (m_parseAnnotations == NULL) {
559                         /* method not found */
560                         return NULL;
561                 }
562         }
563         
564         return (struct java_util_Map*)vm_call_method(
565                         m_parseAnnotations, NULL, annotations,
566                         constantPool, declaringClass);
567 }
568
569
570 /* reflect_get_parameterannotations *******************************************
571
572    Calls the annotation parser with the unparsed parameter annotations of
573    a method and returnes the parsed parameter annotations in a 2 dimensional
574    array.
575    
576    IN:
577        parameterAnnotations....the unparsed parameter annotations
578            slot....................the slot of the method
579        declaringClass..........the class in which the annotated element is
580                                    declared
581        referer.................the calling class (for the 'referer' parameter
582                                of vm_call_method())
583
584    RETURN VALUE:
585        The parsed parameter annotations in a 2 dimensional array.
586
587 *******************************************************************************/
588
589 java_handle_objectarray_t* reflect_get_parameterannotations(
590         java_handle_t     *parameterAnnotations,
591         int32_t            slot,
592         java_lang_Class   *declaringClass,
593         classinfo         *referer)
594 {
595         /* This method in java would be basically the following.
596          * We don't do it in java because we don't want to make a
597          * public method with wich you can get a ConstantPool, because
598          * with that you could read any kind of constants (even private
599          * ones).
600          *
601          * ConstantPool constPool = new ConstantPool();
602          * constPool.constantPoolOop = method.getDeclaringClass();
603          * return sun.reflect.AnnotationParser.parseParameterAnnotations(
604          *        parameterAnnotations,
605          *        constPool,
606          *        method.getDeclaringClass(),
607          *        method.getParameterTypes().length);
608          */
609         static methodinfo        *m_parseParameterAnnotations   = NULL;
610                              /* parser method (cached, therefore static)          */
611         utf                      *utf_parseParameterAnnotations = NULL;
612                              /* parser method name                                */
613         utf                      *utf_desc        = NULL;
614                              /* parser method descriptor (signature)              */
615         sun_reflect_ConstantPool *constantPool    = NULL;
616                              /* constant pool of the declaring class              */
617         java_lang_Object         *constantPoolOop = (java_lang_Object*)declaringClass;
618                              /* constantPoolOop field of the constant pool object */
619         classinfo                *c               = NULL;
620                              /* classinfo of the decaring class                   */
621         methodinfo               *m               = NULL;
622                              /* method info of the annotated method               */
623         int32_t                   numParameters   = -1;
624                              /* parameter count of the annotated method           */
625
626         /* get parameter count */
627
628         c = LLNI_classinfo_unwrap(declaringClass);
629         m = &(c->methods[slot]);
630
631         numParameters = method_get_parametercount(m);
632
633         if (numParameters < 0) {
634                 /* error parsing descriptor */
635                 return NULL;
636         }
637
638         /* get ConstantPool */
639
640         constantPool = 
641                 (sun_reflect_ConstantPool*)native_new_and_init(
642                         class_sun_reflect_ConstantPool);
643         
644         if(constantPool == NULL) {
645                 /* out of memory */
646                 return NULL;
647         }
648
649         LLNI_field_set_ref(constantPool, constantPoolOop, constantPoolOop);
650
651         /* only resolve the parser method the first time */
652         if (m_parseParameterAnnotations == NULL) {
653                 utf_parseParameterAnnotations = utf_new_char("parseParameterAnnotations");
654                 utf_desc = utf_new_char(
655                         "([BLsun/reflect/ConstantPool;Ljava/lang/Class;I)"
656                         "[[Ljava/lang/annotation/Annotation;");
657
658                 if (utf_parseParameterAnnotations == NULL || utf_desc == NULL) {
659                         /* out of memory */
660                         return NULL;
661                 }
662
663                 /* get parser method */
664
665                 m_parseParameterAnnotations = class_resolveclassmethod(
666                         class_sun_reflect_annotation_AnnotationParser,
667                         utf_parseParameterAnnotations,
668                         utf_desc,
669                         referer,
670                         true);
671
672                 if (m_parseParameterAnnotations == NULL)
673                 {
674                         /* method not found */
675                         return NULL;
676                 }
677         }
678
679         return (java_handle_objectarray_t*)vm_call_method(
680                 m_parseParameterAnnotations, NULL, parameterAnnotations,
681                 constantPool, declaringClass, numParameters);
682 }
683 #endif
684
685
686 /*
687  * These are local overrides for various environment variables in Emacs.
688  * Please do not remove this and leave it at the end of the file, where
689  * Emacs will automagically detect them.
690  * ---------------------------------------------------------------------
691  * Local variables:
692  * mode: c
693  * indent-tabs-mode: t
694  * c-basic-offset: 4
695  * tab-width: 4
696  * End:
697  * vim:noexpandtab:sw=4:ts=4:
698  */