/* 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
}
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
* c-basic-offset: 4
* tab-width: 4
* End:
+ * vim:noexpandtab:sw=4:ts=4:
*/