* src/vm/signal.c (signal_thread): Restart sigwait if it has been
[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_JAVA_RUNTIME_LIBRARY_OPENJDK)
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_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"
53 #endif
54
55 #if defined(ENABLE_ANNOTATIONS) && defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
56 # include "vm/vm.hpp"
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.hpp"
65 #include "vm/global.h"
66 #include "vm/initialize.h"
67 #include "vm/string.hpp"
68
69 #include "vmcore/globals.hpp"
70 #include "vmcore/method.h"
71
72
73 /* reflect_constructor_new *****************************************************
74
75    Allocates a new java.lang.reflect.Constructor object and
76    initializes the fields with the method passed.
77
78 *******************************************************************************/
79
80 java_lang_reflect_Constructor *reflect_constructor_new(methodinfo *m)
81 {
82         java_handle_t                   *o;
83         java_lang_reflect_Constructor   *rc;
84         int32_t                          slot;
85
86 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
87         java_lang_reflect_VMConstructor *rvmc;
88 #endif
89
90         /* Allocate a java.lang.reflect.Constructor object. */
91
92         o = builtin_new(class_java_lang_reflect_Constructor);
93
94         if (o == NULL)
95                 return NULL;
96
97         /* Initialize instance fields. */
98
99         rc = (java_lang_reflect_Constructor *) o;
100
101         /* Calculate the slot. */
102
103         slot = m - m->clazz->methods;
104
105 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
106
107         /* Allocate a java.lang.reflect.VMConstructor object. */
108
109         o = builtin_new(class_java_lang_reflect_VMConstructor);
110
111         if (o == NULL)
112                 return NULL;
113
114         rvmc = (java_lang_reflect_VMConstructor *) o;
115
116         /* Link the two Java objects. */
117
118         LLNI_field_set_ref(rc,   cons, rvmc);
119         LLNI_field_set_ref(rvmc, cons, rc);
120
121         /* Set Java object instance fields. */
122
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));
127
128 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
129
130         /* Set Java object instance fields. */
131
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));
140
141 #else
142 # error unknown classpath configuration
143 #endif
144
145         return rc;
146 }
147
148
149 /* reflect_field_new ***********************************************************
150
151    Allocates a new java.lang.reflect.Field object and initializes the
152    fields with the field passed.
153
154 *******************************************************************************/
155
156 java_lang_reflect_Field *reflect_field_new(fieldinfo *f)
157 {
158         java_handle_t             *o;
159         java_lang_reflect_Field   *rf;
160         int32_t                    slot;
161
162 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
163         java_lang_reflect_VMField *rvmf;
164 #endif
165
166         /* Allocate a java.lang.reflect.Field object. */
167
168         o = builtin_new(class_java_lang_reflect_Field);
169
170         if (o == NULL)
171                 return NULL;
172
173         /* initialize instance fields */
174
175         rf = (java_lang_reflect_Field *) o;
176
177         /* Calculate the slot. */
178
179         slot = f - f->clazz->fields;
180
181 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
182
183         /* Allocate a java.lang.reflect.VMField object. */
184
185         o = builtin_new(class_java_lang_reflect_VMField);
186
187         if (o == NULL)
188                 return NULL;
189
190         rvmf = (java_lang_reflect_VMField *) o;
191
192         /* Link the two Java objects. */
193
194         LLNI_field_set_ref(rf,   f, rvmf);
195         LLNI_field_set_ref(rvmf, f, rf);
196
197         /* Set the Java object fields. */
198
199         LLNI_field_set_cls(rvmf, clazz,       f->clazz);
200
201         /* The name needs to be interned */
202         /* XXX implement me better! */
203
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));
207
208 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
209
210         /* Set the Java object fields. */
211
212         LLNI_field_set_cls(rf, clazz,       f->clazz);
213
214         /* The name needs to be interned */
215         /* XXX implement me better! */
216
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));
223
224 #else
225 # error unknown classpath configuration
226 #endif
227
228         return rf;
229 }
230
231
232 /* reflect_method_new **********************************************************
233
234    Allocates a new java.lang.reflect.Method object and initializes the
235    fields with the method passed.
236
237 *******************************************************************************/
238
239 java_lang_reflect_Method *reflect_method_new(methodinfo *m)
240 {
241         java_handle_t              *o;
242         java_lang_reflect_Method   *rm;
243         int32_t                     slot;
244
245 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
246         java_lang_reflect_VMMethod *rvmm;
247 #endif
248
249         /* Allocate a java.lang.reflect.Method object. */
250
251         o = builtin_new(class_java_lang_reflect_Method);
252
253         if (o == NULL)
254                 return NULL;
255
256         /* initialize instance fields */
257
258         rm = (java_lang_reflect_Method *) o;
259
260         /* Calculate the slot. */
261
262         slot = m - m->clazz->methods;
263
264 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
265
266         /* Allocate a java.lang.reflect.VMMethod object. */
267
268         o = builtin_new(class_java_lang_reflect_VMMethod);
269
270         if (o == NULL)
271                 return NULL;
272
273         rvmm = (java_lang_reflect_VMMethod *) o;
274
275         /* Link the two Java objects. */
276
277         LLNI_field_set_ref(rm,   m, rvmm);
278         LLNI_field_set_ref(rvmm, m, rm);
279
280         /* Set Java object instance fields. */
281
282         LLNI_field_set_cls(rvmm, clazz,                m->clazz);
283
284         /* The name needs to be interned */
285         /* XXX implement me better! */
286
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));
292
293 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
294
295         LLNI_field_set_cls(rm, clazz,                m->clazz);
296
297         /* The name needs to be interned */
298         /* XXX implement me better! */
299
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));
310
311 #else
312 # error unknown classpath configuration
313 #endif
314
315         return rm;
316 }
317
318
319 /* reflect_invoke **************************************************************
320
321    Invoke a method on the given object with the given arguments.
322
323    For instance methods OBJ must be != NULL and the method is looked up
324    in the vftbl of the object.
325
326    For static methods, OBJ is ignored.
327
328 *******************************************************************************/
329
330 static java_handle_t *reflect_invoke(methodinfo *m, java_handle_t *o, java_handle_objectarray_t *params)
331 {
332         methodinfo    *resm;
333         java_handle_t *ro;
334         int            argcount;
335         int            paramcount;
336
337         /* Sanity check. */
338
339         assert(m != NULL);
340
341         argcount = m->parseddesc->paramcount;
342         paramcount = argcount;
343
344         /* If method is non-static, remove the `this' pointer. */
345
346         if (!(m->flags & ACC_STATIC))
347                 paramcount--;
348
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. */
352
353         if (!(m->flags & ACC_STATIC) && o && (!builtin_instanceof(o, m->clazz))) {
354                 exceptions_throw_illegalargumentexception();
355                 return NULL;
356         }
357
358         /* check if we got the right number of arguments */
359
360         if (((params == NULL) && (paramcount != 0)) ||
361                 (params && (LLNI_array_size(params) != paramcount))) 
362         {
363                 exceptions_throw_illegalargumentexception();
364                 return NULL;
365         }
366
367         /* for instance methods we need an object */
368
369         if (!(m->flags & ACC_STATIC) && (o == NULL)) {
370                 /* XXX not sure if that is the correct exception */
371                 exceptions_throw_nullpointerexception();
372                 return NULL;
373         }
374
375         /* for static methods, zero object to make subsequent code simpler */
376         if (m->flags & ACC_STATIC)
377                 o = NULL;
378
379         if (o != NULL) {
380                 /* for instance methods we must do a vftbl lookup */
381                 resm = method_vftbl_lookup(LLNI_vftbl_direct(o), m);
382         }
383         else {
384                 /* for static methods, just for convenience */
385                 resm = m;
386         }
387
388         ro = vm_call_method_objectarray(resm, o, params);
389
390         return ro;
391 }
392
393
394 /* reflect_constructor_newinstance ********************************************
395
396    Creates an Java object instance of the given constructor.
397
398    ARGUMENTS:
399       m .......... methodinfo of the constructor
400       args ....... constructor arguments
401       override ... override security checks
402
403    RETURN:
404       constructed Java object
405
406 *******************************************************************************/
407
408 java_handle_t *reflect_constructor_newinstance(methodinfo *m, java_handle_objectarray_t *args, bool override)
409 {
410         java_handle_t *o;
411
412         /* Should we bypass security the checks (AccessibleObject)? */
413
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
418                        [2] <caller>
419                 */
420
421                 if (!access_check_method(m, 2))
422                         return NULL;
423         }
424
425         /* Create a Java object. */
426
427         o = builtin_new(m->clazz);
428
429         if (o == NULL)
430                 return NULL;
431         
432         /* Call initializer. */
433
434         (void) reflect_invoke(m, o, args);
435
436         return o;
437 }
438
439
440 /* reflect_method_invoke *******************************************************
441
442    Invokes the given method.
443
444    ARGUMENTS:
445       m .......... methodinfo
446       args ....... method arguments
447       override ... override security checks
448
449    RETURN:
450       return value of the method
451
452 *******************************************************************************/
453
454 java_handle_t *reflect_method_invoke(methodinfo *m, java_handle_t *o, java_handle_objectarray_t *args, bool override)
455 {
456         java_handle_t *ro;
457
458         /* Should we bypass security the checks (AccessibleObject)? */
459
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)
465                        [2] <caller>
466                 */
467
468                 if (!access_check_method(m, 2))
469                         return NULL;
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(). */
474
475                 if (!access_check_method(m, 1))
476                         return NULL;
477 #else
478 # error unknown classpath configuration
479 #endif
480         }
481
482         /* Check if method class is initialized. */
483
484         if (!(m->clazz->state & CLASS_INITIALIZED))
485                 if (!initialize_class(m->clazz))
486                         return NULL;
487
488         /* Call the Java method. */
489
490         ro = reflect_invoke(m, o, args);
491
492         return ro;
493 }
494
495
496 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) && defined(ENABLE_ANNOTATIONS)
497 /* reflect_get_declaredannotations *********************************************
498
499    Calls the annotation parser with the unparsed annotations and returnes
500    the parsed annotations as a map.
501    
502    IN:
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
506                           vm_call_method())
507
508    RETURN VALUE:
509        The parsed annotations as a
510            java.util.Map<Class<? extends Annotation>, Annotation>.
511
512 *******************************************************************************/
513
514 struct java_util_Map* reflect_get_declaredannotations(
515         java_handle_bytearray_t *annotations,
516         classinfo               *declaringClass,
517         classinfo               *referer)
518 {
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)          */
530
531         constantPool = 
532                 (sun_reflect_ConstantPool*)native_new_and_init(
533                         class_sun_reflect_ConstantPool);
534                 
535         if(constantPool == NULL) {
536                 /* out of memory */
537                 return NULL;
538         }
539                 
540         LLNI_field_set_ref(constantPool, constantPoolOop, constantPoolOop);
541                 
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;)"
547                         "Ljava/util/Map;");
548
549                 if (utf_parseAnnotations == NULL || utf_desc == NULL) {
550                         /* out of memory */
551                         return NULL;
552                 }
553                 
554                 m_parseAnnotations = class_resolveclassmethod(
555                         class_sun_reflect_annotation_AnnotationParser,
556                         utf_parseAnnotations,
557                         utf_desc,
558                         referer,
559                         true);
560         
561                 if (m_parseAnnotations == NULL) {
562                         /* method not found */
563                         return NULL;
564                 }
565         }
566         
567         return (struct java_util_Map*)vm_call_method(
568                         m_parseAnnotations, NULL, annotations,
569                         constantPool, declaringClass);
570 }
571
572
573 /* reflect_get_parameterannotations *******************************************
574
575    Calls the annotation parser with the unparsed parameter annotations of
576    a method and returnes the parsed parameter annotations in a 2 dimensional
577    array.
578    
579    IN:
580        parameterAnnotations....the unparsed parameter annotations
581            slot....................the slot of the method
582        declaringClass..........the class in which the annotated element is
583                                    declared
584        referer.................the calling class (for the 'referer' parameter
585                                of vm_call_method())
586
587    RETURN VALUE:
588        The parsed parameter annotations in a 2 dimensional array.
589
590 *******************************************************************************/
591
592 java_handle_objectarray_t* reflect_get_parameterannotations(
593         java_handle_t     *parameterAnnotations,
594         methodinfo        *m,
595         classinfo         *referer)
596 {
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
601          * ones).
602          *
603          * ConstantPool constPool = new ConstantPool();
604          * constPool.constantPoolOop = method.getDeclaringClass();
605          * return sun.reflect.AnnotationParser.parseParameterAnnotations(
606          *        parameterAnnotations,
607          *        constPool,
608          *        method.getDeclaringClass(),
609          *        method.getParameterTypes().length);
610          */
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           */
621
622         /* get parameter count */
623
624         numParameters = method_get_parametercount(m);
625
626         if (numParameters < 0) {
627                 /* error parsing descriptor */
628                 return NULL;
629         }
630
631         /* get ConstantPool */
632
633         constantPool = 
634                 (sun_reflect_ConstantPool*)native_new_and_init(
635                         class_sun_reflect_ConstantPool);
636         
637         if(constantPool == NULL) {
638                 /* out of memory */
639                 return NULL;
640         }
641
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);
644
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;");
651
652                 if (utf_parseParameterAnnotations == NULL || utf_desc == NULL) {
653                         /* out of memory */
654                         return NULL;
655                 }
656
657                 /* get parser method */
658
659                 m_parseParameterAnnotations = class_resolveclassmethod(
660                         class_sun_reflect_annotation_AnnotationParser,
661                         utf_parseParameterAnnotations,
662                         utf_desc,
663                         referer,
664                         true);
665
666                 if (m_parseParameterAnnotations == NULL)
667                 {
668                         /* method not found */
669                         return NULL;
670                 }
671         }
672
673         return (java_handle_objectarray_t*)vm_call_method(
674                 m_parseParameterAnnotations, NULL, parameterAnnotations,
675                 constantPool, m->clazz, numParameters);
676 }
677 #endif
678
679
680 /*
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  * ---------------------------------------------------------------------
685  * Local variables:
686  * mode: c
687  * indent-tabs-mode: t
688  * c-basic-offset: 4
689  * tab-width: 4
690  * End:
691  * vim:noexpandtab:sw=4:ts=4:
692  */