6618f6134abac3e97a973f7dd5ce24afc34ed95c
[cacao.git] / src / native / vm / reflect.c
1 /* src/native/vm/reflect.c - helper functions for java/lang/reflect
2
3    Copyright (C) 2007 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25 */
26
27
28 #include "config.h"
29
30 #include <stdint.h>
31
32 #if defined(ENABLE_ANNOTATIONS)
33 #include "mm/memory.h"
34
35 #if defined(WITH_CLASSPATH_GNU)
36 #include "vm/vm.h"
37
38 #include "native/include/sun_reflect_ConstantPool.h"
39 #endif
40 #endif
41
42 #include "native/jni.h"
43 #include "native/llni.h"
44 #include "native/native.h"
45
46 /* keep this order of the native includes */
47
48 #include "native/include/java_lang_String.h"
49
50 #if defined(WITH_CLASSPATH_SUN)
51 # include "native/include/java_nio_ByteBuffer.h"        /* required by j.l.CL */
52 #endif
53 #include "native/include/java_lang_ClassLoader.h"
54
55 #include "native/include/java_lang_Object.h"
56 #include "native/include/java_lang_Class.h"
57 #include "native/include/java_lang_reflect_Constructor.h"
58 #include "native/include/java_lang_reflect_Field.h"
59 #include "native/include/java_lang_reflect_Method.h"
60
61 #include "native/vm/reflect.h"
62
63 #include "vm/builtin.h"
64 #include "vm/global.h"
65 #include "vm/stringlocal.h"
66
67 #include "vmcore/method.h"
68
69
70 /* reflect_constructor_new *****************************************************
71
72    Allocates a new java.lang.reflect.Constructor object and
73    initializes the fields with the method passed.
74
75 *******************************************************************************/
76
77 java_lang_reflect_Constructor *reflect_constructor_new(methodinfo *m)
78 {
79         classinfo                     *c;
80         java_handle_t                 *o;
81         java_lang_reflect_Constructor *rc;
82         int32_t                        slot;
83
84         /* get declaring class */
85
86         c = m->class;
87
88         /* allocate a new object */
89
90         o = builtin_new(class_java_lang_reflect_Constructor);
91
92         if (o == NULL)
93                 return NULL;
94
95         /* initialize instance fields */
96
97         rc = (java_lang_reflect_Constructor *) o;
98
99         /* calculate the slot */
100
101         slot = m - c->methods;
102
103 #if defined(WITH_CLASSPATH_GNU)
104
105         LLNI_field_set_cls(rc, clazz               , c);
106         LLNI_field_set_val(rc, slot                , slot);
107         LLNI_field_set_ref(rc, annotations         , method_get_annotations(m));
108         LLNI_field_set_ref(rc, parameterAnnotations, method_get_parameterannotations(m));
109
110 #elif defined(WITH_CLASSPATH_SUN)
111
112         LLNI_field_set_cls(rc, clazz               , c);
113         LLNI_field_set_ref(rc, parameterTypes      , method_get_parametertypearray(m));
114         LLNI_field_set_ref(rc, exceptionTypes      , method_get_exceptionarray(m));
115         LLNI_field_set_val(rc, modifiers           , m->flags & ACC_CLASS_REFLECT_MASK);
116         LLNI_field_set_val(rc, slot                , slot);
117         LLNI_field_set_ref(rc, signature           , m->signature ? (java_lang_String *) javastring_new(m->signature) : NULL);
118         LLNI_field_set_ref(rc, annotations         , method_get_annotations(m));
119         LLNI_field_set_ref(rc, parameterAnnotations, method_get_parameterannotations(m));
120
121 #else
122 # error unknown classpath configuration
123 #endif
124
125         return rc;
126 }
127
128
129 /* reflect_field_new ***********************************************************
130
131    Allocates a new java.lang.reflect.Field object and initializes the
132    fields with the field passed.
133
134 *******************************************************************************/
135
136 java_lang_reflect_Field *reflect_field_new(fieldinfo *f)
137 {
138         classinfo               *c;
139         java_handle_t           *o;
140         java_lang_reflect_Field *rf;
141         int32_t                  slot;
142
143         /* get declaring class */
144
145         c = f->class;
146
147         /* allocate a new object */
148
149         o = builtin_new(class_java_lang_reflect_Field);
150
151         if (o == NULL)
152                 return NULL;
153
154         /* initialize instance fields */
155
156         rf = (java_lang_reflect_Field *) o;
157
158         /* calculate the slot */
159
160         slot = f - c->fields;
161
162 #if defined(WITH_CLASSPATH_GNU)
163
164         LLNI_field_set_cls(rf, clazz         , c);
165
166         /* The name needs to be interned */
167         /* XXX implement me better! */
168
169         LLNI_field_set_ref(rf, name          , javastring_intern(javastring_new(f->name)));
170         LLNI_field_set_val(rf, slot          , slot);
171         LLNI_field_set_ref(rf, annotations   , field_get_annotations(f));
172
173 #elif defined(WITH_CLASSPATH_SUN)
174
175         LLNI_field_set_cls(rf, clazz         , c);
176
177         /* The name needs to be interned */
178         /* XXX implement me better! */
179
180         LLNI_field_set_ref(rf, name          , javastring_intern(javastring_new(f->name)));
181         LLNI_field_set_cls(rf, type          , (java_lang_Class *) field_get_type(f));
182         LLNI_field_set_val(rf, modifiers     , f->flags);
183         LLNI_field_set_val(rf, slot          , slot);
184         LLNI_field_set_ref(rf, signature     , f->signature ? (java_lang_String *) javastring_new(f->signature) : NULL);
185         LLNI_field_set_ref(rf, annotations   , field_get_annotations(f));
186
187 #else
188 # error unknown classpath configuration
189 #endif
190
191         return rf;
192 }
193
194
195 /* reflect_method_new **********************************************************
196
197    Allocates a new java.lang.reflect.Method object and initializes the
198    fields with the method passed.
199
200 *******************************************************************************/
201
202 java_lang_reflect_Method *reflect_method_new(methodinfo *m)
203 {
204         classinfo                *c;
205         java_handle_t            *o;
206         java_lang_reflect_Method *rm;
207         int32_t                   slot;
208
209         /* get declaring class */
210
211         c = m->class;
212
213         /* allocate a new object */
214
215         o = builtin_new(class_java_lang_reflect_Method);
216
217         if (o == NULL)
218                 return NULL;
219
220         /* initialize instance fields */
221
222         rm = (java_lang_reflect_Method *) o;
223
224         /* calculate the slot */
225
226         slot = m - c->methods;
227
228 #if defined(WITH_CLASSPATH_GNU)
229
230         LLNI_field_set_cls(rm, clazz               , m->class);
231
232         /* The name needs to be interned */
233         /* XXX implement me better! */
234
235         LLNI_field_set_ref(rm, name                , javastring_intern(javastring_new(m->name)));
236         LLNI_field_set_val(rm, slot                , slot);
237         LLNI_field_set_ref(rm, annotations         , method_get_annotations(m));
238         LLNI_field_set_ref(rm, parameterAnnotations, method_get_parameterannotations(m));
239         LLNI_field_set_ref(rm, annotationDefault   , method_get_annotationdefault(m));
240
241 #elif defined(WITH_CLASSPATH_SUN)
242
243         LLNI_field_set_cls(rm, clazz               , m->class);
244
245         /* The name needs to be interned */
246         /* XXX implement me better! */
247
248         LLNI_field_set_ref(rm, name                , javastring_intern(javastring_new(m->name)));
249         LLNI_field_set_ref(rm, parameterTypes      , method_get_parametertypearray(m));
250         LLNI_field_set_cls(rm, returnType          , (java_lang_Class *) method_returntype_get(m));
251         LLNI_field_set_ref(rm, exceptionTypes      , method_get_exceptionarray(m));
252         LLNI_field_set_val(rm, modifiers           , m->flags & ACC_CLASS_REFLECT_MASK);
253         LLNI_field_set_val(rm, slot                , slot);
254         LLNI_field_set_ref(rm, signature           , m->signature ? (java_lang_String *) javastring_new(m->signature) : NULL);
255         LLNI_field_set_ref(rm, annotations         , method_get_annotations(m));
256         LLNI_field_set_ref(rm, parameterAnnotations, method_get_parameterannotations(m));
257         LLNI_field_set_ref(rm, annotationDefault   , method_get_annotationdefault(m));
258
259 #else
260 # error unknown classpath configuration
261 #endif
262
263         return rm;
264 }
265
266
267 #if defined(WITH_CLASSPATH_GNU) && defined(ENABLE_ANNOTATIONS)
268 /* reflect_get_declaredannotatios *********************************************
269
270    Calls the annotation parser with the unparsed annotations and returnes
271    the parsed annotations as a map.
272    
273    IN:
274        annotations........the unparsed annotations
275        declaringClass.....the class in which the annotated element is declared
276        referer............the calling class (for the 'referer' parameter of
277                           vm_call_method())
278
279    RETURN VALUE:
280        The parsed annotations as a
281            java.util.Map<Class<? extends Annotation>, Annotation>.
282
283 *******************************************************************************/
284
285 struct java_util_Map* reflect_get_declaredannotatios(
286         java_handle_bytearray_t *annotations,
287         java_lang_Class         *declaringClass,
288         classinfo               *referer)
289 {
290         static methodinfo        *m_parseAnnotations   = NULL;
291                                     /* parser method (chached, therefore static)  */
292         utf                      *utf_parseAnnotations = NULL;
293                                     /* parser method name                         */
294         utf                      *utf_desc             = NULL;
295                                     /* parser method descriptor (signature)       */
296         sun_reflect_ConstantPool *constantPool         = NULL;
297                                     /* constant pool of the declaring class       */
298         java_lang_Object         *constantPoolOop      = (java_lang_Object*)declaringClass;
299                                     /* constantPoolOop field of the constant pool */
300                                     /* object (sun.reflect.ConstantPool)          */
301
302         constantPool = 
303                 (sun_reflect_ConstantPool*)native_new_and_init(
304                         class_sun_reflect_ConstantPool);
305                 
306         if(constantPool == NULL) {
307                 /* out of memory */
308                 return NULL;
309         }
310                 
311         LLNI_field_set_ref(constantPool, constantPoolOop, constantPoolOop);
312                 
313         /* only resolve the parser method the first time */
314         if (m_parseAnnotations == NULL) {
315                 utf_parseAnnotations = utf_new_char("parseAnnotations");
316                 utf_desc = utf_new_char(
317                         "([BLsun/reflect/ConstantPool;Ljava/lang/Class;)"
318                         "Ljava/util/Map;");
319
320                 if (utf_parseAnnotations == NULL || utf_desc == NULL) {
321                         /* out of memory */
322                         return NULL;
323                 }
324                 
325                 m_parseAnnotations = class_resolveclassmethod(
326                         class_sun_reflect_annotation_AnnotationParser,
327                         utf_parseAnnotations,
328                         utf_desc,
329                         referer,
330                         true);
331         
332                 if (m_parseAnnotations == NULL) {
333                         /* method not found */
334                         return NULL;
335                 }
336         }
337         
338         return (struct java_util_Map*)vm_call_method(
339                         m_parseAnnotations, NULL, annotations,
340                         constantPool, declaringClass);
341 }
342
343
344 /* reflect_get_parameterannotations *******************************************
345
346    Calls the annotation parser with the unparsed parameter annotations of
347    a method and returnes the parsed parameter annotations in a 2 dimensional
348    array.
349    
350    IN:
351        parameterAnnotations....the unparsed parameter annotations
352            slot....................the slot of the method
353        declaringClass..........the class in which the annotated element is
354                                    declared
355        referer.................the calling class (for the 'referer' parameter
356                                of vm_call_method())
357
358    RETURN VALUE:
359        The parsed parameter annotations in a 2 dimensional array.
360
361 *******************************************************************************/
362
363 java_handle_objectarray_t* reflect_get_parameterannotations(
364         java_handle_t     *parameterAnnotations,
365         int32_t            slot,
366         java_lang_Class   *declaringClass,
367         classinfo         *referer)
368 {
369         /* This method in java would be basically the following.
370          * We don't do it in java because we don't want to make a
371          * public method with wich you can get a ConstantPool, because
372          * with that you could read any kind of constants (even private
373          * ones).
374          *
375          * ConstantPool constPool = new ConstantPool();
376          * constPool.constantPoolOop = method.getDeclaringClass();
377          * return sun.reflect.AnnotationParser.parseParameterAnnotations(
378          *        parameterAnnotations,
379          *        constPool,
380          *        method.getDeclaringClass(),
381          *        method.getParameterTypes().length);
382          */
383         static methodinfo        *m_parseParameterAnnotations   = NULL;
384                              /* parser method (cached, therefore static)          */
385         utf                      *utf_parseParameterAnnotations = NULL;
386                              /* parser method name                                */
387         utf                      *utf_desc        = NULL;
388                              /* parser method descriptor (signature)              */
389         sun_reflect_ConstantPool *constantPool    = NULL;
390                              /* constant pool of the declaring class              */
391         java_lang_Object         *constantPoolOop = (java_lang_Object*)declaringClass;
392                              /* constantPoolOop field of the constant pool object */
393         classinfo                *c               = NULL;
394                              /* classinfo of the decaring class                   */
395         methodinfo               *m               = NULL;
396                              /* method info of the annotated method               */
397         int32_t                   numParameters   = -1;
398                              /* parameter count of the annotated method           */
399
400         /* get parameter count */
401
402         c = LLNI_classinfo_unwrap(declaringClass);
403         m = &(c->methods[slot]);
404
405         numParameters = method_get_parametercount(m);
406
407         if (numParameters < 0) {
408                 /* error parsing descriptor */
409                 return NULL;
410         }
411
412         /* get ConstantPool */
413
414         constantPool = 
415                 (sun_reflect_ConstantPool*)native_new_and_init(
416                         class_sun_reflect_ConstantPool);
417         
418         if(constantPool == NULL) {
419                 /* out of memory */
420                 return NULL;
421         }
422
423         LLNI_field_set_ref(constantPool, constantPoolOop, constantPoolOop);
424
425         /* only resolve the parser method the first time */
426         if (m_parseParameterAnnotations == NULL) {
427                 utf_parseParameterAnnotations = utf_new_char("parseParameterAnnotations");
428                 utf_desc = utf_new_char(
429                         "([BLsun/reflect/ConstantPool;Ljava/lang/Class;I)"
430                         "[[Ljava/lang/annotation/Annotation;");
431
432                 if (utf_parseParameterAnnotations == NULL || utf_desc == NULL) {
433                         /* out of memory */
434                         return NULL;
435                 }
436
437                 /* get parser method */
438
439                 m_parseParameterAnnotations = class_resolveclassmethod(
440                         class_sun_reflect_annotation_AnnotationParser,
441                         utf_parseParameterAnnotations,
442                         utf_desc,
443                         referer,
444                         true);
445
446                 if (m_parseParameterAnnotations == NULL)
447                 {
448                         /* method not found */
449                         return NULL;
450                 }
451         }
452
453         return (java_handle_objectarray_t*)vm_call_method(
454                 m_parseParameterAnnotations, NULL, parameterAnnotations,
455                 constantPool, declaringClass, numParameters);
456 }
457 #endif
458
459
460 /*
461  * These are local overrides for various environment variables in Emacs.
462  * Please do not remove this and leave it at the end of the file, where
463  * Emacs will automagically detect them.
464  * ---------------------------------------------------------------------
465  * Local variables:
466  * mode: c
467  * indent-tabs-mode: t
468  * c-basic-offset: 4
469  * tab-width: 4
470  * End:
471  * vim:noexpandtab:sw=4:ts=4:
472  */