diff -r 7601ab0e1e33 -r dad31fc330cd src/share/vm/classfile/classFileParser.cpp --- a/src/share/vm/classfile/classFileParser.cpp Fri Dec 03 12:14:33 2010 -0800 +++ b/src/share/vm/classfile/classFileParser.cpp Fri Dec 03 15:53:57 2010 -0800 @@ -99,12 +99,6 @@ unsigned int hashValues[SymbolTable::symbol_alloc_batch_size]; int names_count = 0; - // Side buffer for operands of variable-sized (InvokeDynamic) entries. - GrowableArray* operands = NULL; -#ifdef ASSERT - GrowableArray* indy_instructions = new GrowableArray(THREAD, 10); -#endif - // parsing Index 0 is unused for (int index = 1; index < length; index++) { // Each of the following case guarantees one more byte in the stream @@ -184,36 +178,20 @@ "Class file version does not support constant tag %u in class file %s"), tag, CHECK); } - if (!AllowTransitionalJSR292 && tag == JVM_CONSTANT_InvokeDynamicTrans) { - classfile_parse_error( + cfs->guarantee_more(5, CHECK); // bsm_index, nt, tag/access_flags + u2 bootstrap_specifier_index = cfs->get_u2_fast(); + u2 name_and_type_index = cfs->get_u2_fast(); + if (tag == JVM_CONSTANT_InvokeDynamicTrans) { + if (!AllowTransitionalJSR292) + classfile_parse_error( "This JVM does not support transitional InvokeDynamic tag %u in class file %s", tag, CHECK); + cp->invoke_dynamic_trans_at_put(index, bootstrap_specifier_index, name_and_type_index); + break; } - bool trans_no_argc = AllowTransitionalJSR292 && (tag == JVM_CONSTANT_InvokeDynamicTrans); - cfs->guarantee_more(7, CHECK); // bsm_index, nt, argc, ..., tag/access_flags - u2 bootstrap_method_index = cfs->get_u2_fast(); - u2 name_and_type_index = cfs->get_u2_fast(); - int argument_count = trans_no_argc ? 0 : cfs->get_u2_fast(); - cfs->guarantee_more(2*argument_count + 1, CHECK); // argv[argc]..., tag/access_flags - int argv_offset = constantPoolOopDesc::_indy_argv_offset; - int op_count = argv_offset + argument_count; // bsm, nt, argc, argv[]... - int op_base = start_operand_group(operands, op_count, CHECK); - assert(argv_offset == 3, "else adjust next 3 assignments"); - operands->at_put(op_base + constantPoolOopDesc::_indy_bsm_offset, bootstrap_method_index); - operands->at_put(op_base + constantPoolOopDesc::_indy_nt_offset, name_and_type_index); - operands->at_put(op_base + constantPoolOopDesc::_indy_argc_offset, argument_count); - for (int arg_i = 0; arg_i < argument_count; arg_i++) { - int arg = cfs->get_u2_fast(); - operands->at_put(op_base + constantPoolOopDesc::_indy_argv_offset + arg_i, arg); - } - cp->invoke_dynamic_at_put(index, op_base, op_count); -#ifdef ASSERT - // Record the steps just taken for later checking. - indy_instructions->append(index); - indy_instructions->append(bootstrap_method_index); - indy_instructions->append(name_and_type_index); - indy_instructions->append(argument_count); -#endif //ASSERT + if (_max_bootstrap_specifier_index < (int) bootstrap_specifier_index) + _max_bootstrap_specifier_index = (int) bootstrap_specifier_index; // collect for later + cp->invoke_dynamic_at_put(index, bootstrap_specifier_index, name_and_type_index); } break; case JVM_CONSTANT_Integer : @@ -316,23 +294,6 @@ oopFactory::new_symbols(cp, names_count, names, lengths, indices, hashValues, CHECK); } - if (operands != NULL && operands->length() > 0) { - store_operand_array(operands, cp, CHECK); - } -#ifdef ASSERT - // Re-assert the indy structures, now that assertion checking can work. - for (int indy_i = 0; indy_i < indy_instructions->length(); ) { - int index = indy_instructions->at(indy_i++); - int bootstrap_method_index = indy_instructions->at(indy_i++); - int name_and_type_index = indy_instructions->at(indy_i++); - int argument_count = indy_instructions->at(indy_i++); - assert(cp->check_invoke_dynamic_at(index, - bootstrap_method_index, name_and_type_index, - argument_count), - "indy structure is OK"); - } -#endif //ASSERT - // Copy _current pointer of local copy back to stream(). #ifdef ASSERT assert(cfs0->current() == old_current, "non-exclusive use of stream()"); @@ -340,41 +301,6 @@ cfs0->set_current(cfs1.current()); } -int ClassFileParser::start_operand_group(GrowableArray* &operands, int op_count, TRAPS) { - if (operands == NULL) { - operands = new GrowableArray(THREAD, 100); - int fillp_offset = constantPoolOopDesc::_multi_operand_buffer_fill_pointer_offset; - while (operands->length() <= fillp_offset) - operands->append(0); // force op_base > 0, for an error check - DEBUG_ONLY(operands->at_put(fillp_offset, (int)badHeapWordVal)); - } - int cnt_pos = operands->append(op_count); - int arg_pos = operands->length(); - operands->at_grow(arg_pos + op_count - 1); // grow to include the operands - assert(operands->length() == arg_pos + op_count, ""); - int op_base = cnt_pos - constantPoolOopDesc::_multi_operand_count_offset; - return op_base; -} - -void ClassFileParser::store_operand_array(GrowableArray* operands, constantPoolHandle cp, TRAPS) { - // Collect the buffer of operands from variable-sized entries into a permanent array. - int arraylen = operands->length(); - int fillp_offset = constantPoolOopDesc::_multi_operand_buffer_fill_pointer_offset; - assert(operands->at(fillp_offset) == (int)badHeapWordVal, "value unused so far"); - operands->at_put(fillp_offset, arraylen); - cp->multi_operand_buffer_grow(arraylen, CHECK); - typeArrayOop operands_oop = cp->operands(); - assert(operands_oop->length() == arraylen, ""); - for (int i = 0; i < arraylen; i++) { - operands_oop->int_at_put(i, operands->at(i)); - } - cp->set_operands(operands_oop); - // The fill_pointer is used only by constantPoolOop::copy_entry_to and friends, - // when constant pools need to be merged. Make sure it is sane now. - assert(cp->multi_operand_buffer_fill_pointer() == arraylen, ""); -} - - bool inline valid_cp_range(int index, int length) { return (index > 0 && index < length); } constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) { @@ -401,7 +327,8 @@ // first verification pass - validate cross references and fixup class and string constants for (index = 1; index < length; index++) { // Index 0 is unused - switch (cp->tag_at(index).value()) { + jbyte tag = cp->tag_at(index).value(); + switch (tag) { case JVM_CONSTANT_Class : ShouldNotReachHere(); // Only JVM_CONSTANT_ClassIndex should be present break; @@ -543,35 +470,23 @@ } break; case JVM_CONSTANT_InvokeDynamicTrans : - ShouldNotReachHere(); // this tag does not appear in the heap case JVM_CONSTANT_InvokeDynamic : { - int bootstrap_method_ref_index = cp->invoke_dynamic_bootstrap_method_ref_index_at(index); int name_and_type_ref_index = cp->invoke_dynamic_name_and_type_ref_index_at(index); - check_property((bootstrap_method_ref_index == 0 && AllowTransitionalJSR292) - || - (valid_cp_range(bootstrap_method_ref_index, length) && - (cp->tag_at(bootstrap_method_ref_index).is_method_handle())), - "Invalid constant pool index %u in class file %s", - bootstrap_method_ref_index, - CHECK_(nullHandle)); check_property(valid_cp_range(name_and_type_ref_index, length) && cp->tag_at(name_and_type_ref_index).is_name_and_type(), "Invalid constant pool index %u in class file %s", name_and_type_ref_index, CHECK_(nullHandle)); - int argc = cp->invoke_dynamic_argument_count_at(index); - for (int arg_i = 0; arg_i < argc; arg_i++) { - int arg = cp->invoke_dynamic_argument_index_at(index, arg_i); - check_property(valid_cp_range(arg, length) && - cp->tag_at(arg).is_loadable_constant() || - // temporary early forms of string and class: - cp->tag_at(arg).is_klass_index() || - cp->tag_at(arg).is_string_index(), + if (tag == JVM_CONSTANT_InvokeDynamicTrans) { + int bootstrap_method_ref_index = cp->invoke_dynamic_bootstrap_method_ref_index_at(index); + check_property(valid_cp_range(bootstrap_method_ref_index, length) && + cp->tag_at(bootstrap_method_ref_index).is_method_handle(), "Invalid constant pool index %u in class file %s", - arg, + bootstrap_method_ref_index, CHECK_(nullHandle)); } + // bootstrap specifier index must be checked later, when BootstrapMethods attr is available break; } default: @@ -2429,6 +2344,76 @@ k->set_generic_signature(cp->symbol_at(signature_index)); } +void ClassFileParser::parse_classfile_bootstrap_methods_attribute(constantPoolHandle cp, instanceKlassHandle k, + u4 attribute_byte_length, TRAPS) { + ClassFileStream* cfs = stream(); + u1* current_start = cfs->current(); + + cfs->guarantee_more(2, CHECK); // length + int attribute_array_length = cfs->get_u2_fast(); + + guarantee_property(_max_bootstrap_specifier_index < attribute_array_length, + "Short length on BootstrapMethods in class file %s", + CHECK); + + // The attribute contains a counted array of counted tuples of shorts, + // represending bootstrap specifiers: + // length*{bootstrap_method_index, argument_count*{argument_index}} + int operand_count = (attribute_byte_length - sizeof(u2)) / sizeof(u2); + // operand_count = number of shorts in attr, except for leading length + + // The attribute is copied into a short[] array. + // The array begins with a series of short[2] pairs, one for each tuple. + int index_size = (attribute_array_length * 2); + + typeArrayOop operands_oop = oopFactory::new_permanent_intArray(index_size + operand_count, CHECK); + typeArrayHandle operands(THREAD, operands_oop); + operands_oop = NULL; // tidy + + int operand_fill_index = index_size; + int cp_size = cp->length(); + + for (int n = 0; n < attribute_array_length; n++) { + // Store a 32-bit offset into the header of the operand array. + assert(constantPoolOopDesc::operand_offset_at(operands(), n) == 0, ""); + constantPoolOopDesc::operand_offset_at_put(operands(), n, operand_fill_index); + + // Read a bootstrap specifier. + cfs->guarantee_more(sizeof(u2) * 2, CHECK); // bsm, argc + u2 bootstrap_method_index = cfs->get_u2_fast(); + u2 argument_count = cfs->get_u2_fast(); + check_property( + valid_cp_range(bootstrap_method_index, cp_size) && + cp->tag_at(bootstrap_method_index).is_method_handle(), + "bootstrap_method_index %u has bad constant type in class file %s", + CHECK); + operands->short_at_put(operand_fill_index++, bootstrap_method_index); + operands->short_at_put(operand_fill_index++, argument_count); + + cfs->guarantee_more(sizeof(u2) * argument_count, CHECK); // argv[argc] + for (int j = 0; j < argument_count; j++) { + u2 arg_index = cfs->get_u2_fast(); + check_property( + valid_cp_range(arg_index, cp_size) && + cp->tag_at(arg_index).is_loadable_constant(), + "argument_index %u has bad constant type in class file %s", + CHECK); + operands->short_at_put(operand_fill_index++, arg_index); + } + } + + assert(operand_fill_index == operands()->length(), "exact fill"); + assert(constantPoolOopDesc::operand_array_length(operands()) == attribute_array_length, "correct decode"); + + u1* current_end = cfs->current(); + guarantee_property(current_end == current_start + attribute_byte_length, + "Bad length on BootstrapMethods in class file %s", + CHECK); + + cp->set_operands(operands()); +} + + void ClassFileParser::parse_classfile_attributes(constantPoolHandle cp, instanceKlassHandle k, TRAPS) { ClassFileStream* cfs = stream(); // Set inner classes attribute to default sentinel @@ -2438,6 +2423,7 @@ bool parsed_sourcefile_attribute = false; bool parsed_innerclasses_attribute = false; bool parsed_enclosingmethod_attribute = false; + bool parsed_bootstrap_methods_attribute = false; u1* runtime_visible_annotations = NULL; int runtime_visible_annotations_length = 0; u1* runtime_invisible_annotations = NULL; @@ -2536,6 +2522,12 @@ classfile_parse_error("Invalid or out-of-bounds method index in EnclosingMethod attribute in class file %s", CHECK); } k->set_enclosing_method_indices(class_index, method_index); + } else if (tag == vmSymbols::tag_bootstrap_methods() && + _major_version >= Verifier::INVOKEDYNAMIC_MAJOR_VERSION) { + if (parsed_bootstrap_methods_attribute) + classfile_parse_error("Multiple BootstrapMethods attributes in class file %s", CHECK); + parsed_bootstrap_methods_attribute = true; + parse_classfile_bootstrap_methods_attribute(cp, k, attribute_length, CHECK); } else { // Unknown attribute cfs->skip_u1(attribute_length, CHECK); @@ -2551,6 +2543,11 @@ runtime_invisible_annotations_length, CHECK); k->set_class_annotations(annotations()); + + if (_max_bootstrap_specifier_index >= 0) { + guarantee_property(parsed_bootstrap_methods_attribute, + "Missing BootstrapMethods attribute in class file %s", CHECK); + } } @@ -2868,6 +2865,7 @@ PerfClassTraceTime::PARSE_CLASS); _has_finalizer = _has_empty_finalizer = _has_vanilla_constructor = false; + _max_bootstrap_specifier_index = -1; if (JvmtiExport::should_post_class_file_load_hook()) { unsigned char* ptr = cfs->buffer();