* src/vm/jit/oprofile-agent.cpp: Set source formatting to c++.
[cacao.git] / src / vmcore / field.c
index 01b5f72b841ccac6ad1c0a55d5b694628483c5b1..4adcc03bbb5cdbe8416866c10d3156c9b29c9927 100644 (file)
@@ -1,9 +1,7 @@
 /* src/vmcore/field.c - field functions
 
-   Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
-   C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
-   E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
-   J. Wenninger, Institut f. Computersprachen - TU Wien
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
 
    This file is part of CACAO.
 
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   $Id: field.c 7246 2007-01-29 18:49:05Z twisti $
-
 */
 
 
 #include "config.h"
 
+#include <assert.h>
+#include <stdint.h>
 #include <stdio.h>
 
+#include "mm/memory.h"
+
+#include "native/llni.h"
+
 #include "vm/types.h"
 
+#include "vm/array.h"
+#include "vm/builtin.h"
+#include "vm/exceptions.hpp"
+#include "vm/global.h"
+#include "vm/primitive.hpp"
+#include "vm/string.hpp"
+#include "vm/vm.hpp"
+
+#include "vmcore/annotation.h"
+#include "vmcore/class.h"
+#include "vmcore/descriptor.h"
 #include "vmcore/field.h"
+#include "vmcore/loader.h"
+#include "vmcore/options.h"
 #include "vmcore/references.h"
+#include "vmcore/suck.h"
 #include "vmcore/utf8.h"
 
 
+/* field_load ******************************************************************
+
+   Load everything about a class field from the class file and fill a
+   fieldinfo structure.
+
+*******************************************************************************/
+
+#define field_load_NOVALUE  0xffffffff /* must be bigger than any u2 value! */
+
+bool field_load(classbuffer *cb, fieldinfo *f, descriptor_pool *descpool)
+{
+       classinfo *c;
+       u4 attrnum, i;
+       u4 pindex = field_load_NOVALUE;     /* constantvalue_index */
+       utf *u;
+
+       /* Get class. */
+
+       c = cb->clazz;
+
+       f->clazz = c;
+
+       /* Get access flags. */
+
+       if (!suck_check_classbuffer_size(cb, 2 + 2 + 2))
+               return false;
+
+       f->flags = suck_u2(cb);
+
+       /* Get name. */
+
+       if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
+               return false;
+
+       f->name = u;
+
+       /* Get descriptor. */
+
+       if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
+               return false;
+
+       f->descriptor = u;
+       f->parseddesc = NULL;
+
+       if (!descriptor_pool_add(descpool, u, NULL))
+               return false;
+
+       /* descriptor_pool_add accepts method descriptors, so we have to
+          check against them here before the call of
+          descriptor_to_basic_type below. */
+
+       if (u->text[0] == '(') {
+               exceptions_throw_classformaterror(c, "Method descriptor used for field");
+               return false;
+       }
+
+#ifdef ENABLE_VERIFIER
+       if (opt_verify) {
+               /* check name */
+               if (!is_valid_name_utf(f->name) || f->name->text[0] == '<') {
+                       exceptions_throw_classformaterror(c,
+                                                                                         "Illegal Field name \"%s\"",
+                                                                                         f->name->text);
+                       return false;
+               }
+
+               /* check flag consistency */
+               i = f->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED);
+
+               if ((i != 0 && i != ACC_PUBLIC && i != ACC_PRIVATE && i != ACC_PROTECTED) ||
+                       ((f->flags & (ACC_FINAL | ACC_VOLATILE)) == (ACC_FINAL | ACC_VOLATILE))) {
+                       exceptions_throw_classformaterror(c,
+                                                                                         "Illegal field modifiers: 0x%X",
+                                                                                         f->flags);
+                       return false;
+               }
+
+               if (c->flags & ACC_INTERFACE) {
+                       if (((f->flags & (ACC_STATIC | ACC_PUBLIC | ACC_FINAL))
+                               != (ACC_STATIC | ACC_PUBLIC | ACC_FINAL)) ||
+                               f->flags & ACC_TRANSIENT) {
+                               exceptions_throw_classformaterror(c,
+                                                                                                 "Illegal field modifiers: 0x%X",
+                                                                                                 f->flags);
+                               return false;
+                       }
+               }
+       }
+#endif /* ENABLE_VERIFIER */
+
+       /* data type */
+
+       f->type = descriptor_to_basic_type(f->descriptor);
+
+       /* For static-fields allocate memory for the value and set the
+          value to 0. */
+
+       if (f->flags & ACC_STATIC) {
+               switch (f->type) {
+               case TYPE_INT:
+               case TYPE_LNG:
+               case TYPE_FLT:
+               case TYPE_DBL:
+                       f->value = NEW(imm_union);
+                       break;
+
+               case TYPE_ADR:
+#if !defined(ENABLE_GC_BOEHM)
+                       f->value = NEW(imm_union);
+#else
+                       f->value = GCNEW_UNCOLLECTABLE(imm_union, 1);
+#endif
+                       break;
+
+               default:
+                       vm_abort("field_load: invalid field type %d", f->type);
+               }
+
+               /* Set the field to zero, for float and double fields set the
+                  correct 0.0 value. */
+
+               switch (f->type) {
+               case TYPE_INT:
+               case TYPE_LNG:
+               case TYPE_ADR:
+                       f->value->l = 0;
+                       break;
+
+               case TYPE_FLT:
+                       f->value->f = 0.0;
+                       break;
+
+               case TYPE_DBL:
+                       f->value->d = 0.0;
+                       break;
+               }
+       }
+       else {
+               /* For instance-fields set the offset to 0. */
+
+               f->offset = 0;
+
+               /* For final fields, which are not static, we need a value
+                  structure. */
+
+               if (f->flags & ACC_FINAL) {
+                       f->value = NEW(imm_union);
+                       /* XXX hack */
+                       f->value->l = 0;
+               }
+
+               switch (f->type) {
+               case TYPE_ADR:
+                       c->flags |= ACC_CLASS_HAS_POINTERS;
+                       break;
+               }
+       }
+
+       /* read attributes */
+
+       if (!suck_check_classbuffer_size(cb, 2))
+               return false;
+
+       attrnum = suck_u2(cb);
+
+       for (i = 0; i < attrnum; i++) {
+               if (!suck_check_classbuffer_size(cb, 2))
+                       return false;
+
+               if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
+                       return false;
+
+               if (u == utf_ConstantValue) {
+                       if (!suck_check_classbuffer_size(cb, 4 + 2))
+                               return false;
+
+                       /* check attribute length */
+
+                       if (suck_u4(cb) != 2) {
+                               exceptions_throw_classformaterror(c, "Wrong size for VALUE attribute");
+                               return false;
+                       }
+                       
+                       /* constant value attribute */
+
+                       if (pindex != field_load_NOVALUE) {
+                               exceptions_throw_classformaterror(c, "Multiple ConstantValue attributes");
+                               return false;
+                       }
+                       
+                       /* index of value in constantpool */
+
+                       pindex = suck_u2(cb);
+               
+                       /* initialize field with value from constantpool */             
+
+                       switch (f->type) {
+                       case TYPE_INT: {
+                               constant_integer *ci; 
+
+                               if (!(ci = class_getconstant(c, pindex, CONSTANT_Integer)))
+                                       return false;
+
+                               f->value->i = ci->value;
+                       }
+                       break;
+                                       
+                       case TYPE_LNG: {
+                               constant_long *cl; 
+
+                               if (!(cl = class_getconstant(c, pindex, CONSTANT_Long)))
+                                       return false;
+
+                               f->value->l = cl->value;
+                       }
+                       break;
+
+                       case TYPE_FLT: {
+                               constant_float *cf;
+
+                               if (!(cf = class_getconstant(c, pindex, CONSTANT_Float)))
+                                       return false;
+
+                               f->value->f = cf->value;
+                       }
+                       break;
+                                                                                       
+                       case TYPE_DBL: {
+                               constant_double *cd;
+
+                               if (!(cd = class_getconstant(c, pindex, CONSTANT_Double)))
+                                       return false;
+
+                               f->value->d = cd->value;
+                       }
+                       break;
+                                               
+                       case TYPE_ADR:
+                               if (!(u = class_getconstant(c, pindex, CONSTANT_String)))
+                                       return false;
+
+                               /* Create Java-string from compressed UTF8-string. */
+
+                               f->value->a = literalstring_new(u);
+                               break;
+       
+                       default: 
+                               vm_abort("field_load: invalid field type %d", f->type);
+                       }
+               }
+#if defined(ENABLE_JAVASE)
+               else if (u == utf_Signature) {
+                       /* Signature */
+
+                       if (!loader_load_attribute_signature(cb, &(f->signature)))
+                               return false;
+               }
+
+#if defined(ENABLE_ANNOTATIONS)
+               else if (u == utf_RuntimeVisibleAnnotations) {
+                       /* RuntimeVisibleAnnotations */
+                       if (!annotation_load_field_attribute_runtimevisibleannotations(cb, f))
+                               return false;
+               }
+               else if (u == utf_RuntimeInvisibleAnnotations) {
+                       /* RuntimeInvisibleAnnotations */
+                       if (!annotation_load_field_attribute_runtimeinvisibleannotations(cb, f))
+                               return false;
+               }
+#endif
+#endif
+               else {
+                       /* unknown attribute */
+
+                       if (!loader_skip_attribute_body(cb))
+                               return false;
+               }
+       }
+
+       /* everything was ok */
+
+       return true;
+}
+
+
+/* field_get_type **************************************************************
+
+   Returns the type of the field as class.
+
+*******************************************************************************/
+
+classinfo *field_get_type(fieldinfo *f)
+{
+       typedesc  *td;
+       utf       *u;
+       classinfo *c;
+
+       td = f->parseddesc;
+
+       if (td->type == TYPE_ADR) {
+               assert(td->classref);
+
+               u = td->classref->name;
+
+               /* load the class of the field-type with the field's
+                  classloader */
+
+               c = load_class_from_classloader(u, f->clazz->classloader);
+       }
+       else {
+               c = Primitive_get_class_by_type(td->primitivetype);
+       }
+
+       return c;
+}
+
+
 /* field_free ******************************************************************
 
    Frees a fields' resources.
 
 void field_free(fieldinfo *f)
 {
-       /* empty */
+       /* free memory for fields which have a value */
+
+       if (f->value)
+#if defined(ENABLE_GC_BOEHM)
+               if (f->type != TYPE_ADR)
+#endif
+                       FREE(f->value, imm_union);
+}
+
+
+/* field_get_annotations ******************************************************
+
+   Get a fields' unparsed annotations in a byte array.
+
+   IN:
+       f........the field of which the annotations should be returned
+
+   RETURN VALUE:
+       The unparsed annotations in a byte array (or NULL if there aren't any).
+
+*******************************************************************************/
+
+java_handle_bytearray_t *field_get_annotations(fieldinfo *f)
+{
+#if defined(ENABLE_ANNOTATIONS)
+       classinfo               *c;           /* declaring class           */
+       int                      slot;        /* slot of this field        */
+       java_handle_bytearray_t *annotations; /* unparsed annotations      */
+       java_handle_t           *field_annotations;  /* array of unparsed  */
+                      /* annotations of all fields of the declaring class */
+
+       c           = f->clazz;
+       slot        = f - c->fields;
+       annotations = NULL;
+
+       LLNI_classinfo_field_get(c, field_annotations, field_annotations);
+
+       /* the field_annotations array might be shorter then the field
+        * count if the fields above a certain index have no annotations.
+        */
+       if (field_annotations != NULL &&
+               array_length_get(field_annotations) > slot) {
+               annotations = (java_handle_bytearray_t*)array_objectarray_element_get(
+                               (java_handle_objectarray_t*)field_annotations, slot);
+       }
+       
+       return annotations;
+#else
+       return NULL;
+#endif
 }
 
 
@@ -93,13 +475,17 @@ void field_print(fieldinfo *f)
                return;
        }
 
-       utf_display_printable_ascii_classname(f->class->name);
+       utf_display_printable_ascii_classname(f->clazz->name);
        printf(".");
        utf_display_printable_ascii(f->name);
        printf(" ");
        utf_display_printable_ascii(f->descriptor);     
 
        field_printflags(f);
+
+       if (!(f->flags & ACC_STATIC)) {
+               printf(", offset: %d", f->offset);
+       }
 }
 #endif
 
@@ -172,4 +558,5 @@ void field_fieldref_println(constant_FMIref *fr)
  * c-basic-offset: 4
  * tab-width: 4
  * End:
+ * vim:noexpandtab:sw=4:ts=4:
  */