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