4adcc03bbb5cdbe8416866c10d3156c9b29c9927
[cacao.git] / src / vmcore / field.c
1 /* src/vmcore/field.c - field functions
2
3    Copyright (C) 1996-2005, 2006, 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 <assert.h>
29 #include <stdint.h>
30 #include <stdio.h>
31
32 #include "mm/memory.h"
33
34 #include "native/llni.h"
35
36 #include "vm/types.h"
37
38 #include "vm/array.h"
39 #include "vm/builtin.h"
40 #include "vm/exceptions.hpp"
41 #include "vm/global.h"
42 #include "vm/primitive.hpp"
43 #include "vm/string.hpp"
44 #include "vm/vm.hpp"
45
46 #include "vmcore/annotation.h"
47 #include "vmcore/class.h"
48 #include "vmcore/descriptor.h"
49 #include "vmcore/field.h"
50 #include "vmcore/loader.h"
51 #include "vmcore/options.h"
52 #include "vmcore/references.h"
53 #include "vmcore/suck.h"
54 #include "vmcore/utf8.h"
55
56
57 /* field_load ******************************************************************
58
59    Load everything about a class field from the class file and fill a
60    fieldinfo structure.
61
62 *******************************************************************************/
63
64 #define field_load_NOVALUE  0xffffffff /* must be bigger than any u2 value! */
65
66 bool field_load(classbuffer *cb, fieldinfo *f, descriptor_pool *descpool)
67 {
68         classinfo *c;
69         u4 attrnum, i;
70         u4 pindex = field_load_NOVALUE;     /* constantvalue_index */
71         utf *u;
72
73         /* Get class. */
74
75         c = cb->clazz;
76
77         f->clazz = c;
78
79         /* Get access flags. */
80
81         if (!suck_check_classbuffer_size(cb, 2 + 2 + 2))
82                 return false;
83
84         f->flags = suck_u2(cb);
85
86         /* Get name. */
87
88         if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
89                 return false;
90
91         f->name = u;
92
93         /* Get descriptor. */
94
95         if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
96                 return false;
97
98         f->descriptor = u;
99         f->parseddesc = NULL;
100
101         if (!descriptor_pool_add(descpool, u, NULL))
102                 return false;
103
104         /* descriptor_pool_add accepts method descriptors, so we have to
105            check against them here before the call of
106            descriptor_to_basic_type below. */
107
108         if (u->text[0] == '(') {
109                 exceptions_throw_classformaterror(c, "Method descriptor used for field");
110                 return false;
111         }
112
113 #ifdef ENABLE_VERIFIER
114         if (opt_verify) {
115                 /* check name */
116                 if (!is_valid_name_utf(f->name) || f->name->text[0] == '<') {
117                         exceptions_throw_classformaterror(c,
118                                                                                           "Illegal Field name \"%s\"",
119                                                                                           f->name->text);
120                         return false;
121                 }
122
123                 /* check flag consistency */
124                 i = f->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED);
125
126                 if ((i != 0 && i != ACC_PUBLIC && i != ACC_PRIVATE && i != ACC_PROTECTED) ||
127                         ((f->flags & (ACC_FINAL | ACC_VOLATILE)) == (ACC_FINAL | ACC_VOLATILE))) {
128                         exceptions_throw_classformaterror(c,
129                                                                                           "Illegal field modifiers: 0x%X",
130                                                                                           f->flags);
131                         return false;
132                 }
133
134                 if (c->flags & ACC_INTERFACE) {
135                         if (((f->flags & (ACC_STATIC | ACC_PUBLIC | ACC_FINAL))
136                                 != (ACC_STATIC | ACC_PUBLIC | ACC_FINAL)) ||
137                                 f->flags & ACC_TRANSIENT) {
138                                 exceptions_throw_classformaterror(c,
139                                                                                                   "Illegal field modifiers: 0x%X",
140                                                                                                   f->flags);
141                                 return false;
142                         }
143                 }
144         }
145 #endif /* ENABLE_VERIFIER */
146
147         /* data type */
148
149         f->type = descriptor_to_basic_type(f->descriptor);
150
151         /* For static-fields allocate memory for the value and set the
152            value to 0. */
153
154         if (f->flags & ACC_STATIC) {
155                 switch (f->type) {
156                 case TYPE_INT:
157                 case TYPE_LNG:
158                 case TYPE_FLT:
159                 case TYPE_DBL:
160                         f->value = NEW(imm_union);
161                         break;
162
163                 case TYPE_ADR:
164 #if !defined(ENABLE_GC_BOEHM)
165                         f->value = NEW(imm_union);
166 #else
167                         f->value = GCNEW_UNCOLLECTABLE(imm_union, 1);
168 #endif
169                         break;
170
171                 default:
172                         vm_abort("field_load: invalid field type %d", f->type);
173                 }
174
175                 /* Set the field to zero, for float and double fields set the
176                    correct 0.0 value. */
177
178                 switch (f->type) {
179                 case TYPE_INT:
180                 case TYPE_LNG:
181                 case TYPE_ADR:
182                         f->value->l = 0;
183                         break;
184
185                 case TYPE_FLT:
186                         f->value->f = 0.0;
187                         break;
188
189                 case TYPE_DBL:
190                         f->value->d = 0.0;
191                         break;
192                 }
193         }
194         else {
195                 /* For instance-fields set the offset to 0. */
196
197                 f->offset = 0;
198
199                 /* For final fields, which are not static, we need a value
200                    structure. */
201
202                 if (f->flags & ACC_FINAL) {
203                         f->value = NEW(imm_union);
204                         /* XXX hack */
205                         f->value->l = 0;
206                 }
207
208                 switch (f->type) {
209                 case TYPE_ADR:
210                         c->flags |= ACC_CLASS_HAS_POINTERS;
211                         break;
212                 }
213         }
214
215         /* read attributes */
216
217         if (!suck_check_classbuffer_size(cb, 2))
218                 return false;
219
220         attrnum = suck_u2(cb);
221
222         for (i = 0; i < attrnum; i++) {
223                 if (!suck_check_classbuffer_size(cb, 2))
224                         return false;
225
226                 if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
227                         return false;
228
229                 if (u == utf_ConstantValue) {
230                         if (!suck_check_classbuffer_size(cb, 4 + 2))
231                                 return false;
232
233                         /* check attribute length */
234
235                         if (suck_u4(cb) != 2) {
236                                 exceptions_throw_classformaterror(c, "Wrong size for VALUE attribute");
237                                 return false;
238                         }
239                         
240                         /* constant value attribute */
241
242                         if (pindex != field_load_NOVALUE) {
243                                 exceptions_throw_classformaterror(c, "Multiple ConstantValue attributes");
244                                 return false;
245                         }
246                         
247                         /* index of value in constantpool */
248
249                         pindex = suck_u2(cb);
250                 
251                         /* initialize field with value from constantpool */             
252
253                         switch (f->type) {
254                         case TYPE_INT: {
255                                 constant_integer *ci; 
256
257                                 if (!(ci = class_getconstant(c, pindex, CONSTANT_Integer)))
258                                         return false;
259
260                                 f->value->i = ci->value;
261                         }
262                         break;
263                                         
264                         case TYPE_LNG: {
265                                 constant_long *cl; 
266
267                                 if (!(cl = class_getconstant(c, pindex, CONSTANT_Long)))
268                                         return false;
269
270                                 f->value->l = cl->value;
271                         }
272                         break;
273
274                         case TYPE_FLT: {
275                                 constant_float *cf;
276
277                                 if (!(cf = class_getconstant(c, pindex, CONSTANT_Float)))
278                                         return false;
279
280                                 f->value->f = cf->value;
281                         }
282                         break;
283                                                                                         
284                         case TYPE_DBL: {
285                                 constant_double *cd;
286
287                                 if (!(cd = class_getconstant(c, pindex, CONSTANT_Double)))
288                                         return false;
289
290                                 f->value->d = cd->value;
291                         }
292                         break;
293                                                 
294                         case TYPE_ADR:
295                                 if (!(u = class_getconstant(c, pindex, CONSTANT_String)))
296                                         return false;
297
298                                 /* Create Java-string from compressed UTF8-string. */
299
300                                 f->value->a = literalstring_new(u);
301                                 break;
302         
303                         default: 
304                                 vm_abort("field_load: invalid field type %d", f->type);
305                         }
306                 }
307 #if defined(ENABLE_JAVASE)
308                 else if (u == utf_Signature) {
309                         /* Signature */
310
311                         if (!loader_load_attribute_signature(cb, &(f->signature)))
312                                 return false;
313                 }
314
315 #if defined(ENABLE_ANNOTATIONS)
316                 else if (u == utf_RuntimeVisibleAnnotations) {
317                         /* RuntimeVisibleAnnotations */
318                         if (!annotation_load_field_attribute_runtimevisibleannotations(cb, f))
319                                 return false;
320                 }
321                 else if (u == utf_RuntimeInvisibleAnnotations) {
322                         /* RuntimeInvisibleAnnotations */
323                         if (!annotation_load_field_attribute_runtimeinvisibleannotations(cb, f))
324                                 return false;
325                 }
326 #endif
327 #endif
328                 else {
329                         /* unknown attribute */
330
331                         if (!loader_skip_attribute_body(cb))
332                                 return false;
333                 }
334         }
335
336         /* everything was ok */
337
338         return true;
339 }
340
341
342 /* field_get_type **************************************************************
343
344    Returns the type of the field as class.
345
346 *******************************************************************************/
347
348 classinfo *field_get_type(fieldinfo *f)
349 {
350         typedesc  *td;
351         utf       *u;
352         classinfo *c;
353
354         td = f->parseddesc;
355
356         if (td->type == TYPE_ADR) {
357                 assert(td->classref);
358
359                 u = td->classref->name;
360
361                 /* load the class of the field-type with the field's
362                    classloader */
363
364                 c = load_class_from_classloader(u, f->clazz->classloader);
365         }
366         else {
367                 c = Primitive_get_class_by_type(td->primitivetype);
368         }
369
370         return c;
371 }
372
373
374 /* field_free ******************************************************************
375
376    Frees a fields' resources.
377
378 *******************************************************************************/
379
380 void field_free(fieldinfo *f)
381 {
382         /* free memory for fields which have a value */
383
384         if (f->value)
385 #if defined(ENABLE_GC_BOEHM)
386                 if (f->type != TYPE_ADR)
387 #endif
388                         FREE(f->value, imm_union);
389 }
390
391
392 /* field_get_annotations ******************************************************
393
394    Get a fields' unparsed annotations in a byte array.
395
396    IN:
397        f........the field of which the annotations should be returned
398
399    RETURN VALUE:
400        The unparsed annotations in a byte array (or NULL if there aren't any).
401
402 *******************************************************************************/
403
404 java_handle_bytearray_t *field_get_annotations(fieldinfo *f)
405 {
406 #if defined(ENABLE_ANNOTATIONS)
407         classinfo               *c;           /* declaring class           */
408         int                      slot;        /* slot of this field        */
409         java_handle_bytearray_t *annotations; /* unparsed annotations      */
410         java_handle_t           *field_annotations;  /* array of unparsed  */
411                        /* annotations of all fields of the declaring class */
412
413         c           = f->clazz;
414         slot        = f - c->fields;
415         annotations = NULL;
416
417         LLNI_classinfo_field_get(c, field_annotations, field_annotations);
418
419         /* the field_annotations array might be shorter then the field
420          * count if the fields above a certain index have no annotations.
421          */
422         if (field_annotations != NULL &&
423                 array_length_get(field_annotations) > slot) {
424                 annotations = (java_handle_bytearray_t*)array_objectarray_element_get(
425                                 (java_handle_objectarray_t*)field_annotations, slot);
426         }
427         
428         return annotations;
429 #else
430         return NULL;
431 #endif
432 }
433
434
435 /* field_printflags ************************************************************
436
437    (debugging only)
438
439 *******************************************************************************/
440
441 #if !defined(NDEBUG)
442 void field_printflags(fieldinfo *f)
443 {
444         if (f == NULL) {
445                 printf("NULL");
446                 return;
447         }
448
449         if (f->flags & ACC_PUBLIC)       printf(" PUBLIC");
450         if (f->flags & ACC_PRIVATE)      printf(" PRIVATE");
451         if (f->flags & ACC_PROTECTED)    printf(" PROTECTED");
452         if (f->flags & ACC_STATIC)       printf(" STATIC");
453         if (f->flags & ACC_FINAL)        printf(" FINAL");
454         if (f->flags & ACC_SYNCHRONIZED) printf(" SYNCHRONIZED");
455         if (f->flags & ACC_VOLATILE)     printf(" VOLATILE");
456         if (f->flags & ACC_TRANSIENT)    printf(" TRANSIENT");
457         if (f->flags & ACC_NATIVE)       printf(" NATIVE");
458         if (f->flags & ACC_INTERFACE)    printf(" INTERFACE");
459         if (f->flags & ACC_ABSTRACT)     printf(" ABSTRACT");
460 }
461 #endif
462
463
464 /* field_print *****************************************************************
465
466    (debugging only)
467
468 *******************************************************************************/
469
470 #if !defined(NDEBUG)
471 void field_print(fieldinfo *f)
472 {
473         if (f == NULL) {
474                 printf("(fieldinfo*)NULL");
475                 return;
476         }
477
478         utf_display_printable_ascii_classname(f->clazz->name);
479         printf(".");
480         utf_display_printable_ascii(f->name);
481         printf(" ");
482         utf_display_printable_ascii(f->descriptor);     
483
484         field_printflags(f);
485
486         if (!(f->flags & ACC_STATIC)) {
487                 printf(", offset: %d", f->offset);
488         }
489 }
490 #endif
491
492
493 /* field_println ***************************************************************
494
495    (debugging only)
496
497 *******************************************************************************/
498
499 #if !defined(NDEBUG)
500 void field_println(fieldinfo *f)
501 {
502         field_print(f);
503         printf("\n");
504 }
505 #endif
506
507 /* field_fieldref_print ********************************************************
508
509    (debugging only)
510
511 *******************************************************************************/
512
513 #if !defined(NDEBUG)
514 void field_fieldref_print(constant_FMIref *fr)
515 {
516         if (fr == NULL) {
517                 printf("(constant_FMIref *)NULL");
518                 return;
519         }
520
521         if (IS_FMIREF_RESOLVED(fr)) {
522                 printf("<field> ");
523                 field_print(fr->p.field);
524         }
525         else {
526                 printf("<fieldref> ");
527                 utf_display_printable_ascii_classname(fr->p.classref->name);
528                 printf(".");
529                 utf_display_printable_ascii(fr->name);
530                 printf(" ");
531                 utf_display_printable_ascii(fr->descriptor);
532         }
533 }
534 #endif
535
536 /* field_fieldref_println ******************************************************
537
538    (debugging only)
539
540 *******************************************************************************/
541
542 #if !defined(NDEBUG)
543 void field_fieldref_println(constant_FMIref *fr)
544 {
545         field_fieldref_print(fr);
546         printf("\n");
547 }
548 #endif
549
550 /*
551  * These are local overrides for various environment variables in Emacs.
552  * Please do not remove this and leave it at the end of the file, where
553  * Emacs will automagically detect them.
554  * ---------------------------------------------------------------------
555  * Local variables:
556  * mode: c
557  * indent-tabs-mode: t
558  * c-basic-offset: 4
559  * tab-width: 4
560  * End:
561  * vim:noexpandtab:sw=4:ts=4:
562  */