* src/vmcore/annotation.c
[cacao.git] / src / vmcore / annotation.c
1 /* src/vmcore/annotation.c - class annotations
2
3    Copyright (C) 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4    R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5    C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6    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 #include "config.h"
28
29 #include <assert.h>
30
31 #include "native/llni.h"
32
33 #include "vm/types.h"
34 #include "vm/array.h"
35 #include "vm/builtin.h"
36 #include "vm/primitive.h"
37
38 #include "mm/memory.h"
39
40 #include "toolbox/logging.h"
41
42 #include "vmcore/annotation.h"
43 #include "vmcore/class.h"
44 #include "vmcore/suck.h"
45
46 #if !defined(ENABLE_ANNOTATIONS)
47 # error annotation support has to be enabled when compling this file!
48 #endif
49
50
51 /* annotation_bytearrays_resize ***********************************************
52
53    Resize an array of bytearrays.
54
55 *******************************************************************************/
56
57 static bool annotation_bytearrays_resize(java_handle_objectarray_t **bas,
58         uint32_t size)
59 {
60         java_handle_objectarray_t *newbas = NULL;
61         uint32_t minsize;
62         uint32_t oldsize;
63         
64         assert(bas != NULL);
65         
66         /* if the size already fits do nothing */
67         if (*bas != NULL) {
68                 oldsize = array_length_get((java_handle_t*)*bas);
69
70                 if (size == oldsize) {
71                         return true;
72                 }
73         }
74
75         newbas = builtin_anewarray(size,
76                 primitive_arrayclass_get_by_type(PRIMITIVETYPE_BYTE));
77         
78         if (newbas == NULL) {
79                 /* out of memory */
80                 return false;
81         }
82         
83         /* is there a old byte array array? */
84         if (*bas != NULL) {
85                 minsize = size < oldsize ? size : oldsize;
86
87                 MCOPY(LLNI_array_data(newbas), LLNI_array_data(*bas), java_object_t*, minsize);
88         }
89
90         *bas = newbas;
91
92         return true;
93 }
94
95
96 /* annotation_bytearrays_insert ***********************************************
97
98    Insert a bytearray into an array of bytearrays.
99
100 *******************************************************************************/
101
102 static bool annotation_bytearrays_insert(java_handle_objectarray_t **bas,
103         uint32_t index, java_handle_bytearray_t *ba)
104 {
105         uint32_t size = 0;
106
107         assert(bas != NULL);
108
109         /* do nothing if NULL is inserted but no array exists */
110         if (ba == NULL && *bas == NULL) {
111                 return true;
112         }
113
114         /* get lengths if array exists */
115         if (*bas != NULL) {
116                 size = array_length_get((java_handle_t*)*bas);
117         }
118
119         if (ba == NULL) {
120                 /* insert NULL only if array is big enough */
121                 if (size > index) {
122                         array_objectarray_element_set(*bas, index, NULL);
123                 }
124         }
125         else {
126                 /* resize array if it's not enough for inserted value */
127                 if (size <= index) {
128                         if (!annotation_bytearrays_resize(bas, index + 1)) {
129                                 /* out of memory */
130                                 return false;
131                         }
132                 }
133
134                 array_objectarray_element_set(*bas, index, (java_handle_t*)ba);
135         }
136         
137         return true;
138 }
139
140
141 /* annotation_load_attribute_body *********************************************
142
143    This function loads the body of a generic attribute.
144
145    XXX: Maybe this function should be called loader_load_attribute_body and
146         located in vmcore/loader.c?
147
148    attribute_info {
149        u2 attribute_name_index;
150        u4 attribute_length;
151        u1 info[attribute_length];
152    }
153
154    IN:
155        cb.................classbuffer from which to read the data.
156        errormsg_prefix....prefix for error messages (if any).
157
158    OUT:
159        attribute..........bytearray-pointer which will be set to the read data.
160    
161    RETURN VALUE:
162        true if all went good. false otherwhise.
163
164 *******************************************************************************/
165
166 static bool annotation_load_attribute_body(classbuffer *cb,
167         java_handle_bytearray_t **attribute, const char *errormsg_prefix)
168 {
169         uint32_t size = 0;
170         java_handle_bytearray_t *ba = NULL;
171
172         assert(cb != NULL);
173         assert(attribute != NULL);
174
175         if (!suck_check_classbuffer_size(cb, 4)) {
176                 log_println("%s: size missing", errormsg_prefix);
177                 return false;
178         }
179
180         /* load attribute_length */
181         size = suck_u4(cb);
182         
183         if (!suck_check_classbuffer_size(cb, size)) {
184                 log_println("%s: invalid size", errormsg_prefix);
185                 return false;
186         }
187         
188         /* if attribute_length == 0 then NULL is
189          * the right value for this attribute */
190         if (size > 0) {
191                 ba = builtin_newarray_byte(size);
192
193                 if (ba == NULL) {
194                         /* out of memory */
195                         return false;
196                 }
197
198                 /* load data */
199                 suck_nbytes((uint8_t*)LLNI_array_data(ba), cb, size);
200
201                 /* return data */
202                 *attribute = ba;
203         }
204         
205         return true;
206 }
207
208
209 /* annotation_load_method_attribute_annotationdefault *************************
210
211    Load annotation default value.
212
213    AnnotationDefault_attribute {
214        u2 attribute_name_index;
215        u4 attribute_length;
216        element_value default_value;
217    }
218
219    IN:
220        cb.................classbuffer from which to read the data.
221        m..................methodinfo for the method of which the annotation
222                           default value is read and into which the value is
223                           stored into.
224
225    RETURN VALUE:
226        true if all went good. false otherwhise.
227
228 *******************************************************************************/
229
230 bool annotation_load_method_attribute_annotationdefault(
231                 classbuffer *cb, methodinfo *m)
232 {
233         int slot = 0;
234         java_handle_bytearray_t    *annotationdefault  = NULL;
235         java_handle_objectarray_t **annotationdefaults = NULL;
236
237         assert(cb != NULL);
238         assert(m != NULL);
239
240         annotationdefaults = &(m->class->method_annotationdefaults);
241
242         if (!annotation_load_attribute_body(
243                         cb, &annotationdefault,
244                         "invalid annotation default method attribute")) {
245                 return false;
246         }
247
248         if (annotationdefault != NULL) {
249                 slot = m - m->class->methods;
250
251                 if (!annotation_bytearrays_insert(
252                                 annotationdefaults, slot, annotationdefault)) {
253                         return false;
254                 }
255         }
256
257         return true;
258 }
259
260
261 /* annotation_load_method_attribute_runtimevisibleparameterannotations ********
262
263    Load runtime visible parameter annotations.
264
265    RuntimeVisibleParameterAnnotations_attribute {
266        u2 attribute_name_index;
267        u4 attribute_length;
268        u1 num_parameters;
269        {
270            u2 num_annotations;
271            annotation annotations[num_annotations];
272        } parameter_annotations[num_parameters];
273    }
274
275    IN:
276        cb.................classbuffer from which to read the data.
277        m..................methodinfo for the method of which the parameter
278                           annotations are read and into which the parameter
279                           annotations are stored into.
280
281    RETURN VALUE:
282        true if all went good. false otherwhise.
283
284 *******************************************************************************/
285
286 bool annotation_load_method_attribute_runtimevisibleparameterannotations(
287                 classbuffer *cb, methodinfo *m)
288 {
289         int slot = 0;
290         java_handle_bytearray_t    *annotations          = NULL;
291         java_handle_objectarray_t **parameterannotations = NULL;
292
293         assert(cb != NULL);
294         assert(m != NULL);
295
296         parameterannotations = &(m->class->method_parameterannotations);
297
298         if (!annotation_load_attribute_body(
299                         cb, &annotations,
300                         "invalid runtime visible parameter annotations method attribute")) {
301                 return false;
302         }
303
304         if (annotations != NULL) {
305                 slot = m - m->class->methods;
306
307                 if (!annotation_bytearrays_insert(
308                                 parameterannotations, slot, annotations)) {
309                         return false;
310                 }
311         }
312
313         return true;
314 }
315
316
317 /* annotation_load_method_attribute_runtimeinvisibleparameterannotations ******
318  
319    Load runtime invisible parameter annotations.
320
321    <quote cite="http://jcp.org/en/jsr/detail?id=202">
322    The RuntimeInvisibleParameterAnnotations attribute is similar to the
323    RuntimeVisibleParameterAnnotations attribute, except that the annotations
324    represented by a RuntimeInvisibleParameterAnnotations attribute must not be
325    made available for return by reflective APIs, unless the the JVM has
326    specifically been instructed to retain these annotations via some
327    implementation-specific mechanism such as a command line flag. In the
328    absence of such instructions, the JVM ignores this attribute.
329    </quote>
330
331    Hotspot loads them into the same bytearray as the runtime visible parameter
332    annotations (after the runtime visible parameter annotations). But in J2SE
333    the bytearray will only be parsed as if ther is only one annotation
334    structure in it, so the runtime invisible parameter annotatios will be
335    ignored.
336
337    Therefore I do not even bother to read them.
338
339    RuntimeInvisibleParameterAnnotations_attribute {
340        u2 attribute_name_index;
341        u4 attribute_length;
342        u1 num_parameters;
343        {
344            u2 num_annotations;
345            annotation annotations[num_annotations];
346        } parameter_annotations[num_parameters];
347    }
348
349    IN:
350        cb.................classbuffer from which to read the data.
351        m..................methodinfo for the method of which the parameter
352                           annotations are read and into which the parameter
353                           annotations are stored into.
354
355    RETURN VALUE:
356        true if all went good. false otherwhise.
357
358 *******************************************************************************/
359
360 bool annotation_load_method_attribute_runtimeinvisibleparameterannotations(
361                 classbuffer *cb, methodinfo *m)
362 {
363         return loader_skip_attribute_body(cb);
364 }
365
366
367 /* annotation_load_class_attribute_runtimevisibleannotations ******************
368    
369    Load runtime visible annotations of a class.
370    
371 *******************************************************************************/
372
373 bool annotation_load_class_attribute_runtimevisibleannotations(
374         classbuffer *cb)
375 {
376         return annotation_load_attribute_body(
377                 cb, &(cb->class->annotations),
378                 "invalid runtime visible annotations class attribute");
379 }
380
381
382 /* annotation_load_class_attribute_runtimeinvisibleannotations ****************
383    
384    Load runtime invisible annotations of a class (just skip them).
385    
386 *******************************************************************************/
387
388 bool annotation_load_class_attribute_runtimeinvisibleannotations(
389         classbuffer *cb)
390 {
391         return loader_skip_attribute_body(cb);
392 }
393
394
395 /* annotation_load_method_attribute_runtimevisibleannotations *****************
396    
397    Load runtime visible annotations of a method.
398    
399 *******************************************************************************/
400
401 bool annotation_load_method_attribute_runtimevisibleannotations(
402         classbuffer *cb, methodinfo *m)
403 {
404         int slot = 0;
405         java_handle_bytearray_t    *annotations        = NULL;
406         java_handle_objectarray_t **method_annotations = NULL;
407
408         assert(cb != NULL);
409         assert(m != NULL);
410
411         method_annotations = &(m->class->method_annotations);
412
413         if (!annotation_load_attribute_body(
414                         cb, &annotations,
415                         "invalid runtime visible annotations method attribute")) {
416                 return false;
417         }
418
419         if (annotations != NULL) {
420                 slot = m - m->class->methods;
421
422                 if (!annotation_bytearrays_insert(
423                                 method_annotations, slot, annotations)) {
424                         return false;
425                 }
426         }
427
428         return true;
429 }
430
431
432 /* annotation_load_method_attribute_runtimeinvisibleannotations ****************
433    
434    Load runtime invisible annotations of a method (just skip them).
435    
436 *******************************************************************************/
437
438 bool annotation_load_method_attribute_runtimeinvisibleannotations(
439         classbuffer *cb, methodinfo *m)
440 {
441         return loader_skip_attribute_body(cb);
442 }
443
444
445 /* annotation_load_field_attribute_runtimevisibleannotations ******************
446    
447    Load runtime visible annotations of a field.
448    
449 *******************************************************************************/
450
451 bool annotation_load_field_attribute_runtimevisibleannotations(
452         classbuffer *cb, fieldinfo *f)
453 {
454         int slot = 0;
455         java_handle_bytearray_t    *annotations       = NULL;
456         java_handle_objectarray_t **field_annotations = NULL;
457
458         assert(cb != NULL);
459         assert(f != NULL);
460
461         field_annotations = &(f->class->field_annotations);
462
463         if (!annotation_load_attribute_body(
464                         cb, &annotations,
465                         "invalid runtime visible annotations field attribute")) {
466                 return false;
467         }
468
469         if (annotations != NULL) {
470                 slot = f - f->class->fields;
471
472                 if (!annotation_bytearrays_insert(
473                                 field_annotations, slot, annotations)) {
474                         return false;
475                 }
476         }
477
478         return true;
479 }
480
481
482 /* annotation_load_field_attribute_runtimeinvisibleannotations ****************
483    
484    Load runtime invisible annotations of a field (just skip them).
485    
486 *******************************************************************************/
487
488 bool annotation_load_field_attribute_runtimeinvisibleannotations(
489         classbuffer *cb, fieldinfo *f)
490 {
491         return loader_skip_attribute_body(cb);
492 }
493
494
495 /*
496  * These are local overrides for various environment variables in Emacs.
497  * Please do not remove this and leave it at the end of the file, where
498  * Emacs will automagically detect them.
499  * ---------------------------------------------------------------------
500  * Local variables:
501  * mode: c
502  * indent-tabs-mode: t
503  * c-basic-offset: 4
504  * tab-width: 4
505  * End:
506  * vim:noexpandtab:sw=4:ts=4:
507  */