# HG changeset patch # User coleenp # Date 1360609582 18000 # Node ID df8faef6efafc6c8b2030f5f418fb531dc2257e0 # Parent 753e5733b5c9e24ccb3f48362a4ad49d9aebbd3a 8007320: NPG: move method annotations Summary: allocate method annotations and attach to ConstMethod if present Reviewed-by: dcubed, jiangli, sspitsyn, iklam diff -r 753e5733b5c9 -r df8faef6efaf hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstMethod.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstMethod.java Fri Feb 08 16:56:03 2013 -0800 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstMethod.java Mon Feb 11 14:06:22 2013 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,12 +49,18 @@ private static int HAS_LOCALVARIABLE_TABLE; private static int HAS_EXCEPTION_TABLE; private static int HAS_GENERIC_SIGNATURE; + private static int HAS_METHOD_ANNOTATIONS; + private static int HAS_PARAMETER_ANNOTATIONS; + private static int HAS_DEFAULT_ANNOTATIONS; + private static int HAS_TYPE_ANNOTATIONS; + + private static final int sizeofShort = 2; private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { Type type = db.lookupType("ConstMethod"); constants = new MetadataField(type.getAddressField("_constants"), 0); constMethodSize = new CIntField(type.getCIntegerField("_constMethod_size"), 0); - flags = new ByteField(type.getJByteField("_flags"), 0); + flags = new CIntField(type.getCIntegerField("_flags"), 0); // enum constants for flags HAS_LINENUMBER_TABLE = db.lookupIntConstant("ConstMethod::_has_linenumber_table").intValue(); @@ -62,6 +68,10 @@ HAS_LOCALVARIABLE_TABLE = db.lookupIntConstant("ConstMethod::_has_localvariable_table").intValue(); HAS_EXCEPTION_TABLE = db.lookupIntConstant("ConstMethod::_has_exception_table").intValue(); HAS_GENERIC_SIGNATURE = db.lookupIntConstant("ConstMethod::_has_generic_signature").intValue(); + HAS_METHOD_ANNOTATIONS = db.lookupIntConstant("ConstMethod::_has_method_annotations").intValue(); + HAS_PARAMETER_ANNOTATIONS = db.lookupIntConstant("ConstMethod::_has_parameter_annotations").intValue(); + HAS_DEFAULT_ANNOTATIONS = db.lookupIntConstant("ConstMethod::_has_default_annotations").intValue(); + HAS_TYPE_ANNOTATIONS = db.lookupIntConstant("ConstMethod::_has_type_annotations").intValue(); // Size of Java bytecodes allocated immediately after ConstMethod*. codeSize = new CIntField(type.getCIntegerField("_code_size"), 0); @@ -92,7 +102,7 @@ // Fields private static MetadataField constants; private static CIntField constMethodSize; - private static ByteField flags; + private static CIntField flags; private static CIntField codeSize; private static CIntField nameIndex; private static CIntField signatureIndex; @@ -123,7 +133,7 @@ return constMethodSize.getValue(this); } - public byte getFlags() { + public long getFlags() { return flags.getValue(this); } @@ -253,7 +263,7 @@ public void iterateFields(MetadataVisitor visitor) { visitor.doMetadata(constants, true); visitor.doCInt(constMethodSize, true); - visitor.doByte(flags, true); + visitor.doCInt(flags, true); visitor.doCInt(codeSize, true); visitor.doCInt(nameIndex, true); visitor.doCInt(signatureIndex, true); @@ -381,6 +391,22 @@ return (getFlags() & HAS_GENERIC_SIGNATURE) != 0; } + private boolean hasMethodAnnotations() { + return (getFlags() & HAS_METHOD_ANNOTATIONS) != 0; + } + + private boolean hasParameterAnnotations() { + return (getFlags() & HAS_PARAMETER_ANNOTATIONS) != 0; + } + + private boolean hasDefaultAnnotations() { + return (getFlags() & HAS_DEFAULT_ANNOTATIONS) != 0; + } + + private boolean hasTypeAnnotations() { + return (getFlags() & HAS_TYPE_ANNOTATIONS) != 0; + } + //--------------------------------------------------------------------------- // Internals only below this point @@ -400,9 +426,15 @@ return offsetOfCodeEnd() + (isNative() ? 2 * VM.getVM().getAddressSize() : 0); } - // Offset of last short in Method* + // Offset of last short in Method* before annotations, if present private long offsetOfLastU2Element() { - return getSize() * VM.getVM().getObjectHeap().getOopSize() - 2; + int offset = 0; + if (hasMethodAnnotations()) offset++; + if (hasParameterAnnotations()) offset++; + if (hasTypeAnnotations()) offset++; + if (hasDefaultAnnotations()) offset++; + long wordSize = VM.getVM().getObjectHeap().getOopSize(); + return (getSize() * wordSize) - (offset * wordSize) - sizeofShort; } // Offset of the generic signature index @@ -411,7 +443,7 @@ } private long offsetOfCheckedExceptionsLength() { - return hasGenericSignature() ? offsetOfLastU2Element() - 2 : + return hasGenericSignature() ? offsetOfLastU2Element() - sizeofShort : offsetOfLastU2Element(); } @@ -461,11 +493,11 @@ } if (hasExceptionTable()) { - return offsetOfExceptionTable() - 2; + return offsetOfExceptionTable() - sizeofShort; } else if (hasCheckedExceptions()) { - return offsetOfCheckedExceptions() - 2; + return offsetOfCheckedExceptions() - sizeofShort; } else { - return hasGenericSignature() ? offsetOfLastU2Element() - 2 : + return hasGenericSignature() ? offsetOfLastU2Element() - sizeofShort : offsetOfLastU2Element(); } } @@ -493,9 +525,9 @@ Assert.that(hasExceptionTable(), "should only be called if table is present"); } if (hasCheckedExceptions()) { - return offsetOfCheckedExceptions() - 2; + return offsetOfCheckedExceptions() - sizeofShort; } else { - return hasGenericSignature() ? offsetOfLastU2Element() - 2 : + return hasGenericSignature() ? offsetOfLastU2Element() - sizeofShort : offsetOfLastU2Element(); } } diff -r 753e5733b5c9 -r df8faef6efaf hotspot/src/share/vm/classfile/classFileParser.cpp --- a/hotspot/src/share/vm/classfile/classFileParser.cpp Fri Feb 08 16:56:03 2013 -0800 +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Mon Feb 11 14:06:22 2013 -0500 @@ -1856,6 +1856,154 @@ #define MAX_CODE_SIZE 65535 #define INITIAL_MAX_LVT_NUMBER 256 +/* Copy class file LVT's/LVTT's into the HotSpot internal LVT. + * + * Rules for LVT's and LVTT's are: + * - There can be any number of LVT's and LVTT's. + * - If there are n LVT's, it is the same as if there was just + * one LVT containing all the entries from the n LVT's. + * - There may be no more than one LVT entry per local variable. + * Two LVT entries are 'equal' if these fields are the same: + * start_pc, length, name, slot + * - There may be no more than one LVTT entry per each LVT entry. + * Each LVTT entry has to match some LVT entry. + * - HotSpot internal LVT keeps natural ordering of class file LVT entries. + */ +void ClassFileParser::copy_localvariable_table(ConstMethod* cm, + int lvt_cnt, + u2* localvariable_table_length, + u2** localvariable_table_start, + int lvtt_cnt, + u2* localvariable_type_table_length, + u2** localvariable_type_table_start, + TRAPS) { + + LVT_Hash** lvt_Hash = NEW_RESOURCE_ARRAY(LVT_Hash*, HASH_ROW_SIZE); + initialize_hashtable(lvt_Hash); + + // To fill LocalVariableTable in + Classfile_LVT_Element* cf_lvt; + LocalVariableTableElement* lvt = cm->localvariable_table_start(); + + for (int tbl_no = 0; tbl_no < lvt_cnt; tbl_no++) { + cf_lvt = (Classfile_LVT_Element *) localvariable_table_start[tbl_no]; + for (int idx = 0; idx < localvariable_table_length[tbl_no]; idx++, lvt++) { + copy_lvt_element(&cf_lvt[idx], lvt); + // If no duplicates, add LVT elem in hashtable lvt_Hash. + if (LVT_put_after_lookup(lvt, lvt_Hash) == false + && _need_verify + && _major_version >= JAVA_1_5_VERSION) { + clear_hashtable(lvt_Hash); + ConstantPool* cp = cm->constants(); + classfile_parse_error("Duplicated LocalVariableTable attribute " + "entry for '%s' in class file %s", + cp->symbol_at(lvt->name_cp_index)->as_utf8(), + CHECK); + } + } + } + + // To merge LocalVariableTable and LocalVariableTypeTable + Classfile_LVT_Element* cf_lvtt; + LocalVariableTableElement lvtt_elem; + + for (int tbl_no = 0; tbl_no < lvtt_cnt; tbl_no++) { + cf_lvtt = (Classfile_LVT_Element *) localvariable_type_table_start[tbl_no]; + for (int idx = 0; idx < localvariable_type_table_length[tbl_no]; idx++) { + copy_lvt_element(&cf_lvtt[idx], &lvtt_elem); + int index = hash(&lvtt_elem); + LVT_Hash* entry = LVT_lookup(&lvtt_elem, index, lvt_Hash); + if (entry == NULL) { + if (_need_verify) { + clear_hashtable(lvt_Hash); + ConstantPool* cp = cm->constants(); + classfile_parse_error("LVTT entry for '%s' in class file %s " + "does not match any LVT entry", + cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(), + CHECK); + } + } else if (entry->_elem->signature_cp_index != 0 && _need_verify) { + clear_hashtable(lvt_Hash); + ConstantPool* cp = cm->constants(); + classfile_parse_error("Duplicated LocalVariableTypeTable attribute " + "entry for '%s' in class file %s", + cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(), + CHECK); + } else { + // to add generic signatures into LocalVariableTable + entry->_elem->signature_cp_index = lvtt_elem.descriptor_cp_index; + } + } + } + clear_hashtable(lvt_Hash); +} + + +void ClassFileParser::copy_method_annotations(ClassLoaderData* loader_data, + ConstMethod* cm, + u1* runtime_visible_annotations, + int runtime_visible_annotations_length, + u1* runtime_invisible_annotations, + int runtime_invisible_annotations_length, + u1* runtime_visible_parameter_annotations, + int runtime_visible_parameter_annotations_length, + u1* runtime_invisible_parameter_annotations, + int runtime_invisible_parameter_annotations_length, + u1* runtime_visible_type_annotations, + int runtime_visible_type_annotations_length, + u1* runtime_invisible_type_annotations, + int runtime_invisible_type_annotations_length, + u1* annotation_default, + int annotation_default_length, + TRAPS) { + + AnnotationArray* a; + + if (runtime_visible_annotations_length + + runtime_invisible_annotations_length > 0) { + a = assemble_annotations(loader_data, + runtime_visible_annotations, + runtime_visible_annotations_length, + runtime_invisible_annotations, + runtime_invisible_annotations_length, + CHECK); + cm->set_method_annotations(a); + } + + if (runtime_visible_parameter_annotations_length + + runtime_invisible_parameter_annotations_length > 0) { + a = assemble_annotations(loader_data, + runtime_visible_parameter_annotations, + runtime_visible_parameter_annotations_length, + runtime_invisible_parameter_annotations, + runtime_invisible_parameter_annotations_length, + CHECK); + cm->set_parameter_annotations(a); + } + + if (annotation_default_length > 0) { + a = assemble_annotations(loader_data, + annotation_default, + annotation_default_length, + NULL, + 0, + CHECK); + cm->set_default_annotations(a); + } + + if (runtime_visible_type_annotations_length + + runtime_invisible_type_annotations_length > 0) { + a = assemble_annotations(loader_data, + runtime_visible_type_annotations, + runtime_visible_type_annotations_length, + runtime_invisible_type_annotations, + runtime_invisible_type_annotations_length, + CHECK); + cm->set_type_annotations(a); + } +} + + // Note: the parse_method below is big and clunky because all parsing of the code and exceptions // attribute is inlined. This is cumbersome to avoid since we inline most of the parts in the // Method* to save footprint, so we only know the size of the resulting Method* when the @@ -1869,10 +2017,6 @@ constantPoolHandle cp, bool is_interface, AccessFlags *promoted_flags, - AnnotationArray** method_annotations, - AnnotationArray** method_parameter_annotations, - AnnotationArray** method_default_annotations, - AnnotationArray** method_type_annotations, TRAPS) { ClassFileStream* cfs = stream(); methodHandle nullHandle; @@ -2273,10 +2417,24 @@ } // All sizing information for a Method* is finally available, now create it + InlineTableSizes sizes( + total_lvt_length, + linenumber_table_length, + exception_table_length, + checked_exceptions_length, + method_parameters_length, + generic_signature_index, + runtime_visible_annotations_length + + runtime_invisible_annotations_length, + runtime_visible_parameter_annotations_length + + runtime_invisible_parameter_annotations_length, + runtime_visible_type_annotations_length + + runtime_invisible_type_annotations_length, + annotation_default_length, + 0); + Method* m = Method::allocate( - loader_data, code_length, access_flags, linenumber_table_length, - total_lvt_length, exception_table_length, checked_exceptions_length, - method_parameters_length, generic_signature_index, + loader_data, code_length, access_flags, &sizes, ConstMethod::NORMAL, CHECK_(nullHandle)); ClassLoadingService::add_class_method_size(m->size()*HeapWordSize); @@ -2347,107 +2505,37 @@ copy_u2_with_conversion((u2*) m->checked_exceptions_start(), checked_exceptions_start, size); } - /* Copy class file LVT's/LVTT's into the HotSpot internal LVT. - * - * Rules for LVT's and LVTT's are: - * - There can be any number of LVT's and LVTT's. - * - If there are n LVT's, it is the same as if there was just - * one LVT containing all the entries from the n LVT's. - * - There may be no more than one LVT entry per local variable. - * Two LVT entries are 'equal' if these fields are the same: - * start_pc, length, name, slot - * - There may be no more than one LVTT entry per each LVT entry. - * Each LVTT entry has to match some LVT entry. - * - HotSpot internal LVT keeps natural ordering of class file LVT entries. - */ + // Copy class file LVT's/LVTT's into the HotSpot internal LVT. if (total_lvt_length > 0) { - int tbl_no, idx; - promoted_flags->set_has_localvariable_table(); - - LVT_Hash** lvt_Hash = NEW_RESOURCE_ARRAY(LVT_Hash*, HASH_ROW_SIZE); - initialize_hashtable(lvt_Hash); - - // To fill LocalVariableTable in - Classfile_LVT_Element* cf_lvt; - LocalVariableTableElement* lvt = m->localvariable_table_start(); - - for (tbl_no = 0; tbl_no < lvt_cnt; tbl_no++) { - cf_lvt = (Classfile_LVT_Element *) localvariable_table_start[tbl_no]; - for (idx = 0; idx < localvariable_table_length[tbl_no]; idx++, lvt++) { - copy_lvt_element(&cf_lvt[idx], lvt); - // If no duplicates, add LVT elem in hashtable lvt_Hash. - if (LVT_put_after_lookup(lvt, lvt_Hash) == false - && _need_verify - && _major_version >= JAVA_1_5_VERSION ) { - clear_hashtable(lvt_Hash); - classfile_parse_error("Duplicated LocalVariableTable attribute " - "entry for '%s' in class file %s", - cp->symbol_at(lvt->name_cp_index)->as_utf8(), - CHECK_(nullHandle)); - } - } - } - - // To merge LocalVariableTable and LocalVariableTypeTable - Classfile_LVT_Element* cf_lvtt; - LocalVariableTableElement lvtt_elem; - - for (tbl_no = 0; tbl_no < lvtt_cnt; tbl_no++) { - cf_lvtt = (Classfile_LVT_Element *) localvariable_type_table_start[tbl_no]; - for (idx = 0; idx < localvariable_type_table_length[tbl_no]; idx++) { - copy_lvt_element(&cf_lvtt[idx], &lvtt_elem); - int index = hash(&lvtt_elem); - LVT_Hash* entry = LVT_lookup(&lvtt_elem, index, lvt_Hash); - if (entry == NULL) { - if (_need_verify) { - clear_hashtable(lvt_Hash); - classfile_parse_error("LVTT entry for '%s' in class file %s " - "does not match any LVT entry", - cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(), - CHECK_(nullHandle)); - } - } else if (entry->_elem->signature_cp_index != 0 && _need_verify) { - clear_hashtable(lvt_Hash); - classfile_parse_error("Duplicated LocalVariableTypeTable attribute " - "entry for '%s' in class file %s", - cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(), - CHECK_(nullHandle)); - } else { - // to add generic signatures into LocalVariableTable - entry->_elem->signature_cp_index = lvtt_elem.descriptor_cp_index; - } - } - } - clear_hashtable(lvt_Hash); + copy_localvariable_table(m->constMethod(), lvt_cnt, + localvariable_table_length, + localvariable_table_start, + lvtt_cnt, + localvariable_type_table_length, + localvariable_type_table_start, CHECK_NULL); } if (parsed_annotations.has_any_annotations()) parsed_annotations.apply_to(m); - *method_annotations = assemble_annotations(loader_data, - runtime_visible_annotations, - runtime_visible_annotations_length, - runtime_invisible_annotations, - runtime_invisible_annotations_length, - CHECK_(nullHandle)); - *method_parameter_annotations = assemble_annotations(loader_data, - runtime_visible_parameter_annotations, - runtime_visible_parameter_annotations_length, - runtime_invisible_parameter_annotations, - runtime_invisible_parameter_annotations_length, - CHECK_(nullHandle)); - *method_default_annotations = assemble_annotations(loader_data, - annotation_default, - annotation_default_length, - NULL, - 0, - CHECK_(nullHandle)); - *method_type_annotations = assemble_annotations(loader_data, - runtime_visible_type_annotations, - runtime_visible_type_annotations_length, - runtime_invisible_type_annotations, - runtime_invisible_type_annotations_length, - CHECK_(nullHandle)); + + // Copy annotations + copy_method_annotations(loader_data, m->constMethod(), + runtime_visible_annotations, + runtime_visible_annotations_length, + runtime_invisible_annotations, + runtime_invisible_annotations_length, + runtime_visible_parameter_annotations, + runtime_visible_parameter_annotations_length, + runtime_invisible_parameter_annotations, + runtime_invisible_parameter_annotations_length, + runtime_visible_type_annotations, + runtime_visible_type_annotations_length, + runtime_invisible_type_annotations, + runtime_invisible_type_annotations_length, + annotation_default, + annotation_default_length, + CHECK_NULL); if (name == vmSymbols::finalize_method_name() && signature == vmSymbols::void_method_signature()) { @@ -2463,6 +2551,7 @@ _has_vanilla_constructor = true; } + NOT_PRODUCT(m->verify()); return m; } @@ -2476,17 +2565,9 @@ bool is_interface, AccessFlags* promoted_flags, bool* has_final_method, - Array** methods_annotations, - Array** methods_parameter_annotations, - Array** methods_default_annotations, - Array** methods_type_annotations, bool* has_default_methods, TRAPS) { ClassFileStream* cfs = stream(); - AnnotationArray* method_annotations = NULL; - AnnotationArray* method_parameter_annotations = NULL; - AnnotationArray* method_default_annotations = NULL; - AnnotationArray* method_type_annotations = NULL; cfs->guarantee_more(2, CHECK_NULL); // length u2 length = cfs->get_u2_fast(); if (length == 0) { @@ -2500,10 +2581,6 @@ methodHandle method = parse_method(loader_data, cp, is_interface, promoted_flags, - &method_annotations, - &method_parameter_annotations, - &method_default_annotations, - &method_type_annotations, CHECK_NULL); if (method->is_final()) { @@ -2514,38 +2591,6 @@ *has_default_methods = true; } methods->at_put(index, method()); - - if (method_annotations != NULL) { - if (*methods_annotations == NULL) { - *methods_annotations = - MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL); - } - (*methods_annotations)->at_put(index, method_annotations); - } - - if (method_parameter_annotations != NULL) { - if (*methods_parameter_annotations == NULL) { - *methods_parameter_annotations = - MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL); - } - (*methods_parameter_annotations)->at_put(index, method_parameter_annotations); - } - - if (method_default_annotations != NULL) { - if (*methods_default_annotations == NULL) { - *methods_default_annotations = - MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL); - } - (*methods_default_annotations)->at_put(index, method_default_annotations); - } - - if (method_type_annotations != NULL) { - if (*methods_type_annotations == NULL) { - *methods_type_annotations = - MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL); - } - (*methods_type_annotations)->at_put(index, method_type_annotations); - } } if (_need_verify && length > 1) { @@ -2578,11 +2623,7 @@ Array* ClassFileParser::sort_methods(ClassLoaderData* loader_data, Array* methods, - Array* methods_annotations, - Array* methods_parameter_annotations, - Array* methods_default_annotations, - Array* methods_type_annotations, - TRAPS) { + TRAPS) { int length = methods->length(); // If JVMTI original method ordering or sharing is enabled we have to // remember the original class file ordering. @@ -2598,10 +2639,7 @@ } // Sort method array by ascending method name (for faster lookups & vtable construction) // Note that the ordering is not alphabetical, see Symbol::fast_compare - Method::sort_methods(methods, methods_annotations, - methods_parameter_annotations, - methods_default_annotations, - methods_type_annotations); + Method::sort_methods(methods); // If JVMTI original method ordering or sharing is enabled construct int // array remembering the original ordering @@ -3048,9 +3086,6 @@ k->set_source_debug_extension(_sde_buffer, _sde_length); } k->set_inner_classes(_inner_classes); - if (_annotations != NULL) { - k->annotations()->set_class_annotations(_annotations); - } } AnnotationArray* ClassFileParser::assemble_annotations(ClassLoaderData* loader_data, @@ -3361,19 +3396,10 @@ bool has_final_method = false; AccessFlags promoted_flags; promoted_flags.set_flags(0); - - Array* methods_annotations = NULL; - Array* methods_parameter_annotations = NULL; - Array* methods_default_annotations = NULL; - Array* methods_type_annotations = NULL; Array* methods = parse_methods(loader_data, cp, access_flags.is_interface(), &promoted_flags, &has_final_method, - &methods_annotations, - &methods_parameter_annotations, - &methods_default_annotations, - &methods_type_annotations, &has_default_methods, CHECK_(nullHandle)); @@ -3432,10 +3458,6 @@ // sort methods Array* method_ordering = sort_methods(loader_data, methods, - methods_annotations, - methods_parameter_annotations, - methods_default_annotations, - methods_type_annotations, CHECK_(nullHandle)); // promote flags from parse_methods() to the klass' flags @@ -4035,7 +4057,6 @@ const unsigned int total_oop_map_count = compute_oop_map_count(super_klass, nonstatic_oop_map_count, first_nonstatic_oop_offset); - // Compute reference type ReferenceType rt; if (super_klass() == NULL) { @@ -4057,7 +4078,7 @@ access_flags, name, super_klass(), - host_klass, + !host_klass.is_null(), CHECK_(nullHandle)); // Add all classes to our internal class loader list here, @@ -4103,31 +4124,15 @@ if (is_anonymous()) // I am well known to myself cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve - // Allocate an annotation type if needed. - if (fields_annotations != NULL || - methods_annotations != NULL || - methods_parameter_annotations != NULL || - methods_default_annotations != NULL || - fields_type_annotations != NULL || - methods_type_annotations != NULL) { - Annotations* anno = Annotations::allocate(loader_data, - fields_annotations, methods_annotations, - methods_parameter_annotations, - methods_default_annotations, CHECK_(nullHandle)); - this_klass->set_annotations(anno); - } else { - this_klass->set_annotations(NULL); - } - - if (fields_type_annotations != NULL || - methods_type_annotations != NULL) { - assert(this_klass->annotations() != NULL, "annotations should have been allocated"); - Annotations* anno = Annotations::allocate(loader_data, - fields_type_annotations, - methods_type_annotations, - NULL, - NULL, CHECK_(nullHandle)); - this_klass->annotations()->set_type_annotations(anno); + // Assign allocations if needed + if (_annotations != NULL || _type_annotations != NULL || + fields_annotations != NULL || fields_type_annotations != NULL) { + Annotations* annotations = Annotations::allocate(loader_data, CHECK_NULL); + annotations->set_class_annotations(_annotations); + annotations->set_class_type_annotations(_type_annotations); + annotations->set_fields_annotations(fields_annotations); + annotations->set_fields_type_annotations(fields_type_annotations); + this_klass->set_annotations(annotations); } this_klass->set_minor_version(minor_version); @@ -4153,27 +4158,8 @@ // Fill in field values obtained by parse_classfile_attributes if (parsed_annotations.has_any_annotations()) parsed_annotations.apply_to(this_klass); - - // Create annotations - if (_annotations != NULL && this_klass->annotations() == NULL) { - Annotations* anno = Annotations::allocate(loader_data, CHECK_NULL); - this_klass->set_annotations(anno); - } apply_parsed_class_attributes(this_klass); - // Create type annotations - if (_type_annotations != NULL) { - if (this_klass->annotations() == NULL) { - Annotations* anno = Annotations::allocate(loader_data, CHECK_NULL); - this_klass->set_annotations(anno); - } - if (this_klass->annotations()->type_annotations() == NULL) { - Annotations* anno = Annotations::allocate(loader_data, CHECK_NULL); - this_klass->annotations()->set_type_annotations(anno); - } - this_klass->annotations()->type_annotations()->set_class_annotations(_type_annotations); - } - // Miranda methods if ((num_miranda_methods > 0) || // if this class introduced new miranda methods or diff -r 753e5733b5c9 -r df8faef6efaf hotspot/src/share/vm/classfile/classFileParser.hpp --- a/hotspot/src/share/vm/classfile/classFileParser.hpp Fri Feb 08 16:56:03 2013 -0800 +++ b/hotspot/src/share/vm/classfile/classFileParser.hpp Mon Feb 11 14:06:22 2013 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -199,29 +199,17 @@ constantPoolHandle cp, bool is_interface, AccessFlags* promoted_flags, - AnnotationArray** method_annotations, - AnnotationArray** method_parameter_annotations, - AnnotationArray** method_default_annotations, - AnnotationArray** method_type_annotations, TRAPS); Array* parse_methods(ClassLoaderData* loader_data, constantPoolHandle cp, bool is_interface, AccessFlags* promoted_flags, bool* has_final_method, - Array** methods_annotations, - Array** methods_parameter_annotations, - Array** methods_default_annotations, - Array** methods_type_annotations, bool* has_default_method, TRAPS); Array* sort_methods(ClassLoaderData* loader_data, Array* methods, - Array* methods_annotations, - Array* methods_parameter_annotations, - Array* methods_default_annotations, - Array* methods_type_annotations, - TRAPS); + TRAPS); u2* parse_exception_table(ClassLoaderData* loader_data, u4 code_length, u4 exception_table_length, constantPoolHandle cp, TRAPS); @@ -377,6 +365,32 @@ : cp->tag_at(index).is_klass_reference()); } + void copy_localvariable_table(ConstMethod* cm, int lvt_cnt, + u2* localvariable_table_length, + u2** localvariable_table_start, + int lvtt_cnt, + u2* localvariable_type_table_length, + u2** localvariable_type_table_start, + TRAPS); + + void copy_method_annotations(ClassLoaderData* loader_data, + ConstMethod* cm, + u1* runtime_visible_annotations, + int runtime_visible_annotations_length, + u1* runtime_invisible_annotations, + int runtime_invisible_annotations_length, + u1* runtime_visible_parameter_annotations, + int runtime_visible_parameter_annotations_length, + u1* runtime_invisible_parameter_annotations, + int runtime_invisible_parameter_annotations_length, + u1* runtime_visible_type_annotations, + int runtime_visible_type_annotations_length, + u1* runtime_invisible_type_annotations, + int runtime_invisible_type_annotations_length, + u1* annotation_default, + int annotation_default_length, + TRAPS); + public: // Constructor ClassFileParser(ClassFileStream* st) { set_stream(st); } diff -r 753e5733b5c9 -r df8faef6efaf hotspot/src/share/vm/classfile/defaultMethods.cpp --- a/hotspot/src/share/vm/classfile/defaultMethods.cpp Fri Feb 08 16:56:03 2013 -0800 +++ b/hotspot/src/share/vm/classfile/defaultMethods.cpp Mon Feb 11 14:06:22 2013 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1146,9 +1146,10 @@ address code_start = static_cast
(bytecodes->adr_at(0)); int code_length = bytecodes->length(); + InlineTableSizes sizes; Method* m = Method::allocate(cp->pool_holder()->class_loader_data(), - code_length, flags, 0, 0, 0, 0, 0, 0, + code_length, flags, &sizes, mt, CHECK_NULL); m->set_constants(NULL); // This will get filled in later @@ -1285,33 +1286,15 @@ enum { ANNOTATIONS, PARAMETERS, DEFAULTS, NUM_ARRAYS }; - Array* original_annots[NUM_ARRAYS] = { NULL }; - Array* original_methods = klass->methods(); - Annotations* annots = klass->annotations(); - if (annots != NULL) { - original_annots[ANNOTATIONS] = annots->methods_annotations(); - original_annots[PARAMETERS] = annots->methods_parameter_annotations(); - original_annots[DEFAULTS] = annots->methods_default_annotations(); - } - Array* original_ordering = klass->method_ordering(); Array* merged_ordering = Universe::the_empty_int_array(); int new_size = klass->methods()->length() + new_methods->length(); - Array* merged_annots[NUM_ARRAYS]; - Array* merged_methods = MetadataFactory::new_array( klass->class_loader_data(), new_size, NULL, CHECK); - for (int i = 0; i < NUM_ARRAYS; ++i) { - if (original_annots[i] != NULL) { - merged_annots[i] = MetadataFactory::new_array( - klass->class_loader_data(), new_size, CHECK); - } else { - merged_annots[i] = NULL; - } - } + if (original_ordering != NULL && original_ordering->length() > 0) { merged_ordering = MetadataFactory::new_array( klass->class_loader_data(), new_size, CHECK); @@ -1338,12 +1321,6 @@ (new_method == NULL || orig_method->name() < new_method->name())) { merged_methods->at_put(i, orig_method); original_methods->at_put(orig_idx, NULL); - for (int j = 0; j < NUM_ARRAYS; ++j) { - if (merged_annots[j] != NULL) { - merged_annots[j]->at_put(i, original_annots[j]->at(orig_idx)); - original_annots[j]->at_put(orig_idx, NULL); - } - } if (merged_ordering->length() > 0) { merged_ordering->at_put(i, original_ordering->at(orig_idx)); } @@ -1372,21 +1349,9 @@ // Replace klass methods with new merged lists klass->set_methods(merged_methods); - if (annots != NULL) { - annots->set_methods_annotations(merged_annots[ANNOTATIONS]); - annots->set_methods_parameter_annotations(merged_annots[PARAMETERS]); - annots->set_methods_default_annotations(merged_annots[DEFAULTS]); - } else { - assert(merged_annots[ANNOTATIONS] == NULL, "Must be"); - assert(merged_annots[PARAMETERS] == NULL, "Must be"); - assert(merged_annots[DEFAULTS] == NULL, "Must be"); - } ClassLoaderData* cld = klass->class_loader_data(); MetadataFactory::free_array(cld, original_methods); - for (int i = 0; i < NUM_ARRAYS; ++i) { - MetadataFactory::free_array(cld, original_annots[i]); - } if (original_ordering->length() > 0) { klass->set_method_ordering(merged_ordering); MetadataFactory::free_array(cld, original_ordering); diff -r 753e5733b5c9 -r df8faef6efaf hotspot/src/share/vm/memory/heapInspection.hpp --- a/hotspot/src/share/vm/memory/heapInspection.hpp Fri Feb 08 16:56:03 2013 -0800 +++ b/hotspot/src/share/vm/memory/heapInspection.hpp Mon Feb 11 14:06:22 2013 -0500 @@ -85,16 +85,20 @@ "Number of bytes used by the InstanceKlass::singers() array") \ f(class_annotations_bytes, class_annotations, \ "Size of class annotations") \ + f(class_type_annotations_bytes, class_type_annotations, \ + "Size of class type annotations") \ f(fields_annotations_bytes, fields_annotations, \ "Size of field annotations") \ + f(fields_type_annotations_bytes, fields_type_annotations, \ + "Size of field type annotations") \ f(methods_annotations_bytes, methods_annotations, \ "Size of method annotations") \ f(methods_parameter_annotations_bytes, methods_parameter_annotations, \ "Size of method parameter annotations") \ + f(methods_type_annotations_bytes, methods_type_annotations, \ + "Size of methods type annotations") \ f(methods_default_annotations_bytes, methods_default_annotations, \ "Size of methods default annotations") \ - f(type_annotations_bytes, type_annotations, \ - "Size of type annotations") \ f(annotations_bytes, annotations, \ "Size of all annotations") \ f(cp_bytes, Cp, \ diff -r 753e5733b5c9 -r df8faef6efaf hotspot/src/share/vm/oops/annotations.cpp --- a/hotspot/src/share/vm/oops/annotations.cpp Fri Feb 08 16:56:03 2013 -0800 +++ b/hotspot/src/share/vm/oops/annotations.cpp Mon Feb 11 14:06:22 2013 -0500 @@ -36,16 +36,8 @@ return new (loader_data, size(), true, THREAD) Annotations(); } -Annotations* Annotations::allocate(ClassLoaderData* loader_data, - Array* fa, - Array* ma, - Array* mpa, - Array* mda, TRAPS) { - return new (loader_data, size(), true, THREAD) Annotations(fa, ma, mpa, mda); -} - // helper -static void free_contents(ClassLoaderData* loader_data, Array* p) { +void Annotations::free_contents(ClassLoaderData* loader_data, Array* p) { if (p != NULL) { for (int i = 0; i < p->length(); i++) { MetadataFactory::free_array(loader_data, p->at(i)); @@ -59,44 +51,16 @@ MetadataFactory::free_array(loader_data, class_annotations()); } free_contents(loader_data, fields_annotations()); - free_contents(loader_data, methods_annotations()); - free_contents(loader_data, methods_parameter_annotations()); - free_contents(loader_data, methods_default_annotations()); - // Recursively deallocate optional Annotations linked through this one - MetadataFactory::free_metadata(loader_data, type_annotations()); + if (class_type_annotations() != NULL) { + MetadataFactory::free_array(loader_data, class_type_annotations()); + } + free_contents(loader_data, fields_type_annotations()); } -// Set the annotation at 'idnum' to 'anno'. -// We don't want to create or extend the array if 'anno' is NULL, since that is the -// default value. However, if the array exists and is long enough, we must set NULL values. -void Annotations::set_methods_annotations_of(instanceKlassHandle ik, - int idnum, AnnotationArray* anno, - Array** md_p, - TRAPS) { - Array* md = *md_p; - if (md != NULL && md->length() > idnum) { - md->at_put(idnum, anno); - } else if (anno != NULL) { - // create the array - int length = MAX2(idnum+1, (int)ik->idnum_allocated_count()); - md = MetadataFactory::new_array(ik->class_loader_data(), length, CHECK); - if (*md_p != NULL) { - // copy the existing entries - for (int index = 0; index < (*md_p)->length(); index++) { - md->at_put(index, (*md_p)->at(index)); - } - } - set_annotations(md, md_p); - md->at_put(idnum, anno); - } // if no array and idnum isn't included there is nothing to do -} - -// Keep created annotations in a global growable array (should be hashtable) -// need to add, search, delete when class is unloaded. -// Does it need a lock? yes. This sucks. - // Copy annotations to JVM call or reflection to the java heap. +// The alternative to creating this array and adding to Java heap pressure +// is to have a hashtable of the already created typeArrayOops typeArrayOop Annotations::make_java_array(AnnotationArray* annotations, TRAPS) { if (annotations != NULL) { int length = annotations->length(); @@ -132,28 +96,15 @@ void Annotations::collect_statistics(KlassSizeStats *sz) const { sz->_annotations_bytes = sz->count(this); sz->_class_annotations_bytes = sz->count(class_annotations()); + sz->_class_type_annotations_bytes = sz->count(class_type_annotations()); sz->_fields_annotations_bytes = count_bytes(fields_annotations()); - sz->_methods_annotations_bytes = count_bytes(methods_annotations()); - sz->_methods_parameter_annotations_bytes = - count_bytes(methods_parameter_annotations()); - sz->_methods_default_annotations_bytes = - count_bytes(methods_default_annotations()); - - const Annotations* type_anno = type_annotations(); - if (type_anno != NULL) { - sz->_type_annotations_bytes = sz->count(type_anno); - sz->_type_annotations_bytes += sz->count(type_anno->class_annotations()); - sz->_type_annotations_bytes += count_bytes(type_anno->fields_annotations()); - sz->_type_annotations_bytes += count_bytes(type_anno->methods_annotations()); - } + sz->_fields_type_annotations_bytes = count_bytes(fields_type_annotations()); sz->_annotations_bytes += sz->_class_annotations_bytes + + sz->_class_type_annotations_bytes + sz->_fields_annotations_bytes + - sz->_methods_annotations_bytes + - sz->_methods_parameter_annotations_bytes + - sz->_methods_default_annotations_bytes + - sz->_type_annotations_bytes; + sz->_fields_type_annotations_bytes; sz->_ro_bytes += sz->_annotations_bytes; } @@ -165,8 +116,7 @@ void Annotations::print_on(outputStream* st) const { st->print(BULLET"class_annotations "); class_annotations()->print_value_on(st); st->print(BULLET"fields_annotations "); fields_annotations()->print_value_on(st); - st->print(BULLET"methods_annotations "); methods_annotations()->print_value_on(st); - st->print(BULLET"methods_parameter_annotations"); methods_parameter_annotations()->print_value_on(st); - st->print(BULLET"methods_default_annotations "); methods_default_annotations()->print_value_on(st); + st->print(BULLET"class_type_annotations "); class_type_annotations()->print_value_on(st); + st->print(BULLET"fields_type_annotations "); fields_type_annotations()->print_value_on(st); } #endif // PRODUCT diff -r 753e5733b5c9 -r df8faef6efaf hotspot/src/share/vm/oops/annotations.hpp --- a/hotspot/src/share/vm/oops/annotations.hpp Fri Feb 08 16:56:03 2013 -0800 +++ b/hotspot/src/share/vm/oops/annotations.hpp Mon Feb 11 14:06:22 2013 -0500 @@ -49,38 +49,15 @@ // Annotation objects (byte arrays) for fields, or null if no annotations. // Indices correspond to entries (not indices) in fields array. Array* _fields_annotations; - // Annotation objects (byte arrays) for methods, or null if no annotations. - // Index is the idnum, which is initially the same as the methods array index. - Array* _methods_annotations; - // Annotation objects (byte arrays) for methods' parameters, or null if no - // such annotations. - // Index is the idnum, which is initially the same as the methods array index. - Array* _methods_parameter_annotations; - // Annotation objects (byte arrays) for methods' default values, or null if no - // such annotations. - // Index is the idnum, which is initially the same as the methods array index. - Array* _methods_default_annotations; // Type annotations for this class, or null if none. - Annotations* _type_annotations; - - // Constructor where some some values are known to not be null - Annotations(Array* fa, Array* ma, - Array* mpa, Array* mda) : - _class_annotations(NULL), - _fields_annotations(fa), - _methods_annotations(ma), - _methods_parameter_annotations(mpa), - _methods_default_annotations(mda), - _type_annotations(NULL) {} + AnnotationArray* _class_type_annotations; + Array* _fields_type_annotations; public: // Allocate instance of this class static Annotations* allocate(ClassLoaderData* loader_data, TRAPS); - static Annotations* allocate(ClassLoaderData* loader_data, - Array* fa, - Array* ma, - Array* mpa, - Array* mda, TRAPS); + + static void free_contents(ClassLoaderData* loader_data, Array* p); void deallocate_contents(ClassLoaderData* loader_data); DEBUG_ONLY(bool on_stack() { return false; }) // for template @@ -93,61 +70,24 @@ // Constructor to initialize to null Annotations() : _class_annotations(NULL), _fields_annotations(NULL), - _methods_annotations(NULL), - _methods_parameter_annotations(NULL), - _methods_default_annotations(NULL), - _type_annotations(NULL) {} + _class_type_annotations(NULL), + _fields_type_annotations(NULL) {} AnnotationArray* class_annotations() const { return _class_annotations; } Array* fields_annotations() const { return _fields_annotations; } - Array* methods_annotations() const { return _methods_annotations; } - Array* methods_parameter_annotations() const { return _methods_parameter_annotations; } - Array* methods_default_annotations() const { return _methods_default_annotations; } - Annotations* type_annotations() const { return _type_annotations; } + AnnotationArray* class_type_annotations() const { return _class_type_annotations; } + Array* fields_type_annotations() const { return _fields_type_annotations; } void set_class_annotations(AnnotationArray* md) { _class_annotations = md; } void set_fields_annotations(Array* md) { _fields_annotations = md; } - void set_methods_annotations(Array* md) { _methods_annotations = md; } - void set_methods_parameter_annotations(Array* md) { _methods_parameter_annotations = md; } - void set_methods_default_annotations(Array* md) { _methods_default_annotations = md; } - void set_type_annotations(Annotations* annos) { _type_annotations = annos; } - - // Redefine classes support - AnnotationArray* get_method_annotations_of(int idnum) - { return get_method_annotations_from(idnum, _methods_annotations); } - - AnnotationArray* get_method_parameter_annotations_of(int idnum) - { return get_method_annotations_from(idnum, _methods_parameter_annotations); } - AnnotationArray* get_method_default_annotations_of(int idnum) - { return get_method_annotations_from(idnum, _methods_default_annotations); } - - - void set_method_annotations_of(instanceKlassHandle ik, - int idnum, AnnotationArray* anno, TRAPS) { - set_methods_annotations_of(ik, idnum, anno, &_methods_annotations, THREAD); - } - - void set_method_parameter_annotations_of(instanceKlassHandle ik, - int idnum, AnnotationArray* anno, TRAPS) { - set_methods_annotations_of(ik, idnum, anno, &_methods_parameter_annotations, THREAD); - } - - void set_method_default_annotations_of(instanceKlassHandle ik, - int idnum, AnnotationArray* anno, TRAPS) { - set_methods_annotations_of(ik, idnum, anno, &_methods_default_annotations, THREAD); - } + void set_class_type_annotations(AnnotationArray* cta) { _class_type_annotations = cta; } + void set_fields_type_annotations(Array* fta) { _fields_type_annotations = fta; } // Turn metadata annotations into a Java heap object (oop) static typeArrayOop make_java_array(AnnotationArray* annotations, TRAPS); - inline AnnotationArray* get_method_annotations_from(int idnum, Array* annos); - void set_annotations(Array* md, Array** md_p) { *md_p = md; } - bool is_klass() const { return false; } private: - void set_methods_annotations_of(instanceKlassHandle ik, - int idnum, AnnotationArray* anno, - Array** md_p, TRAPS); static julong count_bytes(Array* p); public: const char* internal_name() const { return "{constant pool}"; } @@ -156,13 +96,4 @@ #endif void print_value_on(outputStream* st) const; }; - - -// For method with idnum get the method's Annotations -inline AnnotationArray* Annotations::get_method_annotations_from(int idnum, Array* annos) { - if (annos == NULL || annos->length() <= idnum) { - return NULL; - } - return annos->at(idnum); -} #endif // SHARE_VM_OOPS_ANNOTATIONS_HPP diff -r 753e5733b5c9 -r df8faef6efaf hotspot/src/share/vm/oops/constMethod.cpp --- a/hotspot/src/share/vm/oops/constMethod.cpp Fri Feb 08 16:56:03 2013 -0800 +++ b/hotspot/src/share/vm/oops/constMethod.cpp Mon Feb 11 14:06:22 2013 -0500 @@ -36,51 +36,26 @@ ConstMethod* ConstMethod::allocate(ClassLoaderData* loader_data, int byte_code_size, - int compressed_line_number_size, - int localvariable_table_length, - int exception_table_length, - int checked_exceptions_length, - int method_parameters_length, - u2 generic_signature_index, + InlineTableSizes* sizes, MethodType method_type, TRAPS) { - int size = ConstMethod::size(byte_code_size, - compressed_line_number_size, - localvariable_table_length, - exception_table_length, - checked_exceptions_length, - method_parameters_length, - generic_signature_index); + int size = ConstMethod::size(byte_code_size, sizes); return new (loader_data, size, true, THREAD) ConstMethod( - byte_code_size, compressed_line_number_size, localvariable_table_length, - exception_table_length, checked_exceptions_length, - method_parameters_length, generic_signature_index, - method_type, size); + byte_code_size, sizes, method_type, size); } ConstMethod::ConstMethod(int byte_code_size, - int compressed_line_number_size, - int localvariable_table_length, - int exception_table_length, - int checked_exceptions_length, - int method_parameters_length, - u2 generic_signature_index, + InlineTableSizes* sizes, MethodType method_type, int size) { No_Safepoint_Verifier no_safepoint; - set_interpreter_kind(Interpreter::invalid); init_fingerprint(); set_constants(NULL); set_stackmap_data(NULL); set_code_size(byte_code_size); set_constMethod_size(size); - set_inlined_tables_length(generic_signature_index, - checked_exceptions_length, - compressed_line_number_size, - localvariable_table_length, - exception_table_length, - method_parameters_length); + set_inlined_tables_length(sizes); set_method_type(method_type); assert(this->size() == size, "wrong size for object"); } @@ -88,47 +63,70 @@ // Deallocate metadata fields associated with ConstMethod* void ConstMethod::deallocate_contents(ClassLoaderData* loader_data) { - set_interpreter_kind(Interpreter::invalid); if (stackmap_data() != NULL) { MetadataFactory::free_array(loader_data, stackmap_data()); } set_stackmap_data(NULL); + + // deallocate annotation arrays + if (has_method_annotations()) + MetadataFactory::free_array(loader_data, method_annotations()); + if (has_parameter_annotations()) + MetadataFactory::free_array(loader_data, parameter_annotations()); + if (has_type_annotations()) + MetadataFactory::free_array(loader_data, type_annotations()); + if (has_default_annotations()) + MetadataFactory::free_array(loader_data, default_annotations()); } // How big must this constMethodObject be? int ConstMethod::size(int code_size, - int compressed_line_number_size, - int local_variable_table_length, - int exception_table_length, - int checked_exceptions_length, - int method_parameters_length, - u2 generic_signature_index) { + InlineTableSizes* sizes) { int extra_bytes = code_size; - if (compressed_line_number_size > 0) { - extra_bytes += compressed_line_number_size; + if (sizes->compressed_linenumber_size() > 0) { + extra_bytes += sizes->compressed_linenumber_size(); } - if (checked_exceptions_length > 0) { + if (sizes->checked_exceptions_length() > 0) { extra_bytes += sizeof(u2); - extra_bytes += checked_exceptions_length * sizeof(CheckedExceptionElement); + extra_bytes += sizes->checked_exceptions_length() * sizeof(CheckedExceptionElement); } - if (local_variable_table_length > 0) { + if (sizes->localvariable_table_length() > 0) { extra_bytes += sizeof(u2); extra_bytes += - local_variable_table_length * sizeof(LocalVariableTableElement); + sizes->localvariable_table_length() * sizeof(LocalVariableTableElement); } - if (exception_table_length > 0) { + if (sizes->exception_table_length() > 0) { extra_bytes += sizeof(u2); - extra_bytes += exception_table_length * sizeof(ExceptionTableElement); + extra_bytes += sizes->exception_table_length() * sizeof(ExceptionTableElement); } - if (generic_signature_index != 0) { + if (sizes->generic_signature_index() != 0) { extra_bytes += sizeof(u2); } - if (method_parameters_length > 0) { + if (sizes->method_parameters_length() > 0) { extra_bytes += sizeof(u2); - extra_bytes += method_parameters_length * sizeof(MethodParametersElement); + extra_bytes += sizes->method_parameters_length() * sizeof(MethodParametersElement); + } + + // Align sizes up to a word. + extra_bytes = align_size_up(extra_bytes, BytesPerWord); + + // One pointer per annotation array + if (sizes->method_annotations_length() > 0) { + extra_bytes += sizeof(AnnotationArray*); } + if (sizes->parameter_annotations_length() > 0) { + extra_bytes += sizeof(AnnotationArray*); + } + if (sizes->type_annotations_length() > 0) { + extra_bytes += sizeof(AnnotationArray*); + } + if (sizes->default_annotations_length() > 0) { + extra_bytes += sizeof(AnnotationArray*); + } + int extra_words = align_size_up(extra_bytes, BytesPerWord) / BytesPerWord; + assert(extra_words == extra_bytes/BytesPerWord, "should already be aligned"); return align_object_size(header_size() + extra_words); } @@ -145,12 +143,28 @@ return code_end(); } +// Last short in ConstMethod* before annotations +u2* ConstMethod::last_u2_element() const { + int offset = 0; + if (has_method_annotations()) offset++; + if (has_parameter_annotations()) offset++; + if (has_type_annotations()) offset++; + if (has_default_annotations()) offset++; + return (u2*)((AnnotationArray**)constMethod_end() - offset) - 1; +} + u2* ConstMethod::generic_signature_index_addr() const { // Located at the end of the constMethod. assert(has_generic_signature(), "called only if generic signature exists"); return last_u2_element(); } +u2* ConstMethod::method_parameters_length_addr() const { + assert(has_method_parameters(), "called only if table is present"); + return has_generic_signature() ? (last_u2_element() - 1) : + last_u2_element(); +} + u2* ConstMethod::checked_exceptions_length_addr() const { // Located immediately before the generic signature index. assert(has_checked_exceptions(), "called only if table is present"); @@ -164,12 +178,6 @@ } } -u2* ConstMethod::method_parameters_length_addr() const { - assert(has_method_parameters(), "called only if table is present"); - return has_generic_signature() ? (last_u2_element() - 1) : - last_u2_element(); -} - u2* ConstMethod::exception_table_length_addr() const { assert(has_exception_handler(), "called only if table is present"); if (has_checked_exceptions()) { @@ -181,9 +189,9 @@ return (u2*)method_parameters_start() - 1; } else { // Else, the exception table is at the end of the constMethod. - return has_generic_signature() ? (last_u2_element() - 1) : - last_u2_element(); - } + return has_generic_signature() ? (last_u2_element() - 1) : + last_u2_element(); + } } } @@ -204,32 +212,38 @@ // Else, the exception table is at the end of the constMethod. return has_generic_signature() ? (last_u2_element() - 1) : last_u2_element(); + } } } - } } // Update the flags to indicate the presence of these optional fields. -void ConstMethod::set_inlined_tables_length(u2 generic_signature_index, - int checked_exceptions_len, - int compressed_line_number_size, - int localvariable_table_len, - int exception_table_len, - int method_parameters_len) { - assert(_flags == 0, "Error"); - if (compressed_line_number_size > 0) +void ConstMethod::set_inlined_tables_length(InlineTableSizes* sizes) { + _flags = 0; + if (sizes->compressed_linenumber_size() > 0) _flags |= _has_linenumber_table; - if (generic_signature_index != 0) + if (sizes->generic_signature_index() != 0) _flags |= _has_generic_signature; - if (method_parameters_len > 0) + if (sizes->method_parameters_length() > 0) _flags |= _has_method_parameters; - if (checked_exceptions_len > 0) + if (sizes->checked_exceptions_length() > 0) _flags |= _has_checked_exceptions; - if (exception_table_len > 0) + if (sizes->exception_table_length() > 0) _flags |= _has_exception_table; - if (localvariable_table_len > 0) + if (sizes->localvariable_table_length() > 0) _flags |= _has_localvariable_table; + // annotations, they are all pointer sized embedded objects so don't have + // a length embedded also. + if (sizes->method_annotations_length() > 0) + _flags |= _has_method_annotations; + if (sizes->parameter_annotations_length() > 0) + _flags |= _has_parameter_annotations; + if (sizes->type_annotations_length() > 0) + _flags |= _has_type_annotations; + if (sizes->default_annotations_length() > 0) + _flags |= _has_default_annotations; + // This code is extremely brittle and should possibly be revised. // The *_length_addr functions walk backwards through the // constMethod data, using each of the length indexes ahead of them, @@ -242,17 +256,17 @@ // Also, the servicability agent needs to be informed anytime // anything is added here. It might be advisable to have some sort // of indication of this inline. - if (generic_signature_index != 0) - *(generic_signature_index_addr()) = generic_signature_index; + if (sizes->generic_signature_index() != 0) + *(generic_signature_index_addr()) = sizes->generic_signature_index(); // New data should probably go here. - if (method_parameters_len > 0) - *(method_parameters_length_addr()) = method_parameters_len; - if (checked_exceptions_len > 0) - *(checked_exceptions_length_addr()) = checked_exceptions_len; - if (exception_table_len > 0) - *(exception_table_length_addr()) = exception_table_len; - if (localvariable_table_len > 0) - *(localvariable_table_length_addr()) = localvariable_table_len; + if (sizes->method_parameters_length() > 0) + *(method_parameters_length_addr()) = sizes->method_parameters_length(); + if (sizes->checked_exceptions_length() > 0) + *(checked_exceptions_length_addr()) = sizes->checked_exceptions_length(); + if (sizes->exception_table_length() > 0) + *(exception_table_length_addr()) = sizes->exception_table_length(); + if (sizes->localvariable_table_length() > 0) + *(localvariable_table_length_addr()) = sizes->localvariable_table_length(); } int ConstMethod::method_parameters_length() const { @@ -307,6 +321,34 @@ return (ExceptionTableElement*)addr; } +AnnotationArray** ConstMethod::method_annotations_addr() const { + assert(has_method_annotations(), "should only be called if method annotations are present"); + return (AnnotationArray**)constMethod_end() - 1; +} + +AnnotationArray** ConstMethod::parameter_annotations_addr() const { + assert(has_parameter_annotations(), "should only be called if method parameter annotations are present"); + int offset = 1; + if (has_method_annotations()) offset++; + return (AnnotationArray**)constMethod_end() - offset; +} + +AnnotationArray** ConstMethod::type_annotations_addr() const { + assert(has_type_annotations(), "should only be called if method type annotations are present"); + int offset = 1; + if (has_method_annotations()) offset++; + if (has_parameter_annotations()) offset++; + return (AnnotationArray**)constMethod_end() - offset; +} + +AnnotationArray** ConstMethod::default_annotations_addr() const { + assert(has_default_annotations(), "should only be called if method default annotations are present"); + int offset = 1; + if (has_method_annotations()) offset++; + if (has_parameter_annotations()) offset++; + if (has_type_annotations()) offset++; + return (AnnotationArray**)constMethod_end() - offset; +} // Printing @@ -339,8 +381,25 @@ sz->_bytecode_bytes += (n2 = code_size()); sz->_stackmap_bytes += (n3 = sz->count_array(stackmap_data())); - sz->_method_all_bytes += n1 + n3; // note: n2 is part of n3 - sz->_ro_bytes += n1 + n3; + // Count method annotations + int a1 = 0, a2 = 0, a3 = 0, a4 = 0; + if (has_method_annotations()) { + sz->_methods_annotations_bytes += (a1 = sz->count_array(method_annotations())); + } + if (has_parameter_annotations()) { + sz->_methods_parameter_annotations_bytes += (a2 = sz->count_array(parameter_annotations())); + } + if (has_type_annotations()) { + sz->_methods_type_annotations_bytes += (a3 = sz->count_array(type_annotations())); + } + if (has_default_annotations()) { + sz->_methods_default_annotations_bytes += (a4 = sz->count_array(default_annotations())); + } + + int size_annotations = a1 + a2 + a3 + a4; + + sz->_method_all_bytes += n1 + n3 + size_annotations; // note: n2 is part of n3 + sz->_ro_bytes += n1 + n3 + size_annotations; } #endif // INCLUDE_SERVICES @@ -352,10 +411,9 @@ // Verification can occur during oop construction before the method or // other fields have been initialized. - guarantee(is_metadata(), err_msg("Should be metadata " PTR_FORMAT, this)); guarantee(method()->is_method(), "should be method"); - address m_end = (address)((oop*) this + size()); + address m_end = (address)((intptr_t) this + size()); address compressed_table_start = code_end(); guarantee(compressed_table_start <= m_end, "invalid method layout"); address compressed_table_end = compressed_table_start; diff -r 753e5733b5c9 -r df8faef6efaf hotspot/src/share/vm/oops/constMethod.hpp --- a/hotspot/src/share/vm/oops/constMethod.hpp Fri Feb 08 16:56:03 2013 -0800 +++ b/hotspot/src/share/vm/oops/constMethod.hpp Mon Feb 11 14:06:22 2013 -0500 @@ -86,19 +86,22 @@ // | generic signature index (u2) | // | (indexed from start of constMethodOop) | // |------------------------------------------------------| +// | annotations arrays - method, parameter, type, default| +// | pointer to Array if annotation is present | +// |------------------------------------------------------| // // IMPORTANT: If anything gets added here, there need to be changes to // ensure that ServicabilityAgent doesn't get broken as a result! -// Utitily class decribing elements in checked exceptions table inlined in Method*. +// Utility class describing elements in checked exceptions table inlined in Method*. class CheckedExceptionElement VALUE_OBJ_CLASS_SPEC { public: u2 class_cp_index; }; -// Utitily class decribing elements in local variable table inlined in Method*. +// Utility class describing elements in local variable table inlined in Method*. class LocalVariableTableElement VALUE_OBJ_CLASS_SPEC { public: u2 start_bci; @@ -109,7 +112,7 @@ u2 slot; }; -// Utitily class describing elements in exception table +// Utility class describing elements in exception table class ExceptionTableElement VALUE_OBJ_CLASS_SPEC { public: u2 start_pc; @@ -127,6 +130,51 @@ class KlassSizeStats; +// Class to collect the sizes of ConstMethod inline tables +#define INLINE_TABLES_DO(do_element) \ + do_element(localvariable_table_length) \ + do_element(compressed_linenumber_size) \ + do_element(exception_table_length) \ + do_element(checked_exceptions_length) \ + do_element(method_parameters_length) \ + do_element(generic_signature_index) \ + do_element(method_annotations_length) \ + do_element(parameter_annotations_length) \ + do_element(type_annotations_length) \ + do_element(default_annotations_length) + +#define INLINE_TABLE_DECLARE(sym) int _##sym; +#define INLINE_TABLE_PARAM(sym) int sym, +#define INLINE_TABLE_INIT(sym) _##sym(sym), +#define INLINE_TABLE_NULL(sym) _##sym(0), +#define INLINE_TABLE_ACCESSOR(sym) int sym() const { return _##sym; } + +class InlineTableSizes : StackObj { + // declarations + INLINE_TABLES_DO(INLINE_TABLE_DECLARE) + int _end; + public: + InlineTableSizes( + INLINE_TABLES_DO(INLINE_TABLE_PARAM) + int end) : + INLINE_TABLES_DO(INLINE_TABLE_INIT) + _end(end) {} + + // Default constructor for no inlined tables + InlineTableSizes() : + INLINE_TABLES_DO(INLINE_TABLE_NULL) + _end(0) {} + + // Accessors + INLINE_TABLES_DO(INLINE_TABLE_ACCESSOR) +}; +#undef INLINE_TABLE_ACCESSOR +#undef INLINE_TABLE_NULL +#undef INLINE_TABLE_INIT +#undef INLINE_TABLE_PARAM +#undef INLINE_TABLE_DECLARE + + class ConstMethod : public MetaspaceObj { friend class VMStructs; @@ -135,13 +183,17 @@ private: enum { - _has_linenumber_table = 1, - _has_checked_exceptions = 2, - _has_localvariable_table = 4, - _has_exception_table = 8, - _has_generic_signature = 16, - _has_method_parameters = 32, - _is_overpass = 64 + _has_linenumber_table = 0x0001, + _has_checked_exceptions = 0x0002, + _has_localvariable_table = 0x0004, + _has_exception_table = 0x0008, + _has_generic_signature = 0x0010, + _has_method_parameters = 0x0020, + _is_overpass = 0x0040, + _has_method_annotations = 0x0080, + _has_parameter_annotations = 0x0100, + _has_type_annotations = 0x0200, + _has_default_annotations = 0x0400 }; // Bit vector of signature @@ -158,8 +210,7 @@ Array* _stackmap_data; int _constMethod_size; - jbyte _interpreter_kind; - jbyte _flags; + u2 _flags; // Size of Java bytecodes allocated immediately after Method*. u2 _code_size; @@ -174,36 +225,21 @@ // Constructor ConstMethod(int byte_code_size, - int compressed_line_number_size, - int localvariable_table_length, - int exception_table_length, - int checked_exceptions_length, - int method_parameters_length, - u2 generic_signature_index, + InlineTableSizes* sizes, MethodType is_overpass, int size); public: static ConstMethod* allocate(ClassLoaderData* loader_data, int byte_code_size, - int compressed_line_number_size, - int localvariable_table_length, - int exception_table_length, - int checked_exceptions_length, - int method_parameters_length, - u2 generic_signature_index, + InlineTableSizes* sizes, MethodType mt, TRAPS); bool is_constMethod() const { return true; } // Inlined tables - void set_inlined_tables_length(u2 generic_signature_index, - int checked_exceptions_len, - int compressed_line_number_size, - int localvariable_table_len, - int exception_table_len, - int method_parameters_length); + void set_inlined_tables_length(InlineTableSizes* sizes); bool has_generic_signature() const { return (_flags & _has_generic_signature) != 0; } @@ -235,10 +271,6 @@ } } - - void set_interpreter_kind(int kind) { _interpreter_kind = kind; } - int interpreter_kind(void) const { return _interpreter_kind; } - // constant pool ConstantPool* constants() const { return _constants; } void set_constants(ConstantPool* c) { _constants = c; } @@ -307,12 +339,7 @@ } // Size needed - static int size(int code_size, int compressed_line_number_size, - int local_variable_table_length, - int exception_table_length, - int checked_exceptions_length, - int method_parameters_length, - u2 generic_signature_index); + static int size(int code_size, InlineTableSizes* sizes); int size() const { return _constMethod_size;} void set_constMethod_size(int size) { _constMethod_size = size; } @@ -354,6 +381,65 @@ int method_parameters_length() const; MethodParametersElement* method_parameters_start() const; + // method annotations + bool has_method_annotations() const + { return (_flags & _has_method_annotations) != 0; } + + bool has_parameter_annotations() const + { return (_flags & _has_parameter_annotations) != 0; } + + bool has_type_annotations() const + { return (_flags & _has_type_annotations) != 0; } + + bool has_default_annotations() const + { return (_flags & _has_default_annotations) != 0; } + + + AnnotationArray** method_annotations_addr() const; + AnnotationArray* method_annotations() const { + return has_method_annotations() ? *(method_annotations_addr()) : NULL; + } + void set_method_annotations(AnnotationArray* anno) { + *(method_annotations_addr()) = anno; + } + + AnnotationArray** parameter_annotations_addr() const; + AnnotationArray* parameter_annotations() const { + return has_parameter_annotations() ? *(parameter_annotations_addr()) : NULL; + } + void set_parameter_annotations(AnnotationArray* anno) { + *(parameter_annotations_addr()) = anno; + } + + AnnotationArray** type_annotations_addr() const; + AnnotationArray* type_annotations() const { + return has_type_annotations() ? *(type_annotations_addr()) : NULL; + } + void set_type_annotations(AnnotationArray* anno) { + *(type_annotations_addr()) = anno; + } + + AnnotationArray** default_annotations_addr() const; + AnnotationArray* default_annotations() const { + return has_default_annotations() ? *(default_annotations_addr()) : NULL; + } + void set_default_annotations(AnnotationArray* anno) { + *(default_annotations_addr()) = anno; + } + + int method_annotations_length() const { + return has_method_annotations() ? method_annotations()->length() : 0; + } + int parameter_annotations_length() const { + return has_parameter_annotations() ? parameter_annotations()->length() : 0; + } + int type_annotations_length() const { + return has_type_annotations() ? type_annotations()->length() : 0; + } + int default_annotations_length() const { + return has_default_annotations() ? default_annotations()->length() : 0; + } + // byte codes void set_code(address code) { if (code_size() > 0) { @@ -409,11 +495,10 @@ // First byte after ConstMethod* address constMethod_end() const - { return (address)((oop*)this + _constMethod_size); } + { return (address)((intptr_t*)this + _constMethod_size); } // Last short in ConstMethod* - u2* last_u2_element() const - { return (u2*)constMethod_end() - 1; } + u2* last_u2_element() const; public: // Printing diff -r 753e5733b5c9 -r df8faef6efaf hotspot/src/share/vm/oops/instanceKlass.cpp --- a/hotspot/src/share/vm/oops/instanceKlass.cpp Fri Feb 08 16:56:03 2013 -0800 +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Mon Feb 11 14:06:22 2013 -0500 @@ -166,20 +166,19 @@ volatile int InstanceKlass::_total_instanceKlass_count = 0; Klass* InstanceKlass::allocate_instance_klass(ClassLoaderData* loader_data, - int vtable_len, - int itable_len, - int static_field_size, - int nonstatic_oop_map_size, - ReferenceType rt, - AccessFlags access_flags, - Symbol* name, + int vtable_len, + int itable_len, + int static_field_size, + int nonstatic_oop_map_size, + ReferenceType rt, + AccessFlags access_flags, + Symbol* name, Klass* super_klass, - KlassHandle host_klass, - TRAPS) { + bool is_anonymous, + TRAPS) { int size = InstanceKlass::size(vtable_len, itable_len, nonstatic_oop_map_size, - access_flags.is_interface(), - !host_klass.is_null()); + access_flags.is_interface(), is_anonymous); // Allocation InstanceKlass* ik; @@ -187,25 +186,25 @@ if (name == vmSymbols::java_lang_Class()) { ik = new (loader_data, size, THREAD) InstanceMirrorKlass( vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt, - access_flags, !host_klass.is_null()); + access_flags, is_anonymous); } else if (name == vmSymbols::java_lang_ClassLoader() || (SystemDictionary::ClassLoader_klass_loaded() && super_klass != NULL && super_klass->is_subtype_of(SystemDictionary::ClassLoader_klass()))) { ik = new (loader_data, size, THREAD) InstanceClassLoaderKlass( vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt, - access_flags, !host_klass.is_null()); + access_flags, is_anonymous); } else { // normal class ik = new (loader_data, size, THREAD) InstanceKlass( vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt, - access_flags, !host_klass.is_null()); + access_flags, is_anonymous); } } else { // reference klass ik = new (loader_data, size, THREAD) InstanceRefKlass( vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt, - access_flags, !host_klass.is_null()); + access_flags, is_anonymous); } Atomic::inc(&_total_instanceKlass_count); @@ -2793,7 +2792,10 @@ st->print("%s", source_debug_extension()); st->cr(); } - st->print(BULLET"annotations: "); annotations()->print_value_on(st); st->cr(); + st->print(BULLET"class annotations: "); class_annotations()->print_value_on(st); st->cr(); + st->print(BULLET"class type annotations: "); class_type_annotations()->print_value_on(st); st->cr(); + st->print(BULLET"field annotations: "); fields_annotations()->print_value_on(st); st->cr(); + st->print(BULLET"field type annotations: "); fields_type_annotations()->print_value_on(st); st->cr(); { ResourceMark rm; // PreviousVersionInfo objects returned via PreviousVersionWalker diff -r 753e5733b5c9 -r df8faef6efaf hotspot/src/share/vm/oops/instanceKlass.hpp --- a/hotspot/src/share/vm/oops/instanceKlass.hpp Fri Feb 08 16:56:03 2013 -0800 +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Mon Feb 11 14:06:22 2013 -0500 @@ -155,8 +155,8 @@ ReferenceType rt, AccessFlags access_flags, Symbol* name, - Klass* super_klass, - KlassHandle host_klass, + Klass* super_klass, + bool is_anonymous, TRAPS); InstanceKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); } @@ -679,19 +679,19 @@ // annotations support Annotations* annotations() const { return _annotations; } void set_annotations(Annotations* anno) { _annotations = anno; } + AnnotationArray* class_annotations() const { - if (annotations() == NULL) return NULL; - return annotations()->class_annotations(); + return (_annotations != NULL) ? _annotations->class_annotations() : NULL; } Array* fields_annotations() const { - if (annotations() == NULL) return NULL; - return annotations()->fields_annotations(); + return (_annotations != NULL) ? _annotations->fields_annotations() : NULL; } - Annotations* type_annotations() const { - if (annotations() == NULL) return NULL; - return annotations()->type_annotations(); + AnnotationArray* class_type_annotations() const { + return (_annotations != NULL) ? _annotations->class_type_annotations() : NULL; } - + Array* fields_type_annotations() const { + return (_annotations != NULL) ? _annotations->fields_type_annotations() : NULL; + } // allocation instanceOop allocate_instance(TRAPS); @@ -810,6 +810,7 @@ // Sizing (in words) static int header_size() { return align_object_offset(sizeof(InstanceKlass)/HeapWordSize); } + static int size(int vtable_length, int itable_length, int nonstatic_oop_map_size, bool is_interface, bool is_anonymous) { @@ -847,10 +848,14 @@ return (OopMapBlock*)(start_of_itable() + align_object_offset(itable_length())); } + Klass** end_of_nonstatic_oop_maps() const { + return (Klass**)(start_of_nonstatic_oop_maps() + + nonstatic_oop_map_count()); + } + Klass** adr_implementor() const { if (is_interface()) { - return (Klass**)(start_of_nonstatic_oop_maps() + - nonstatic_oop_map_count()); + return (Klass**)end_of_nonstatic_oop_maps(); } else { return NULL; } @@ -862,8 +867,7 @@ if (adr_impl != NULL) { return adr_impl + 1; } else { - return (Klass**)(start_of_nonstatic_oop_maps() + - nonstatic_oop_map_count()); + return end_of_nonstatic_oop_maps(); } } else { return NULL; diff -r 753e5733b5c9 -r df8faef6efaf hotspot/src/share/vm/oops/method.cpp --- a/hotspot/src/share/vm/oops/method.cpp Fri Feb 08 16:56:03 2013 -0800 +++ b/hotspot/src/share/vm/oops/method.cpp Mon Feb 11 14:06:22 2013 -0500 @@ -61,24 +61,14 @@ Method* Method::allocate(ClassLoaderData* loader_data, int byte_code_size, AccessFlags access_flags, - int compressed_line_number_size, - int localvariable_table_length, - int exception_table_length, - int checked_exceptions_length, - int method_parameters_length, - u2 generic_signature_index, + InlineTableSizes* sizes, ConstMethod::MethodType method_type, TRAPS) { assert(!access_flags.is_native() || byte_code_size == 0, "native methods should not contain byte codes"); ConstMethod* cm = ConstMethod::allocate(loader_data, byte_code_size, - compressed_line_number_size, - localvariable_table_length, - exception_table_length, - checked_exceptions_length, - method_parameters_length, - generic_signature_index, + sizes, method_type, CHECK_NULL); @@ -317,14 +307,6 @@ } -void Method::set_interpreter_kind() { - int kind = Interpreter::method_kind(this); - assert(kind != Interpreter::invalid, - "interpreter entry must be valid"); - set_interpreter_kind(kind); -} - - // Attempt to return method oop to original state. Clear any pointers // (to objects outside the shared spaces). We won't be able to predict // where they should point in a new JVM. Further initialize some @@ -332,7 +314,6 @@ void Method::remove_unshareable_info() { unlink_method(); - set_interpreter_kind(); } @@ -1045,9 +1026,9 @@ methodHandle m; { + InlineTableSizes sizes; Method* m_oop = Method::allocate(loader_data, 0, - accessFlags_from(flags_bits), - 0, 0, 0, 0, 0, 0, + accessFlags_from(flags_bits), &sizes, ConstMethod::NORMAL, CHECK_(empty)); m = methodHandle(THREAD, m_oop); } @@ -1096,22 +1077,35 @@ assert(!m->is_native(), "cannot rewrite native methods"); // Allocate new Method* AccessFlags flags = m->access_flags(); - u2 generic_signature_index = m->generic_signature_index(); - int checked_exceptions_len = m->checked_exceptions_length(); - int localvariable_len = m->localvariable_table_length(); - int exception_table_len = m->exception_table_length(); - int method_parameters_len = m->method_parameters_length(); + + ConstMethod* cm = m->constMethod(); + int checked_exceptions_len = cm->checked_exceptions_length(); + int localvariable_len = cm->localvariable_table_length(); + int exception_table_len = cm->exception_table_length(); + int method_parameters_len = cm->method_parameters_length(); + int method_annotations_len = cm->method_annotations_length(); + int parameter_annotations_len = cm->parameter_annotations_length(); + int type_annotations_len = cm->type_annotations_length(); + int default_annotations_len = cm->default_annotations_length(); + + InlineTableSizes sizes( + localvariable_len, + new_compressed_linenumber_size, + exception_table_len, + checked_exceptions_len, + method_parameters_len, + cm->generic_signature_index(), + method_annotations_len, + parameter_annotations_len, + type_annotations_len, + default_annotations_len, + 0); ClassLoaderData* loader_data = m->method_holder()->class_loader_data(); Method* newm_oop = Method::allocate(loader_data, new_code_length, flags, - new_compressed_linenumber_size, - localvariable_len, - exception_table_len, - checked_exceptions_len, - method_parameters_len, - generic_signature_index, + &sizes, m->method_type(), CHECK_(methodHandle())); methodHandle newm (THREAD, newm_oop); @@ -1311,29 +1305,6 @@ MethodHandles::print_as_basic_type_signature_on(st, signature(), true); } -// This is only done during class loading, so it is OK to assume method_idnum matches the methods() array -static void reorder_based_on_method_index(Array* methods, - Array* annotations, - GrowableArray* temp_array) { - if (annotations == NULL) { - return; - } - - int length = methods->length(); - int i; - // Copy to temp array - temp_array->clear(); - for (i = 0; i < length; i++) { - temp_array->append(annotations->at(i)); - } - - // Copy back using old method indices - for (i = 0; i < length; i++) { - Method* m = methods->at(i); - annotations->at_put(i, temp_array->at(m->method_idnum())); - } -} - // Comparer for sorting an object array containing // Method*s. static int method_comparator(Method* a, Method* b) { @@ -1341,48 +1312,13 @@ } // This is only done during class loading, so it is OK to assume method_idnum matches the methods() array -void Method::sort_methods(Array* methods, - Array* methods_annotations, - Array* methods_parameter_annotations, - Array* methods_default_annotations, - Array* methods_type_annotations, - bool idempotent) { +void Method::sort_methods(Array* methods, bool idempotent) { int length = methods->length(); if (length > 1) { - bool do_annotations = false; - if (methods_annotations != NULL || - methods_parameter_annotations != NULL || - methods_default_annotations != NULL || - methods_type_annotations != NULL) { - do_annotations = true; - } - if (do_annotations) { - // Remember current method ordering so we can reorder annotations - for (int i = 0; i < length; i++) { - Method* m = methods->at(i); - m->set_method_idnum(i); - } - } { No_Safepoint_Verifier nsv; QuickSort::sort(methods->data(), length, method_comparator, idempotent); } - - // Sort annotations if necessary - assert(methods_annotations == NULL || methods_annotations->length() == methods->length(), ""); - assert(methods_parameter_annotations == NULL || methods_parameter_annotations->length() == methods->length(), ""); - assert(methods_default_annotations == NULL || methods_default_annotations->length() == methods->length(), ""); - assert(methods_type_annotations == NULL || methods_type_annotations->length() == methods->length(), ""); - if (do_annotations) { - ResourceMark rm; - // Allocate temporary storage - GrowableArray* temp_array = new GrowableArray(length); - reorder_based_on_method_index(methods, methods_annotations, temp_array); - reorder_based_on_method_index(methods, methods_parameter_annotations, temp_array); - reorder_based_on_method_index(methods, methods_default_annotations, temp_array); - reorder_based_on_method_index(methods, methods_type_annotations, temp_array); - } - // Reset method ordering for (int i = 0; i < length; i++) { Method* m = methods->at(i); diff -r 753e5733b5c9 -r df8faef6efaf hotspot/src/share/vm/oops/method.hpp --- a/hotspot/src/share/vm/oops/method.hpp Fri Feb 08 16:56:03 2013 -0800 +++ b/hotspot/src/share/vm/oops/method.hpp Mon Feb 11 14:06:22 2013 -0500 @@ -101,6 +101,7 @@ class AdapterHandlerEntry; class MethodData; class ConstMethod; +class InlineTableSizes; class KlassSizeStats; class Method : public Metadata { @@ -157,12 +158,7 @@ static Method* allocate(ClassLoaderData* loader_data, int byte_code_size, AccessFlags access_flags, - int compressed_line_number_size, - int localvariable_table_length, - int exception_table_length, - int checked_exceptions_length, - int method_parameters_length, - u2 generic_signature_index, + InlineTableSizes* sizes, ConstMethod::MethodType method_type, TRAPS); @@ -207,33 +203,17 @@ // annotations support AnnotationArray* annotations() const { - InstanceKlass* ik = method_holder(); - if (ik->annotations() == NULL) { - return NULL; - } - return ik->annotations()->get_method_annotations_of(method_idnum()); + return constMethod()->method_annotations(); } AnnotationArray* parameter_annotations() const { - InstanceKlass* ik = method_holder(); - if (ik->annotations() == NULL) { - return NULL; - } - return ik->annotations()->get_method_parameter_annotations_of(method_idnum()); + return constMethod()->parameter_annotations(); } AnnotationArray* annotation_default() const { - InstanceKlass* ik = method_holder(); - if (ik->annotations() == NULL) { - return NULL; - } - return ik->annotations()->get_method_default_annotations_of(method_idnum()); + return constMethod()->default_annotations(); } - AnnotationArray* type_annotations() const { - InstanceKlass* ik = method_holder(); - Annotations* type_annos = ik->type_annotations(); - if (type_annos == NULL) - return NULL; - return type_annos->get_method_annotations_of(method_idnum()); -} + AnnotationArray* type_annotations() const { + return constMethod()->type_annotations(); + } #ifdef CC_INTERP void set_result_index(BasicType type); @@ -439,13 +419,6 @@ address interpreter_entry() const { return _i2i_entry; } // Only used when first initialize so we can set _i2i_entry and _from_interpreted_entry void set_interpreter_entry(address entry) { _i2i_entry = entry; _from_interpreted_entry = entry; } - int interpreter_kind(void) { - return constMethod()->interpreter_kind(); - } - void set_interpreter_kind(); - void set_interpreter_kind(int kind) { - constMethod()->set_interpreter_kind(kind); - } // native function (used for native methods only) enum { @@ -808,12 +781,7 @@ #endif // Helper routine used for method sorting - static void sort_methods(Array* methods, - Array* methods_annotations, - Array* methods_parameter_annotations, - Array* methods_default_annotations, - Array* methods_type_annotations, - bool idempotent = false); + static void sort_methods(Array* methods, bool idempotent = false); // Deallocation function for redefine classes or if an error occurs void deallocate_contents(ClassLoaderData* loader_data); diff -r 753e5733b5c9 -r df8faef6efaf hotspot/src/share/vm/prims/jvm.cpp --- a/hotspot/src/share/vm/prims/jvm.cpp Fri Feb 08 16:56:03 2013 -0800 +++ b/hotspot/src/share/vm/prims/jvm.cpp Mon Feb 11 14:06:22 2013 -0500 @@ -1573,9 +1573,9 @@ if (!java_lang_Class::is_primitive(JNIHandles::resolve(cls))) { Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve(cls)); if (k->oop_is_instance()) { - Annotations* type_annotations = InstanceKlass::cast(k)->type_annotations(); + AnnotationArray* type_annotations = InstanceKlass::cast(k)->class_type_annotations(); if (type_annotations != NULL) { - typeArrayOop a = Annotations::make_java_array(type_annotations->class_annotations(), CHECK_NULL); + typeArrayOop a = Annotations::make_java_array(type_annotations, CHECK_NULL); return (jbyteArray) JNIHandles::make_local(env, a); } } diff -r 753e5733b5c9 -r df8faef6efaf hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp --- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Fri Feb 08 16:56:03 2013 -0800 +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Mon Feb 11 14:06:22 2013 -0500 @@ -492,26 +492,6 @@ } // end find_or_append_indirect_entry() -void VM_RedefineClasses::swap_all_method_annotations(int i, int j, instanceKlassHandle scratch_class, TRAPS) { - AnnotationArray* save; - - Annotations* sca = scratch_class->annotations(); - if (sca == NULL) return; - - save = sca->get_method_annotations_of(i); - sca->set_method_annotations_of(scratch_class, i, sca->get_method_annotations_of(j), CHECK); - sca->set_method_annotations_of(scratch_class, j, save, CHECK); - - save = sca->get_method_parameter_annotations_of(i); - sca->set_method_parameter_annotations_of(scratch_class, i, sca->get_method_parameter_annotations_of(j), CHECK); - sca->set_method_parameter_annotations_of(scratch_class, j, save, CHECK); - - save = sca->get_method_default_annotations_of(i); - sca->set_method_default_annotations_of(scratch_class, i, sca->get_method_default_annotations_of(j), CHECK); - sca->set_method_default_annotations_of(scratch_class, j, save, CHECK); -} - - jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions( instanceKlassHandle the_class, instanceKlassHandle scratch_class) { @@ -693,10 +673,9 @@ idnum_owner->set_method_idnum(new_num); } k_new_method->set_method_idnum(old_num); - swap_all_method_annotations(old_num, new_num, scratch_class, thread); - if (thread->has_pending_exception()) { - return JVMTI_ERROR_OUT_OF_MEMORY; - } + if (thread->has_pending_exception()) { + return JVMTI_ERROR_OUT_OF_MEMORY; + } } } RC_TRACE(0x00008000, ("Method matched: new: %s [%d] == old: %s [%d]", @@ -729,7 +708,6 @@ idnum_owner->set_method_idnum(new_num); } k_new_method->set_method_idnum(num); - swap_all_method_annotations(new_num, num, scratch_class, thread); if (thread->has_pending_exception()) { return JVMTI_ERROR_OUT_OF_MEMORY; } @@ -1895,10 +1873,7 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_fields_annotations( instanceKlassHandle scratch_class, TRAPS) { - Annotations* sca = scratch_class->annotations(); - if (sca == NULL) return true; - - Array* fields_annotations = sca->fields_annotations(); + Array* fields_annotations = scratch_class->fields_annotations(); if (fields_annotations == NULL || fields_annotations->length() == 0) { // no fields_annotations so nothing to do @@ -1933,21 +1908,10 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_methods_annotations( instanceKlassHandle scratch_class, TRAPS) { - Annotations* sca = scratch_class->annotations(); - if (sca == NULL) return true; - - Array* methods_annotations = sca->methods_annotations(); - - if (methods_annotations == NULL || methods_annotations->length() == 0) { - // no methods_annotations so nothing to do - return true; - } - - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("methods_annotations length=%d", methods_annotations->length())); - - for (int i = 0; i < methods_annotations->length(); i++) { - AnnotationArray* method_annotations = methods_annotations->at(i); + for (int i = 0; i < scratch_class->methods()->length(); i++) { + Method* m = scratch_class->methods()->at(i); + AnnotationArray* method_annotations = m->constMethod()->method_annotations(); + if (method_annotations == NULL || method_annotations->length() == 0) { // this method does not have any annotations so skip it continue; @@ -1983,24 +1947,9 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_methods_parameter_annotations( instanceKlassHandle scratch_class, TRAPS) { - Annotations* sca = scratch_class->annotations(); - if (sca == NULL) return true; - - Array* methods_parameter_annotations = - sca->methods_parameter_annotations(); - - if (methods_parameter_annotations == NULL - || methods_parameter_annotations->length() == 0) { - // no methods_parameter_annotations so nothing to do - return true; - } - - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("methods_parameter_annotations length=%d", - methods_parameter_annotations->length())); - - for (int i = 0; i < methods_parameter_annotations->length(); i++) { - AnnotationArray* method_parameter_annotations = methods_parameter_annotations->at(i); + for (int i = 0; i < scratch_class->methods()->length(); i++) { + Method* m = scratch_class->methods()->at(i); + AnnotationArray* method_parameter_annotations = m->constMethod()->parameter_annotations(); if (method_parameter_annotations == NULL || method_parameter_annotations->length() == 0) { // this method does not have any parameter annotations so skip it @@ -2050,24 +1999,9 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_methods_default_annotations( instanceKlassHandle scratch_class, TRAPS) { - Annotations* sca = scratch_class->annotations(); - if (sca == NULL) return true; - - Array* methods_default_annotations = - sca->methods_default_annotations(); - - if (methods_default_annotations == NULL - || methods_default_annotations->length() == 0) { - // no methods_default_annotations so nothing to do - return true; - } - - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("methods_default_annotations length=%d", - methods_default_annotations->length())); - - for (int i = 0; i < methods_default_annotations->length(); i++) { - AnnotationArray* method_default_annotations = methods_default_annotations->at(i); + for (int i = 0; i < scratch_class->methods()->length(); i++) { + Method* m = scratch_class->methods()->at(i); + AnnotationArray* method_default_annotations = m->constMethod()->default_annotations(); if (method_default_annotations == NULL || method_default_annotations->length() == 0) { // this method does not have any default annotations so skip it @@ -3072,6 +3006,31 @@ } +void VM_RedefineClasses::swap_annotations(instanceKlassHandle the_class, + instanceKlassHandle scratch_class) { + // Since there is currently no rewriting of type annotations indexes + // into the CP, we null out type annotations on scratch_class before + // we swap annotations with the_class rather than facing the + // possibility of shipping annotations with broken indexes to + // Java-land. + ClassLoaderData* loader_data = scratch_class->class_loader_data(); + AnnotationArray* new_class_type_annotations = scratch_class->class_type_annotations(); + if (new_class_type_annotations != NULL) { + MetadataFactory::free_array(loader_data, new_class_type_annotations); + scratch_class->annotations()->set_class_type_annotations(NULL); + } + Array* new_field_type_annotations = scratch_class->fields_type_annotations(); + if (new_field_type_annotations != NULL) { + Annotations::free_contents(loader_data, new_field_type_annotations); + scratch_class->annotations()->set_fields_type_annotations(NULL); + } + + // Swap annotation fields values + Annotations* old_annotations = the_class->annotations(); + the_class->set_annotations(scratch_class->annotations()); + scratch_class->set_annotations(old_annotations); +} + // Install the redefinition of a class: // - house keeping (flushing breakpoints and caches, deoptimizing @@ -3282,23 +3241,7 @@ the_class->set_access_flags(flags); } - // Since there is currently no rewriting of type annotations indexes - // into the CP, we null out type annotations on scratch_class before - // we swap annotations with the_class rather than facing the - // possibility of shipping annotations with broken indexes to - // Java-land. - Annotations* new_annotations = scratch_class->annotations(); - if (new_annotations != NULL) { - Annotations* new_type_annotations = new_annotations->type_annotations(); - if (new_type_annotations != NULL) { - MetadataFactory::free_metadata(scratch_class->class_loader_data(), new_type_annotations); - new_annotations->set_type_annotations(NULL); - } - } - // Swap annotation fields values - Annotations* old_annotations = the_class->annotations(); - the_class->set_annotations(scratch_class->annotations()); - scratch_class->set_annotations(old_annotations); + swap_annotations(the_class, scratch_class); // Replace minor version number of class file u2 old_minor_version = the_class->minor_version(); diff -r 753e5733b5c9 -r df8faef6efaf hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp --- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp Fri Feb 08 16:56:03 2013 -0800 +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp Mon Feb 11 14:06:22 2013 -0500 @@ -384,11 +384,6 @@ jvmtiError compare_and_normalize_class_versions( instanceKlassHandle the_class, instanceKlassHandle scratch_class); - // Swap annotations[i] with annotations[j] - // Used by compare_and_normalize_class_versions() when normalizing - // overloaded methods or changing idnum as when adding or deleting methods. - void swap_all_method_annotations(int i, int j, instanceKlassHandle scratch_class, TRAPS); - // Figure out which new methods match old methods in name and signature, // which methods have been added, and which are no longer present void compute_added_deleted_matching_methods(); @@ -417,6 +412,9 @@ void redefine_single_class(jclass the_jclass, Klass* scratch_class_oop, TRAPS); + void swap_annotations(instanceKlassHandle new_class, + instanceKlassHandle scratch_class); + // Increment the classRedefinedCount field in the specific InstanceKlass // and in all direct and indirect subclasses. void increment_class_counter(InstanceKlass *ik, TRAPS); diff -r 753e5733b5c9 -r df8faef6efaf hotspot/src/share/vm/runtime/fieldDescriptor.cpp --- a/hotspot/src/share/vm/runtime/fieldDescriptor.cpp Fri Feb 08 16:56:03 2013 -0800 +++ b/hotspot/src/share/vm/runtime/fieldDescriptor.cpp Mon Feb 11 14:06:22 2013 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,13 +67,10 @@ AnnotationArray* fieldDescriptor::type_annotations() const { InstanceKlass* ik = field_holder(); - Annotations* type_annos = ik->type_annotations(); + Array* type_annos = ik->fields_type_annotations(); if (type_annos == NULL) return NULL; - Array* md = type_annos->fields_annotations(); - if (md == NULL) - return NULL; - return md->at(index()); + return type_annos->at(index()); } constantTag fieldDescriptor::initial_value_tag() const { diff -r 753e5733b5c9 -r df8faef6efaf hotspot/src/share/vm/runtime/vmStructs.cpp --- a/hotspot/src/share/vm/runtime/vmStructs.cpp Fri Feb 08 16:56:03 2013 -0800 +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Mon Feb 11 14:06:22 2013 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -366,11 +366,10 @@ volatile_nonstatic_field(Method, _from_compiled_entry, address) \ volatile_nonstatic_field(Method, _from_interpreted_entry, address) \ volatile_nonstatic_field(ConstMethod, _fingerprint, uint64_t) \ - nonstatic_field(ConstMethod, _constants, ConstantPool*) \ + nonstatic_field(ConstMethod, _constants, ConstantPool*) \ nonstatic_field(ConstMethod, _stackmap_data, Array*) \ nonstatic_field(ConstMethod, _constMethod_size, int) \ - nonstatic_field(ConstMethod, _interpreter_kind, jbyte) \ - nonstatic_field(ConstMethod, _flags, jbyte) \ + nonstatic_field(ConstMethod, _flags, u2) \ nonstatic_field(ConstMethod, _code_size, u2) \ nonstatic_field(ConstMethod, _name_index, u2) \ nonstatic_field(ConstMethod, _signature_index, u2) \ @@ -2261,14 +2260,18 @@ declare_constant(Klass::_lh_array_tag_obj_value) \ \ /********************************/ \ - /* ConstMethod anon-enum */ \ + /* ConstMethod anon-enum */ \ /********************************/ \ \ - declare_constant(ConstMethod::_has_linenumber_table) \ - declare_constant(ConstMethod::_has_checked_exceptions) \ - declare_constant(ConstMethod::_has_localvariable_table) \ - declare_constant(ConstMethod::_has_exception_table) \ - declare_constant(ConstMethod::_has_generic_signature) \ + declare_constant(ConstMethod::_has_linenumber_table) \ + declare_constant(ConstMethod::_has_checked_exceptions) \ + declare_constant(ConstMethod::_has_localvariable_table) \ + declare_constant(ConstMethod::_has_exception_table) \ + declare_constant(ConstMethod::_has_generic_signature) \ + declare_constant(ConstMethod::_has_method_annotations) \ + declare_constant(ConstMethod::_has_parameter_annotations) \ + declare_constant(ConstMethod::_has_default_annotations) \ + declare_constant(ConstMethod::_has_type_annotations) \ \ /*************************************/ \ /* InstanceKlass enum */ \ diff -r 753e5733b5c9 -r df8faef6efaf hotspot/test/runtime/8007320/ConstMethodTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/8007320/ConstMethodTest.java Mon Feb 11 14:06:22 2013 -0500 @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8007320 + * @summary Test all optional fields in ConstMethod + * @compile -g -parameters ConstMethodTest.java + * @run main ConstMethodTest + */ + +import java.util.*; +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.io.Serializable; + +@Retention(RetentionPolicy.RUNTIME) +@interface MyAnnotation { + public String name(); + public String value(); + public String date() default "today"; +} + +@Target(ElementType.TYPE_USE) +@Retention(RetentionPolicy.RUNTIME) +@interface TypeAnno { + String value(); +} + +@Target(ElementType.TYPE_USE) +@Retention(RetentionPolicy.RUNTIME) +@interface TypeAnno2 { + String value(); +} + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@interface Named { + String value(); +} + +@Retention(RetentionPolicy.RUNTIME) +@interface ScalarTypesWithDefault { + byte b() default 11; + short s() default 12; + int i() default 13; + long l() default 14; + char c() default 'V'; +} + +// Some exception class +class OkException extends RuntimeException {}; + + +@MyAnnotation(name="someName", value = "Hello World") +public class ConstMethodTest { + + private static void check(boolean b) { + if (!b) + throw new RuntimeException(); + } + private static void fail(String msg) { + System.err.println(msg); + throw new RuntimeException(); + } + private static void equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) { + } else { + fail(x + " not equal to " + y); + } + } + private static final String[] parameter_names = { + "parameter", "parameter2", "x" + }; + + // Declare a function with everything in it. + @MyAnnotation(name="someName", value="Hello World") + static void kitchenSinkFunc(@Named(value="aName") String parameter, + @Named("bName") String parameter2, + @ScalarTypesWithDefault T x) + throws @TypeAnno("RE") @TypeAnno2("RE2") RuntimeException, + NullPointerException, + @TypeAnno("AIOOBE") ArrayIndexOutOfBoundsException { + int i, j, k; + try { + System.out.println("calling kitchenSinkFunc " + parameter); + throw new OkException(); // to see stack trace with line numbers + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static void test1() throws Throwable { + for (Method m : ConstMethodTest.class.getDeclaredMethods()) { + if (m.getName().equals("kitchenSinkFunc")) { + Annotation[][] ann = m.getParameterAnnotations(); + equal(ann.length, 3); + Annotation foo = ann[0][0]; + Annotation bar = ann[1][0]; + equal(foo.toString(), "@Named(value=aName)"); + equal(bar.toString(), "@Named(value=bName)"); + check(foo.equals(foo)); + check(bar.equals(bar)); + check(! foo.equals(bar)); + // method annotations + Annotation[] ann2 = m.getAnnotations(); + equal(ann2.length, 1); + Annotation mann = ann2[0]; + equal(mann.toString(), "@MyAnnotation(date=today, name=someName, value=Hello World)"); + // Test Method parameter names + Parameter[] parameters = m.getParameters(); + if(parameters == null) + throw new Exception("getParameters should never be null"); + for(int i = 0; i < parameters.length; i++) { + Parameter p = parameters[i]; + equal(parameters[i].getName(), parameter_names[i]); + } + } + } + } + + public static void main(java.lang.String[] unused) throws Throwable { + // pass 5 so kitchenSinkFunc is instantiated with an int + kitchenSinkFunc("parameter", "param2", 5); + test1(); + } +}; +