Proper x86_64 mnemonics
[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.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_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
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_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
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_JAVA_RUNTIME_LIBRARY_OPENJDK)
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_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
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->clazz->fields;
179
180 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
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->clazz);
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_JAVA_RUNTIME_LIBRARY_OPENJDK)
208
209         /* Set the Java object fields. */
210
211         LLNI_field_set_cls(rf, clazz,       f->clazz);
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_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
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_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
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_JAVA_RUNTIME_LIBRARY_OPENJDK)
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_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)
464                        [2] <caller>
465                 */
466
467                 if (!access_check_method(m, 2))
468                         return NULL;
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(). */
473
474                 if (!access_check_method(m, 1))
475                         return NULL;
476 #else
477 # error unknown classpath configuration
478 #endif
479         }
480
481         /* Check if method class is initialized. */
482
483         if (!(m->clazz->state & CLASS_INITIALIZED))
484                 if (!initialize_class(m->clazz))
485                         return NULL;
486
487         /* Call the Java method. */
488
489         ro = reflect_invoke(m, o, args);
490
491         return ro;
492 }
493
494
495 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) && defined(ENABLE_ANNOTATIONS)
496 /* reflect_get_declaredannotatios *********************************************
497
498    Calls the annotation parser with the unparsed annotations and returnes
499    the parsed annotations as a map.
500    
501    IN:
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
505                           vm_call_method())
506
507    RETURN VALUE:
508        The parsed annotations as a
509            java.util.Map<Class<? extends Annotation>, Annotation>.
510
511 *******************************************************************************/
512
513 struct java_util_Map* reflect_get_declaredannotatios(
514         java_handle_bytearray_t *annotations,
515         java_lang_Class         *declaringClass,
516         classinfo               *referer)
517 {
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)          */
529
530         constantPool = 
531                 (sun_reflect_ConstantPool*)native_new_and_init(
532                         class_sun_reflect_ConstantPool);
533                 
534         if(constantPool == NULL) {
535                 /* out of memory */
536                 return NULL;
537         }
538                 
539         LLNI_field_set_ref(constantPool, constantPoolOop, constantPoolOop);
540                 
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;)"
546                         "Ljava/util/Map;");
547
548                 if (utf_parseAnnotations == NULL || utf_desc == NULL) {
549                         /* out of memory */
550                         return NULL;
551                 }
552                 
553                 m_parseAnnotations = class_resolveclassmethod(
554                         class_sun_reflect_annotation_AnnotationParser,
555                         utf_parseAnnotations,
556                         utf_desc,
557                         referer,
558                         true);
559         
560                 if (m_parseAnnotations == NULL) {
561                         /* method not found */
562                         return NULL;
563                 }
564         }
565         
566         return (struct java_util_Map*)vm_call_method(
567                         m_parseAnnotations, NULL, annotations,
568                         constantPool, declaringClass);
569 }
570
571
572 /* reflect_get_parameterannotations *******************************************
573
574    Calls the annotation parser with the unparsed parameter annotations of
575    a method and returnes the parsed parameter annotations in a 2 dimensional
576    array.
577    
578    IN:
579        parameterAnnotations....the unparsed parameter annotations
580            slot....................the slot of the method
581        declaringClass..........the class in which the annotated element is
582                                    declared
583        referer.................the calling class (for the 'referer' parameter
584                                of vm_call_method())
585
586    RETURN VALUE:
587        The parsed parameter annotations in a 2 dimensional array.
588
589 *******************************************************************************/
590
591 java_handle_objectarray_t* reflect_get_parameterannotations(
592         java_handle_t     *parameterAnnotations,
593         int32_t            slot,
594         java_lang_Class   *declaringClass,
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         java_lang_Object         *constantPoolOop = (java_lang_Object*)declaringClass;
620                              /* constantPoolOop field of the constant pool object */
621         classinfo                *c               = NULL;
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           */
627
628         /* get parameter count */
629
630         c = LLNI_classinfo_unwrap(declaringClass);
631         m = &(c->methods[slot]);
632
633         numParameters = method_get_parametercount(m);
634
635         if (numParameters < 0) {
636                 /* error parsing descriptor */
637                 return NULL;
638         }
639
640         /* get ConstantPool */
641
642         constantPool = 
643                 (sun_reflect_ConstantPool*)native_new_and_init(
644                         class_sun_reflect_ConstantPool);
645         
646         if(constantPool == NULL) {
647                 /* out of memory */
648                 return NULL;
649         }
650
651         LLNI_field_set_ref(constantPool, constantPoolOop, constantPoolOop);
652
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;");
659
660                 if (utf_parseParameterAnnotations == NULL || utf_desc == NULL) {
661                         /* out of memory */
662                         return NULL;
663                 }
664
665                 /* get parser method */
666
667                 m_parseParameterAnnotations = class_resolveclassmethod(
668                         class_sun_reflect_annotation_AnnotationParser,
669                         utf_parseParameterAnnotations,
670                         utf_desc,
671                         referer,
672                         true);
673
674                 if (m_parseParameterAnnotations == NULL)
675                 {
676                         /* method not found */
677                         return NULL;
678                 }
679         }
680
681         return (java_handle_objectarray_t*)vm_call_method(
682                 m_parseParameterAnnotations, NULL, parameterAnnotations,
683                 constantPool, declaringClass, numParameters);
684 }
685 #endif
686
687
688 /*
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  * ---------------------------------------------------------------------
693  * Local variables:
694  * mode: c
695  * indent-tabs-mode: t
696  * c-basic-offset: 4
697  * tab-width: 4
698  * End:
699  * vim:noexpandtab:sw=4:ts=4:
700  */