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