This commit introduces C++ wrapper classes for Java heap objects.
[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/initialize.h"
45 #include "vm/string.hpp"
46
47 #include "vmcore/globals.hpp"
48 #include "vmcore/javaobjects.hpp"
49 #include "vmcore/method.h"
50
51
52 /**
53  * Invoke a method on the given object with the given arguments.
54  *
55  * For instance methods OBJ must be != NULL and the method is looked up
56  * in the vftbl of the object.
57  *
58  * For static methods, OBJ is ignored.
59  */
60 java_handle_t* Reflection::invoke(methodinfo *m, java_handle_t *o, java_handle_objectarray_t *params)
61 {
62         methodinfo    *resm;
63         java_handle_t *ro;
64         int            argcount;
65         int            paramcount;
66
67         /* Sanity check. */
68
69         assert(m != NULL);
70
71         argcount = m->parseddesc->paramcount;
72         paramcount = argcount;
73
74         /* If method is non-static, remove the `this' pointer. */
75
76         if (!(m->flags & ACC_STATIC))
77                 paramcount--;
78
79         /* For instance methods the object has to be an instance of the
80            class the method belongs to. For static methods the obj
81            parameter is ignored. */
82
83         if (!(m->flags & ACC_STATIC) && o && (!builtin_instanceof(o, m->clazz))) {
84                 exceptions_throw_illegalargumentexception();
85                 return NULL;
86         }
87
88         /* check if we got the right number of arguments */
89
90         if (((params == NULL) && (paramcount != 0)) ||
91                 (params && (LLNI_array_size(params) != paramcount))) 
92         {
93                 exceptions_throw_illegalargumentexception();
94                 return NULL;
95         }
96
97         /* for instance methods we need an object */
98
99         if (!(m->flags & ACC_STATIC) && (o == NULL)) {
100                 /* XXX not sure if that is the correct exception */
101                 exceptions_throw_nullpointerexception();
102                 return NULL;
103         }
104
105         /* for static methods, zero object to make subsequent code simpler */
106         if (m->flags & ACC_STATIC)
107                 o = NULL;
108
109         if (o != NULL) {
110                 /* for instance methods we must do a vftbl lookup */
111                 resm = method_vftbl_lookup(LLNI_vftbl_direct(o), m);
112         }
113         else {
114                 /* for static methods, just for convenience */
115                 resm = m;
116         }
117
118         ro = vm_call_method_objectarray(resm, o, params);
119
120         return ro;
121 }
122
123
124 /* reflect_method_invoke *******************************************************
125
126    Invokes the given method.
127
128    ARGUMENTS:
129       m .......... methodinfo
130       args ....... method arguments
131       override ... override security checks
132
133    RETURN:
134       return value of the method
135
136 *******************************************************************************/
137
138 java_handle_t* Reflection::method_invoke(methodinfo *m, java_handle_t *o, java_handle_objectarray_t *args, bool override)
139 {
140         java_handle_t *ro;
141
142         /* Should we bypass security the checks (AccessibleObject)? */
143
144         if (override == false) {
145 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
146                 /* This method is always called like this:
147                        [0] java.lang.reflect.Method.invokeNative (Native Method)
148                        [1] java.lang.reflect.Method.invoke (Method.java:329)
149                        [2] <caller>
150                 */
151
152                 if (!access_check_method(m, 2))
153                         return NULL;
154 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
155                 /* We only pass 1 here as stacktrace_get_caller_class, which
156                    is called from access_check_method, skips
157                    java.lang.reflect.Method.invoke(). */
158
159                 if (!access_check_method(m, 1))
160                         return NULL;
161 #else
162 # error unknown classpath configuration
163 #endif
164         }
165
166         /* Check if method class is initialized. */
167
168         if (!(m->clazz->state & CLASS_INITIALIZED))
169                 if (!initialize_class(m->clazz))
170                         return NULL;
171
172         /* Call the Java method. */
173
174         ro = invoke(m, o, args);
175
176         return ro;
177 }
178
179
180 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) && defined(ENABLE_ANNOTATIONS)
181 /* reflect_get_declaredannotations *********************************************
182
183    Calls the annotation parser with the unparsed annotations and returnes
184    the parsed annotations as a map.
185    
186    IN:
187        annotations........the unparsed annotations
188        declaringClass.....the class in which the annotated element is declared
189        referer............the calling class (for the 'referer' parameter of
190                           vm_call_method())
191
192    RETURN VALUE:
193        The parsed annotations as a
194            java.util.Map<Class<? extends Annotation>, Annotation>.
195
196 *******************************************************************************/
197
198 java_handle_t* Reflection::get_declaredannotations(java_handle_bytearray_t *annotations, classinfo* declaringClass, classinfo *referer)
199 {
200         static methodinfo* m_parseAnnotations = NULL;
201
202         java_handle_t* h = native_new_and_init(class_sun_reflect_ConstantPool);
203                 
204         if (h == NULL)
205                 return NULL;
206
207         sun_reflect_ConstantPool cp(h);
208         cp.set_constantPoolOop(declaringClass);
209                 
210         /* only resolve the parser method the first time */
211         if (m_parseAnnotations == NULL) {
212                 // FIXME Use globals.
213                 utf* utf_parseAnnotations = utf_new_char("parseAnnotations");
214                 utf* utf_desc = utf_new_char("([BLsun/reflect/ConstantPool;Ljava/lang/Class;)Ljava/util/Map;");
215
216                 if (utf_parseAnnotations == NULL || utf_desc == NULL)
217                         return NULL;
218                 
219                 m_parseAnnotations = class_resolveclassmethod(
220                         class_sun_reflect_annotation_AnnotationParser,
221                         utf_parseAnnotations,
222                         utf_desc,
223                         referer,
224                         true);
225         
226                 if (m_parseAnnotations == NULL)
227                         return NULL;
228         }
229         
230         return (java_handle_t*) vm_call_method(m_parseAnnotations, NULL, annotations, cp.get_handle(), declaringClass);
231 }
232
233
234 /* reflect_get_parameterannotations *******************************************
235
236    Calls the annotation parser with the unparsed parameter annotations of
237    a method and returnes the parsed parameter annotations in a 2 dimensional
238    array.
239    
240    IN:
241        parameterAnnotations....the unparsed parameter annotations
242            slot....................the slot of the method
243        declaringClass..........the class in which the annotated element is
244                                    declared
245        referer.................the calling class (for the 'referer' parameter
246                                of vm_call_method())
247
248    RETURN VALUE:
249        The parsed parameter annotations in a 2 dimensional array.
250
251 *******************************************************************************/
252
253 java_handle_objectarray_t* Reflection::get_parameterannotations(java_handle_bytearray_t* parameterAnnotations, methodinfo* m, classinfo* referer)
254 {
255         /* This method in java would be basically the following.
256          * We don't do it in java because we don't want to make a
257          * public method with wich you can get a ConstantPool, because
258          * with that you could read any kind of constants (even private
259          * ones).
260          *
261          * ConstantPool constPool = new ConstantPool();
262          * constPool.constantPoolOop = method.getDeclaringClass();
263          * return sun.reflect.AnnotationParser.parseParameterAnnotations(
264          *        parameterAnnotations,
265          *        constPool,
266          *        method.getDeclaringClass(),
267          *        method.getParameterTypes().length);
268          */
269
270         static methodinfo* m_parseParameterAnnotations = NULL;
271
272         /* get parameter count */
273
274         int32_t numParameters = method_get_parametercount(m);
275
276         if (numParameters < 0)
277                 return NULL;
278
279         /* get ConstantPool */
280
281         java_handle_t* h = native_new_and_init(class_sun_reflect_ConstantPool);
282         
283         if (h == NULL)
284                 return NULL;
285
286         sun_reflect_ConstantPool cp(h);
287         cp.set_constantPoolOop(m->clazz);
288
289         /* only resolve the parser method the first time */
290         if (m_parseParameterAnnotations == NULL) {
291                 utf* utf_parseParameterAnnotations = utf_new_char("parseParameterAnnotations");
292                 utf* utf_desc = utf_new_char("([BLsun/reflect/ConstantPool;Ljava/lang/Class;I)[[Ljava/lang/annotation/Annotation;");
293
294                 if (utf_parseParameterAnnotations == NULL || utf_desc == NULL)
295                         return NULL;
296
297                 /* get parser method */
298
299                 m_parseParameterAnnotations = class_resolveclassmethod(
300                         class_sun_reflect_annotation_AnnotationParser,
301                         utf_parseParameterAnnotations,
302                         utf_desc,
303                         referer,
304                         true);
305
306                 if (m_parseParameterAnnotations == NULL)
307                         return NULL;
308         }
309
310         return (java_handle_objectarray_t*) vm_call_method(m_parseParameterAnnotations, NULL, parameterAnnotations, cp.get_handle(), m->clazz, numParameters);
311 }
312 #endif
313
314
315 /*
316  * These are local overrides for various environment variables in Emacs.
317  * Please do not remove this and leave it at the end of the file, where
318  * Emacs will automagically detect them.
319  * ---------------------------------------------------------------------
320  * Local variables:
321  * mode: c++
322  * indent-tabs-mode: t
323  * c-basic-offset: 4
324  * tab-width: 4
325  * End:
326  * vim:noexpandtab:sw=4:ts=4:
327  */