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