* Merged twisti branch to default. This merge introduces C++ wrapper
[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 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) && defined(ENABLE_ANNOTATIONS)
125 /* reflect_get_declaredannotations *********************************************
126
127    Calls the annotation parser with the unparsed annotations and returnes
128    the parsed annotations as a map.
129    
130    IN:
131        annotations........the unparsed annotations
132        declaringClass.....the class in which the annotated element is declared
133        referer............the calling class (for the 'referer' parameter of
134                           vm_call_method())
135
136    RETURN VALUE:
137        The parsed annotations as a
138            java.util.Map<Class<? extends Annotation>, Annotation>.
139
140 *******************************************************************************/
141
142 java_handle_t* Reflection::get_declaredannotations(java_handle_bytearray_t *annotations, classinfo* declaringClass, classinfo *referer)
143 {
144         static methodinfo* m_parseAnnotations = NULL;
145
146         java_handle_t* h = native_new_and_init(class_sun_reflect_ConstantPool);
147                 
148         if (h == NULL)
149                 return NULL;
150
151         sun_reflect_ConstantPool cp(h);
152         cp.set_constantPoolOop(declaringClass);
153                 
154         /* only resolve the parser method the first time */
155         if (m_parseAnnotations == NULL) {
156                 // FIXME Use globals.
157                 utf* utf_parseAnnotations = utf_new_char("parseAnnotations");
158                 utf* utf_desc = utf_new_char("([BLsun/reflect/ConstantPool;Ljava/lang/Class;)Ljava/util/Map;");
159
160                 if (utf_parseAnnotations == NULL || utf_desc == NULL)
161                         return NULL;
162                 
163                 m_parseAnnotations = class_resolveclassmethod(
164                         class_sun_reflect_annotation_AnnotationParser,
165                         utf_parseAnnotations,
166                         utf_desc,
167                         referer,
168                         true);
169         
170                 if (m_parseAnnotations == NULL)
171                         return NULL;
172         }
173         
174         return (java_handle_t*) vm_call_method(m_parseAnnotations, NULL, annotations, cp.get_handle(), declaringClass);
175 }
176
177
178 /* reflect_get_parameterannotations *******************************************
179
180    Calls the annotation parser with the unparsed parameter annotations of
181    a method and returnes the parsed parameter annotations in a 2 dimensional
182    array.
183    
184    IN:
185        parameterAnnotations....the unparsed parameter annotations
186            slot....................the slot of the method
187        declaringClass..........the class in which the annotated element is
188                                    declared
189        referer.................the calling class (for the 'referer' parameter
190                                of vm_call_method())
191
192    RETURN VALUE:
193        The parsed parameter annotations in a 2 dimensional array.
194
195 *******************************************************************************/
196
197 java_handle_objectarray_t* Reflection::get_parameterannotations(java_handle_bytearray_t* parameterAnnotations, methodinfo* m, classinfo* referer)
198 {
199         /* This method in java would be basically the following.
200          * We don't do it in java because we don't want to make a
201          * public method with wich you can get a ConstantPool, because
202          * with that you could read any kind of constants (even private
203          * ones).
204          *
205          * ConstantPool constPool = new ConstantPool();
206          * constPool.constantPoolOop = method.getDeclaringClass();
207          * return sun.reflect.AnnotationParser.parseParameterAnnotations(
208          *        parameterAnnotations,
209          *        constPool,
210          *        method.getDeclaringClass(),
211          *        method.getParameterTypes().length);
212          */
213
214         static methodinfo* m_parseParameterAnnotations = NULL;
215
216         /* get parameter count */
217
218         int32_t numParameters = method_get_parametercount(m);
219
220         if (numParameters < 0)
221                 return NULL;
222
223         /* get ConstantPool */
224
225         java_handle_t* h = native_new_and_init(class_sun_reflect_ConstantPool);
226         
227         if (h == NULL)
228                 return NULL;
229
230         sun_reflect_ConstantPool cp(h);
231         cp.set_constantPoolOop(m->clazz);
232
233         /* only resolve the parser method the first time */
234         if (m_parseParameterAnnotations == NULL) {
235                 utf* utf_parseParameterAnnotations = utf_new_char("parseParameterAnnotations");
236                 utf* utf_desc = utf_new_char("([BLsun/reflect/ConstantPool;Ljava/lang/Class;I)[[Ljava/lang/annotation/Annotation;");
237
238                 if (utf_parseParameterAnnotations == NULL || utf_desc == NULL)
239                         return NULL;
240
241                 /* get parser method */
242
243                 m_parseParameterAnnotations = class_resolveclassmethod(
244                         class_sun_reflect_annotation_AnnotationParser,
245                         utf_parseParameterAnnotations,
246                         utf_desc,
247                         referer,
248                         true);
249
250                 if (m_parseParameterAnnotations == NULL)
251                         return NULL;
252         }
253
254         return (java_handle_objectarray_t*) vm_call_method(m_parseParameterAnnotations, NULL, parameterAnnotations, cp.get_handle(), m->clazz, numParameters);
255 }
256 #endif
257
258
259 /*
260  * These are local overrides for various environment variables in Emacs.
261  * Please do not remove this and leave it at the end of the file, where
262  * Emacs will automagically detect them.
263  * ---------------------------------------------------------------------
264  * Local variables:
265  * mode: c++
266  * indent-tabs-mode: t
267  * c-basic-offset: 4
268  * tab-width: 4
269  * End:
270  * vim:noexpandtab:sw=4:ts=4:
271  */