* merged with tip (040f180a056b)
[cacao.git] / src / native / vm / reflection.cpp
1 /* src/native/vm/reflection.cpp - 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 #if defined(ENABLE_ANNOTATIONS) && defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
35 # include "vm/vm.hpp"
36 #endif
37
38 #include "native/vm/reflection.hpp"
39
40 #include "vm/access.h"
41 #include "vm/builtin.h"
42 #include "vm/exceptions.hpp"
43 #include "vm/global.h"
44 #include "vm/globals.hpp"
45 #include "vm/initialize.h"
46 #include "vm/javaobjects.hpp"
47 #include "vm/method.h"
48 #include "vm/string.hpp"
49
50
51 /**
52  * Invoke a method on the given object with the given arguments.
53  *
54  * For instance methods OBJ must be != NULL and the method is looked up
55  * in the vftbl of the object.
56  *
57  * For static methods, OBJ is ignored.
58  */
59 java_handle_t* Reflection::invoke(methodinfo *m, java_handle_t *o, java_handle_objectarray_t *params)
60 {
61         methodinfo    *resm;
62         java_handle_t *ro;
63         int            argcount;
64         int            paramcount;
65
66         /* Sanity check. */
67
68         assert(m != NULL);
69
70         argcount = m->parseddesc->paramcount;
71         paramcount = argcount;
72
73         /* If method is non-static, remove the `this' pointer. */
74
75         if (!(m->flags & ACC_STATIC))
76                 paramcount--;
77
78         /* For instance methods the object has to be an instance of the
79            class the method belongs to. For static methods the obj
80            parameter is ignored. */
81
82         if (!(m->flags & ACC_STATIC) && o && (!builtin_instanceof(o, m->clazz))) {
83                 exceptions_throw_illegalargumentexception();
84                 return NULL;
85         }
86
87         /* check if we got the right number of arguments */
88
89         if (((params == NULL) && (paramcount != 0)) ||
90                 (params && (LLNI_array_size(params) != paramcount))) 
91         {
92                 exceptions_throw_illegalargumentexception();
93                 return NULL;
94         }
95
96         /* for instance methods we need an object */
97
98         if (!(m->flags & ACC_STATIC) && (o == NULL)) {
99                 /* XXX not sure if that is the correct exception */
100                 exceptions_throw_nullpointerexception();
101                 return NULL;
102         }
103
104         /* for static methods, zero object to make subsequent code simpler */
105         if (m->flags & ACC_STATIC)
106                 o = NULL;
107
108         if (o != NULL) {
109                 /* for instance methods we must do a vftbl lookup */
110                 resm = method_vftbl_lookup(LLNI_vftbl_direct(o), m);
111         }
112         else {
113                 /* for static methods, just for convenience */
114                 resm = m;
115         }
116
117         ro = vm_call_method_objectarray(resm, o, params);
118
119         return ro;
120 }
121
122
123 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) && defined(ENABLE_ANNOTATIONS)
124 /* reflect_get_declaredannotations *********************************************
125
126    Calls the annotation parser with the unparsed annotations and returnes
127    the parsed annotations as a map.
128    
129    IN:
130        annotations........the unparsed annotations
131        declaringClass.....the class in which the annotated element is declared
132        referer............the calling class (for the 'referer' parameter of
133                           vm_call_method())
134
135    RETURN VALUE:
136        The parsed annotations as a
137            java.util.Map<Class<? extends Annotation>, Annotation>.
138
139 *******************************************************************************/
140
141 java_handle_t* Reflection::get_declaredannotations(java_handle_bytearray_t *annotations, classinfo* declaringClass, classinfo *referer)
142 {
143         static methodinfo* m_parseAnnotations = NULL;
144
145         java_handle_t* h = native_new_and_init(class_sun_reflect_ConstantPool);
146                 
147         if (h == NULL)
148                 return NULL;
149
150         sun_reflect_ConstantPool cp(h);
151         cp.set_constantPoolOop(declaringClass);
152                 
153         /* only resolve the parser method the first time */
154         if (m_parseAnnotations == NULL) {
155                 // FIXME Use globals.
156                 utf* utf_parseAnnotations = utf_new_char("parseAnnotations");
157                 utf* utf_desc = utf_new_char("([BLsun/reflect/ConstantPool;Ljava/lang/Class;)Ljava/util/Map;");
158
159                 if (utf_parseAnnotations == NULL || utf_desc == NULL)
160                         return NULL;
161                 
162                 m_parseAnnotations = class_resolveclassmethod(
163                         class_sun_reflect_annotation_AnnotationParser,
164                         utf_parseAnnotations,
165                         utf_desc,
166                         referer,
167                         true);
168         
169                 if (m_parseAnnotations == NULL)
170                         return NULL;
171         }
172         
173         return (java_handle_t*) vm_call_method(m_parseAnnotations, NULL, annotations, cp.get_handle(), declaringClass);
174 }
175
176
177 /* reflect_get_parameterannotations *******************************************
178
179    Calls the annotation parser with the unparsed parameter annotations of
180    a method and returnes the parsed parameter annotations in a 2 dimensional
181    array.
182    
183    IN:
184        parameterAnnotations....the unparsed parameter annotations
185            slot....................the slot of the method
186        declaringClass..........the class in which the annotated element is
187                                    declared
188        referer.................the calling class (for the 'referer' parameter
189                                of vm_call_method())
190
191    RETURN VALUE:
192        The parsed parameter annotations in a 2 dimensional array.
193
194 *******************************************************************************/
195
196 java_handle_objectarray_t* Reflection::get_parameterannotations(java_handle_bytearray_t* parameterAnnotations, methodinfo* m, classinfo* referer)
197 {
198         /* This method in java would be basically the following.
199          * We don't do it in java because we don't want to make a
200          * public method with wich you can get a ConstantPool, because
201          * with that you could read any kind of constants (even private
202          * ones).
203          *
204          * ConstantPool constPool = new ConstantPool();
205          * constPool.constantPoolOop = method.getDeclaringClass();
206          * return sun.reflect.AnnotationParser.parseParameterAnnotations(
207          *        parameterAnnotations,
208          *        constPool,
209          *        method.getDeclaringClass(),
210          *        method.getParameterTypes().length);
211          */
212
213         static methodinfo* m_parseParameterAnnotations = NULL;
214
215         /* get parameter count */
216
217         int32_t numParameters = method_get_parametercount(m);
218
219         if (numParameters < 0)
220                 return NULL;
221
222         /* get ConstantPool */
223
224         java_handle_t* h = native_new_and_init(class_sun_reflect_ConstantPool);
225         
226         if (h == NULL)
227                 return NULL;
228
229         sun_reflect_ConstantPool cp(h);
230         cp.set_constantPoolOop(m->clazz);
231
232         /* only resolve the parser method the first time */
233         if (m_parseParameterAnnotations == NULL) {
234                 utf* utf_parseParameterAnnotations = utf_new_char("parseParameterAnnotations");
235                 utf* utf_desc = utf_new_char("([BLsun/reflect/ConstantPool;Ljava/lang/Class;I)[[Ljava/lang/annotation/Annotation;");
236
237                 if (utf_parseParameterAnnotations == NULL || utf_desc == NULL)
238                         return NULL;
239
240                 /* get parser method */
241
242                 m_parseParameterAnnotations = class_resolveclassmethod(
243                         class_sun_reflect_annotation_AnnotationParser,
244                         utf_parseParameterAnnotations,
245                         utf_desc,
246                         referer,
247                         true);
248
249                 if (m_parseParameterAnnotations == NULL)
250                         return NULL;
251         }
252
253         return (java_handle_objectarray_t*) vm_call_method(m_parseParameterAnnotations, NULL, parameterAnnotations, cp.get_handle(), m->clazz, numParameters);
254 }
255 #endif
256
257
258 /*
259  * These are local overrides for various environment variables in Emacs.
260  * Please do not remove this and leave it at the end of the file, where
261  * Emacs will automagically detect them.
262  * ---------------------------------------------------------------------
263  * Local variables:
264  * mode: c++
265  * indent-tabs-mode: t
266  * c-basic-offset: 4
267  * tab-width: 4
268  * End:
269  * vim:noexpandtab:sw=4:ts=4:
270  */