--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Fri Dec 03 12:14:33 2010 -0800
+++ b/hotspot/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<int>* operands = NULL;
-#ifdef ASSERT
- GrowableArray<int>* indy_instructions = new GrowableArray<int>(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<int>* &operands, int op_count, TRAPS) {
- if (operands == NULL) {
- operands = new GrowableArray<int>(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<int>* 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();