* Removed all Id tags.
[cacao.git] / src / vmcore / annotation.c
index 86e7f115e4aca4991731a1b55c8b9c027e0e9efa..81ec65ede6bd9eaadbef0ab814cd7b022ded911d 100644 (file)
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   $Id: utf8.h 5920 2006-11-05 21:23:09Z twisti $
-
 */
 
-
 #include "config.h"
+
+#include <assert.h>
+
 #include "vm/types.h"
 
 #include "mm/memory.h"
 
+#include "toolbox/logging.h"
+
 #include "vmcore/annotation.h"
 #include "vmcore/class.h"
 #include "vmcore/suck.h"
 
+#if !defined(ENABLE_ANNOTATIONS)
+# error annotation support has to be enabled when compling this file!
+#endif
+
+/* annotation_bytearray_new ***************************************************
+
+   Allocate a new bytearray.
+
+*******************************************************************************/
+
+annotation_bytearray_t *annotation_bytearray_new(uint32_t size)
+{
+       annotation_bytearray_t *ba =
+               mem_alloc(sizeof(uint32_t) + sizeof(uint8_t) * size);
+
+       if (ba != NULL) {
+               ba->size = size;
+       }
+
+       return ba;
+}
+
+
+/* annotation_bytearray_free **************************************************
+
+   Free a bytearray.
+
+*******************************************************************************/
+
+void annotation_bytearray_free(annotation_bytearray_t *ba)
+{
+       if (ba != NULL) {
+               mem_free(ba, sizeof(uint32_t) + sizeof(uint8_t) * ba->size);
+       }
+}
+
+
+/* annotation_bytearrays_new **************************************************
+
+   Allocate a new array of bytearrays.
+
+*******************************************************************************/
+
+annotation_bytearrays_t *annotation_bytearrays_new(uint32_t size)
+{
+       annotation_bytearrays_t *bas =
+               mem_alloc(sizeof(uint32_t) + sizeof(annotation_bytearray_t*) * size);
+
+       if (bas != NULL) {
+               bas->size = size;
+       }
+
+       return bas;
+}
+
+
+/* annotation_bytearrays_resize ***********************************************
+
+   Resize an array of bytearrays.
+
+*******************************************************************************/
+
+bool annotation_bytearrays_resize(annotation_bytearrays_t **bas,
+       uint32_t size)
+{
+       annotation_bytearrays_t *newbas = NULL;
+       uint32_t i;
+       uint32_t minsize;
+       
+       assert(bas != NULL);
+       
+       newbas = annotation_bytearrays_new(size);
+       
+       if (newbas == NULL) {
+               return false;
+       }
+       
+       if (*bas != NULL) {
+               minsize = size < (*bas)->size ? size : (*bas)->size;
+
+               for (i = size; i < (*bas)->size; ++ i) {
+                       annotation_bytearray_free((*bas)->data[i]);
+               }
+
+               for (i = 0; i < minsize; ++i) {
+                       newbas->data[i] = (*bas)->data[i];
+               }
+       }
+
+       *bas = newbas;
+
+       return true;
+}
+
+
+/* annotation_bytearrays_insert ***********************************************
+
+   Insert a bytearray into an array of bytearrays.
 
-/* annotation_load_attribute_runtimevisibleannotations *************************
+*******************************************************************************/
+
+bool annotation_bytearrays_insert(annotation_bytearrays_t **bas,
+       uint32_t index, annotation_bytearray_t *ba)
+{
+       assert(bas != NULL);
+
+       if (ba != NULL) {
+               if (*bas == NULL || (*bas)->size <= index) {
+                       if (!annotation_bytearrays_resize(bas, index + 1)) {
+                               return false;
+                       }
+               }
+               else {
+                       /* free old bytearray (if any) */
+                       annotation_bytearray_free((*bas)->data[index]);
+               }
+
+               /* insert new bytearray */
+               (*bas)->data[index] = ba;
+       }
+       else if (*bas != NULL && (*bas)->size > index) {
+               /* do not resize when just inserting NULL,
+                * but free old bytearray if there is any */
+               annotation_bytearray_free((*bas)->data[index]);
+       }
+
+       return true;
+}
+
+
+/* annotation_bytearrays_free *************************************************
+
+   Free an array of bytearrays.
+
+*******************************************************************************/
 
-   RuntimeVisibleAnnotations_attribute {
+void annotation_bytearrays_free(annotation_bytearrays_t *bas)
+{
+       uint32_t i;
+
+       if (bas != NULL) {
+               for (i = 0; i < bas->size; ++ i) {
+                       annotation_bytearray_free(bas->data[i]);
+               }
+
+               mem_free(bas, sizeof(uint32_t) +
+                       sizeof(annotation_bytearray_t*) * bas->size);
+       }
+}
+
+
+/* annotation_load_attribute_body *********************************************
+
+   This function loads the body of a generic attribute.
+
+   XXX: Maybe this function should be called loader_load_attribute_body and
+        located in vmcore/loader.c?
+
+   attribute_info {
        u2 attribute_name_index;
        u4 attribute_length;
-       u2 num_annotations;
-       annotation annotations[num_annotations];
+       u1 info[attribute_length];
    }
 
-   annotation {
-       u2 type_index;
-       u2 num_element_value_pairs;
-       {
-            u2            element_name_index;
-            element_value element;
-       } element_value_pairs[num_element_value_pairs];
-   }
+   IN:
+       cb.................classbuffer from which to read the data.
+       errormsg_prefix....prefix for error messages (if any).
 
-   element_value {
-       u1 tag;
-       union {
-           u2 const_value_index;
-           {
-               u2 type_name_index;
-               u2 const_name_index;
-           } enum_const_value;
-           u2 class_info_index;
-           annotation annotation_value;
-           {
-               u2 num_values;
-               element_value values[num_values];
-           } array_value;
-       } value;
-   }
+   OUT:
+       attribute..........bytearray-pointer which will be set to the read data.
+   
+   RETURN VALUE:
+       true if all went good. false otherwhise.
 
 *******************************************************************************/
 
-bool annotation_load_attribute_runtimevisibleannotations(classbuffer *cb)
+static bool annotation_load_attribute_body(classbuffer *cb,
+       annotation_bytearray_t **attribute, const char *errormsg_prefix)
 {
-       classinfo       *c;
-       u4               attribute_length;
-       u2               num_annotations;
-       annotation_t    *annotations;
-       element_value_t *element_value;
-       u2               type_index;
-       u2               num_element_value_pairs;
-       u2               element_name_index;
-       u4               i, j;
+       uint32_t size = 0;
+       annotation_bytearray_t *ba = NULL;
 
-       /* get classinfo */
+       assert(cb != NULL);
+       assert(attribute != NULL);
 
-       c = cb->class;
+       if (!suck_check_classbuffer_size(cb, 4)) {
+               log_println("%s: size missing", errormsg_prefix);
+               return false;
+       }
 
-       if (!suck_check_classbuffer_size(cb, 4 + 2))
+       /* load attribute_length */
+       size = suck_u4(cb);
+       
+       if (!suck_check_classbuffer_size(cb, size)) {
+               log_println("%s: invalid size", errormsg_prefix);
                return false;
+       }
+       
+       /* if attribute_length == 0 then NULL is
+        * the right value for this attribute */
+       if (size > 0) {
+               ba = annotation_bytearray_new(size);
+
+               if (ba == NULL) {
+                       /* out of memory */
+                       return false;
+               }
+
+               /* load data */
+               suck_nbytes(ba->data, cb, size);
+
+               /* return data */
+               *attribute = ba;
+       }
+       
+       return true;
+}
 
-       /* attribute_length */
 
-       attribute_length = suck_u4(cb);
+/* annotation_load_method_attribute_annotationdefault *************************
 
-       if (!suck_check_classbuffer_size(cb, attribute_length))
+   Load annotation default value.
+
+   AnnotationDefault_attribute {
+       u2 attribute_name_index;
+       u4 attribute_length;
+       element_value default_value;
+   }
+
+   IN:
+       cb.................classbuffer from which to read the data.
+       m..................methodinfo for the method of which the annotation
+                          default value is read and into which the value is
+                          stored into.
+
+   RETURN VALUE:
+       true if all went good. false otherwhise.
+
+*******************************************************************************/
+
+bool annotation_load_method_attribute_annotationdefault(
+               classbuffer *cb, methodinfo *m)
+{
+       int slot = 0;
+       annotation_bytearray_t   *annotationdefault  = NULL;
+       annotation_bytearrays_t **annotationdefaults = NULL;
+
+       assert(cb != NULL);
+       assert(m != NULL);
+
+       annotationdefaults = &(m->class->method_annotationdefaults);
+
+       if (!annotation_load_attribute_body(
+               cb, &annotationdefault,
+               "invalid annotation default method attribute")) {
                return false;
+       }
+
+       if (annotationdefault != NULL) {
+               slot = m - m->class->methods;
 
-       /* get number of annotations */
+               if (!annotation_bytearrays_insert(
+                       annotationdefaults, slot, annotationdefault)) {
+                       annotation_bytearray_free(annotationdefault);
+                       return false;
+               }
+       }
 
-       num_annotations = suck_u2(cb);
+       return true;
+}
 
-       printf("num_annotations: %d\n", num_annotations);
 
-       /* allocate annotations-array */
+/* annotation_load_method_attribute_runtimevisibleparameterannotations ********
 
-       annotations = MNEW(annotation_t, num_annotations);
+   Load runtime visible parameter annotations.
 
-       /* parse all annotations */
+   RuntimeVisibleParameterAnnotations_attribute {
+       u2 attribute_name_index;
+       u4 attribute_length;
+       u1 num_parameters;
+       {
+           u2 num_annotations;
+           annotation annotations[num_annotations];
+       } parameter_annotations[num_parameters];
+   }
 
-       for (i = 0; i < num_annotations; i++) {
-               /* get annotation type */
+   IN:
+       cb.................classbuffer from which to read the data.
+       m..................methodinfo for the method of which the parameter
+                          annotations are read and into which the parameter
+                          annotations are stored into.
 
-               type_index = suck_u2(cb);
+   RETURN VALUE:
+       true if all went good. false otherwhise.
 
-               if (!(annotations[i].type =
-                         class_getconstant(c, type_index, CONSTANT_Utf8)))
+*******************************************************************************/
+
+bool annotation_load_method_attribute_runtimevisibleparameterannotations(
+               classbuffer *cb, methodinfo *m)
+{
+       int slot = 0;
+       annotation_bytearray_t  *annotations = NULL;
+       annotation_bytearrays_t **parameterannotations = NULL;
+
+       assert(cb != NULL);
+       assert(m != NULL);
+
+       parameterannotations = &(m->class->method_parameterannotations);
+
+       if (!annotation_load_attribute_body(
+               cb, &annotations,
+               "invalid runtime visible parameter annotations method attribute")) {
+               return false;
+       }
+
+       if (annotations != NULL) {
+               slot = m - m->class->methods;
+
+               if (!annotation_bytearrays_insert(
+                       parameterannotations, slot, annotations)) {
+                       annotation_bytearray_free(annotations);
                        return false;
+               }
+       }
+
+       return true;
+}
+
 
-               printf("type: ");
-               utf_display_printable_ascii(annotations[i].type);
-               printf("\n");
+/* annotation_load_method_attribute_runtimeinvisibleparameterannotations ******
+   Load runtime invisible parameter annotations.
 
-               /* get number of element values */
+   <quote cite="http://jcp.org/en/jsr/detail?id=202">
+   The RuntimeInvisibleParameterAnnotations attribute is similar to the
+   RuntimeVisibleParameterAnnotations attribute, except that the annotations
+   represented by a RuntimeInvisibleParameterAnnotations attribute must not be
+   made available for return by reflective APIs, unless the the JVM has
+   specifically been instructed to retain these annotations via some
+   implementation-specific mechanism such as a command line flag. In the
+   absence of such instructions, the JVM ignores this attribute.
+   </quote>
 
-               num_element_value_pairs = suck_u2(cb);
+   Hotspot loads them into the same bytearray as the runtime visible parameter
+   annotations (after the runtime visible parameter annotations). But in J2SE
+   the bytearray will only be parsed as if ther is only one annotation
+   structure in it, so the runtime invisible parameter annotatios will be
+   ignored.
 
-               printf("num_element_value_pairs: %d\n", num_element_value_pairs);
+   Therefore I do not even bother to read them.
 
-               element_value = MNEW(element_value_t, num_element_value_pairs);
+   RuntimeInvisibleParameterAnnotations_attribute {
+       u2 attribute_name_index;
+       u4 attribute_length;
+       u1 num_parameters;
+       {
+           u2 num_annotations;
+           annotation annotations[num_annotations];
+       } parameter_annotations[num_parameters];
+   }
 
-               /* parse all element values */
+   IN:
+       cb.................classbuffer from which to read the data.
+       m..................methodinfo for the method of which the parameter
+                          annotations are read and into which the parameter
+                          annotations are stored into.
 
-               for (j = 0; j < num_element_value_pairs; j++) {
-                       /* get element name */
+   RETURN VALUE:
+       true if all went good. false otherwhise.
 
-                       element_name_index = suck_u2(cb);
+*******************************************************************************/
 
-                       if (!(element_value[j].name =
-                                 class_getconstant(c, element_name_index, CONSTANT_Utf8)))
-                               return false;
+bool annotation_load_method_attribute_runtimeinvisibleparameterannotations(
+               classbuffer *cb, methodinfo *m)
+{
+       return loader_skip_attribute_body(cb);
+}
 
-                       /* get element tag */
 
-                       element_value[i].tag = suck_u1(cb);
+/* annotation_load_class_attribute_runtimevisibleannotations ******************
+   
+   Load runtime visible annotations of a class.
+   
+*******************************************************************************/
+
+bool annotation_load_class_attribute_runtimevisibleannotations(
+       classbuffer *cb)
+{
+       return annotation_load_attribute_body(
+               cb, &(cb->class->annotations),
+               "invalid runtime visible annotations class attribute");
+}
+
+
+/* annotation_load_class_attribute_runtimeinvisibleannotations ****************
+   
+   Load runtime invisible annotations of a class (just skip them).
+   
+*******************************************************************************/
+
+bool annotation_load_class_attribute_runtimeinvisibleannotations(
+       classbuffer *cb)
+{
+       return loader_skip_attribute_body(cb);
+}
+
+
+/* annotation_load_method_attribute_runtimevisibleannotations *****************
+   
+   Load runtime visible annotations of a method.
+   
+*******************************************************************************/
+
+bool annotation_load_method_attribute_runtimevisibleannotations(
+       classbuffer *cb, methodinfo *m)
+{
+       int slot = 0;
+       annotation_bytearray_t  *annotations = NULL;
+       annotation_bytearrays_t **method_annotations = NULL;
+
+       assert(cb != NULL);
+       assert(m != NULL);
+
+       method_annotations = &(m->class->method_annotations);
+
+       if (!annotation_load_attribute_body(
+               cb, &annotations,
+               "invalid runtime visible annotations method attribute")) {
+               return false;
+       }
+
+       if (annotations != NULL) {
+               slot = m - m->class->methods;
+
+               if (!annotation_bytearrays_insert(
+                       method_annotations, slot, annotations)) {
+                       annotation_bytearray_free(annotations);
+                       return false;
                }
+       }
+
+       return true;
+}
+
+
+/* annotation_load_method_attribute_runtimeinvisibleannotations ****************
+   
+   Load runtime invisible annotations of a method (just skip them).
+   
+*******************************************************************************/
+
+bool annotation_load_method_attribute_runtimeinvisibleannotations(
+       classbuffer *cb, methodinfo *m)
+{
+       return loader_skip_attribute_body(cb);
+}
+
+
+/* annotation_load_field_attribute_runtimevisibleannotations ******************
+   
+   Load runtime visible annotations of a field.
+   
+*******************************************************************************/
+
+bool annotation_load_field_attribute_runtimevisibleannotations(
+       classbuffer *cb, fieldinfo *f)
+{
+       int slot = 0;
+       annotation_bytearray_t  *annotations = NULL;
+       annotation_bytearrays_t **field_annotations = NULL;
+
+       assert(cb != NULL);
+       assert(f != NULL);
 
-               /* store element value data */
+       field_annotations = &(f->class->field_annotations);
 
-               annotations[i].element_valuescount = num_element_value_pairs;
-               annotations[i].element_values      = element_value;
+       if (!annotation_load_attribute_body(
+               cb, &annotations,
+               "invalid runtime visible annotations field attribute")) {
+               return false;
        }
 
-       /* store annotation variables */
+       if (annotations != NULL) {
+               slot = f - f->class->fields;
 
-       c->runtimevisibleannotationscount = num_annotations;
-       c->runtimevisibleannotations      = annotations;
+               if (!annotation_bytearrays_insert(
+                       field_annotations, slot, annotations)) {
+                       annotation_bytearray_free(annotations);
+                       return false;
+               }
+       }
 
        return true;
 }
 
 
+/* annotation_load_field_attribute_runtimeinvisibleannotations ****************
+   
+   Load runtime invisible annotations of a field (just skip them).
+   
+*******************************************************************************/
+
+bool annotation_load_field_attribute_runtimeinvisibleannotations(
+       classbuffer *cb, fieldinfo *f)
+{
+       return loader_skip_attribute_body(cb);
+}
+
+
 /*
  * These are local overrides for various environment variables in Emacs.
  * Please do not remove this and leave it at the end of the file, where