src/share/vm/classfile/classFileParser.cpp
Print this page
rev 3 : [mq]: anonk.patch
@@ -165,15 +165,27 @@
u1* utf8_buffer = cfs->get_u1_buffer();
assert(utf8_buffer != NULL, "null utf8 buffer");
// Got utf8 string, guarantee utf8_length+1 bytes, set stream position forward.
cfs->guarantee_more(utf8_length+1, CHECK); // utf8 string, tag/access_flags
cfs->skip_u1_fast(utf8_length);
+
// Before storing the symbol, make sure it's legal
if (_need_verify) {
verify_legal_utf8((unsigned char*)utf8_buffer, utf8_length, CHECK);
}
+ if (has_cp_patch_at(index)) {
+ Handle patch = clear_cp_patch_at(index);
+ guarantee_property(java_lang_String::is_instance(patch()),
+ "Illegal utf8 patch at %d in class file %s",
+ index, CHECK);
+ char* str = java_lang_String::as_utf8_string(patch());
+ // (could use java_lang_String::as_symbol instead, but might as well batch them)
+ utf8_buffer = (u1*) str;
+ utf8_length = strlen(str);
+ }
+
unsigned int hash;
symbolOop result = SymbolTable::lookup_only((char*)utf8_buffer, utf8_length, hash);
if (result == NULL) {
names[names_count] = (char*)utf8_buffer;
lengths[names_count] = utf8_length;
@@ -298,12 +310,18 @@
check_property(
valid_cp_range(class_index, length) &&
cp->tag_at(class_index).is_utf8(),
"Invalid constant pool index %u in class file %s",
class_index, CHECK_(nullHandle));
- cp->unresolved_klass_at_put(index, cp->symbol_at(class_index));
+ symbolOop name = cp->symbol_at(class_index);
+ klassOop wkk = SystemDictionary::find_well_known_klass(name);
+ if (wkk != NULL) {
+ cp->klass_at_put(index, wkk); // eagerly resolve
+ } else {
+ cp->unresolved_klass_at_put(index, name);
}
+ }
break;
case JVM_CONSTANT_UnresolvedString :
ShouldNotReachHere(); // Only JVM_CONSTANT_StringIndex should be present
break;
case JVM_CONSTANT_StringIndex :
@@ -323,20 +341,49 @@
ShouldNotReachHere();
break;
} // end of switch
} // end of for
+ if (_cp_patches != NULL) {
+ // need to treat this_class specially...
+ int this_class_index;
+ {
+ cfs->guarantee_more(8, CHECK_(nullHandle)); // flags, this_class, super_class, infs_len
+ u1* mark = cfs->current();
+ u2 flags = cfs->get_u2_fast();
+ this_class_index = cfs->get_u2_fast();
+ cfs->set_current(mark); // revert to mark
+ }
+
+ for (index = 1; index < length; index++) { // Index 0 is unused
+ if (has_cp_patch_at(index)) {
+ guarantee_property(index != this_class_index,
+ "Illegal constant pool patch to self at %d in class file %s",
+ index, CHECK_(nullHandle));
+ patch_constant_pool(cp, index, cp_patch_at(index), CHECK_(nullHandle));
+ }
+ }
+ // Ensure that all the patches have been used.
+ for (index = 0; index < _cp_patches->length(); index++) {
+ guarantee_property(!has_cp_patch_at(index),
+ "Unused constant pool patch at %d in class file %s",
+ index, CHECK_(nullHandle));
+ }
+ }
+
if (!_need_verify) {
return cp;
}
// second verification pass - checks the strings are of the right format.
+ // but not yet to the other entries
for (index = 1; index < length; index++) {
jbyte tag = cp->tag_at(index).value();
switch (tag) {
case JVM_CONSTANT_UnresolvedClass: {
symbolHandle class_name(THREAD, cp->unresolved_klass_at(index));
+ // check the name, even if _cp_patches will overwrite it
verify_legal_class_name(class_name, CHECK_(nullHandle));
break;
}
case JVM_CONSTANT_Fieldref:
case JVM_CONSTANT_Methodref:
@@ -375,10 +422,68 @@
return cp;
}
+void ClassFileParser::patch_constant_pool(constantPoolHandle cp, int index, Handle patch, TRAPS) {
+ BasicType patch_type = T_VOID;
+ switch (cp->tag_at(index).value()) {
+
+ case JVM_CONSTANT_UnresolvedClass :
+ // Patching a class means pre-resolving it.
+ // The name in the constant pool is ignored.
+ guarantee_property(java_lang_Class::is_instance(patch())
+ && !java_lang_Class::is_primitive(patch()),
+ "Illegal class patch at %d in class file %s",
+ index, CHECK);
+ cp->klass_at_put(index, java_lang_Class::as_klassOop(patch()));
+ break;
+
+ case JVM_CONSTANT_UnresolvedString :
+ // Patching a string means pre-resolving it.
+ // The spelling in the constant pool is ignored.
+ // The constant reference may be any object whatever.
+ // If it is not a real string, the constant is referred to
+ // as a "pseudo-string".
+ cp->string_at_put(index, patch());
+ break;
+
+ case JVM_CONSTANT_Integer : patch_type = T_INT; goto patch_prim;
+ case JVM_CONSTANT_Float : patch_type = T_FLOAT; goto patch_prim;
+ case JVM_CONSTANT_Long : patch_type = T_LONG; goto patch_prim;
+ case JVM_CONSTANT_Double : patch_type = T_DOUBLE; goto patch_prim;
+ patch_prim:
+ {
+ jvalue value;
+ BasicType value_type = java_lang_boxing_object::get_value(patch(), &value);
+ guarantee_property(value_type == patch_type,
+ "Illegal primitive patch at %d in class file %s",
+ index, CHECK);
+ switch (value_type) {
+ case T_INT: cp->int_at_put(index, value.i); break;
+ case T_FLOAT: cp->float_at_put(index, value.f); break;
+ case T_LONG: cp->long_at_put(index, value.j); break;
+ case T_DOUBLE: cp->long_at_put(index, value.d); break;
+ default: assert(false, "");
+ }
+ }
+ break;
+
+ default:
+ // %%% TODO: put method handles into CONSTANT_InterfaceMethodref, etc.
+ guarantee_property(!has_cp_patch_at(index),
+ "Illegal unexpected patch at %d in class file %s",
+ index, CHECK);
+ return;
+ }
+
+ // On fall-through, mark the patch as used.
+ clear_cp_patch_at(index);
+}
+
+
+
class NameSigHash: public ResourceObj {
public:
symbolOop _name; // name
symbolOop _sig; // signature
NameSigHash* _next; // Next entry in hash table
@@ -445,15 +550,19 @@
objArrayHandle interfaces (THREAD, interface_oop);
int index;
for (index = 0; index < length; index++) {
u2 interface_index = cfs->get_u2(CHECK_(nullHandle));
+ KlassHandle interf;
check_property(
valid_cp_range(interface_index, cp->length()) &&
- cp->tag_at(interface_index).is_unresolved_klass(),
+ cp->tag_at(interface_index).is_klass_reference(),
"Interface name has bad constant pool index %u in class file %s",
interface_index, CHECK_(nullHandle));
+ if (cp->tag_at(interface_index).is_klass()) {
+ interf = KlassHandle(THREAD, cp->resolved_klass_at(interface_index));
+ } else {
symbolHandle unresolved_klass (THREAD, cp->klass_name_at(interface_index));
// Don't need to check legal name because it's checked when parsing constant pool.
// But need to make sure it's not an array type.
guarantee_property(unresolved_klass->byte_at(0) != JVM_SIGNATURE_ARRAY,
@@ -462,13 +571,16 @@
vmtimer->suspend(); // do not count recursive loading twice
// Call resolve_super so classcircularity is checked
klassOop k = SystemDictionary::resolve_super_or_fail(class_name,
unresolved_klass, class_loader, protection_domain,
false, CHECK_(nullHandle));
- KlassHandle interf (THREAD, k);
+ interf = KlassHandle(THREAD, k);
vmtimer->resume();
+ cp->klass_at_put(interface_index, interf()); // eagerly resolve
+ }
+
if (!Klass::cast(interf())->is_interface()) {
THROW_MSG_(vmSymbols::java_lang_IncompatibleClassChangeError(), "Implementing class", nullHandle);
}
interfaces->obj_at_put(index, interf());
}
@@ -874,12 +986,11 @@
"Illegal exception table range in class file %s", CHECK_(nullHandle));
guarantee_property(handler_pc < code_length,
"Illegal exception table handler in class file %s", CHECK_(nullHandle));
if (catch_type_index != 0) {
guarantee_property(valid_cp_range(catch_type_index, cp->length()) &&
- (cp->tag_at(catch_type_index).is_klass() ||
- cp->tag_at(catch_type_index).is_unresolved_klass()),
+ cp->tag_at(catch_type_index).is_klass_reference(),
"Catch type in exception table has bad constant type in class file %s", CHECK_(nullHandle));
}
}
exception_handlers->int_at_put(index++, start_pc);
exception_handlers->int_at_put(index++, end_pc);
@@ -1114,11 +1225,11 @@
if (tag == ITEM_Long || tag == ITEM_Double) {
index++;
} else if (tag == ITEM_Object) {
u2 class_index = u2_array[i2++] = cfs->get_u2(CHECK);
guarantee_property(valid_cp_range(class_index, cp->length()) &&
- cp->tag_at(class_index).is_unresolved_klass(),
+ cp->tag_at(class_index).is_klass_reference(),
"Bad class index %u in StackMap in class file %s",
class_index, CHECK);
} else if (tag == ITEM_Uninitialized) {
u2 offset = u2_array[i2++] = cfs->get_u2(CHECK);
guarantee_property(
@@ -2337,10 +2448,11 @@
instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
Handle class_loader,
Handle protection_domain,
+ GrowableArray<Handle>* cp_patches,
symbolHandle& parsed_name,
TRAPS) {
// So that JVMTI can cache class file in the state before retransformable agents
// have modified it
unsigned char *cached_class_file_bytes = NULL;
@@ -2368,10 +2480,11 @@
cfs = new ClassFileStream(ptr, end_ptr - ptr, cfs->source());
set_stream(cfs);
}
}
+ _cp_patches = cp_patches;
instanceKlassHandle nullHandle;
// Figure out whether we can skip format checking (matching classic VM behavior)
_need_verify = Verifier::should_verify_for(class_loader());
@@ -2498,18 +2611,26 @@
"Invalid superclass index %u in class file %s",
super_class_index,
CHECK_(nullHandle));
} else {
check_property(valid_cp_range(super_class_index, cp_size) &&
- cp->tag_at(super_class_index).is_unresolved_klass(),
+ cp->tag_at(super_class_index).is_klass_reference(),
"Invalid superclass index %u in class file %s",
super_class_index,
CHECK_(nullHandle));
// The class name should be legal because it is checked when parsing constant pool.
// However, make sure it is not an array type.
+ bool is_array = false;
+ if (cp->tag_at(super_class_index).is_klass()) {
+ super_klass = instanceKlassHandle(THREAD, cp->resolved_klass_at(super_class_index));
+ if (_need_verify)
+ is_array = super_klass->oop_is_array();
+ } else if (_need_verify) {
+ is_array = (cp->unresolved_klass_at(super_class_index)->byte_at(0) == JVM_SIGNATURE_ARRAY);
+ }
if (_need_verify) {
- guarantee_property(cp->unresolved_klass_at(super_class_index)->byte_at(0) != JVM_SIGNATURE_ARRAY,
+ guarantee_property(!is_array,
"Bad superclass name in class file %s", CHECK_(nullHandle));
}
}
// Interfaces
@@ -2545,11 +2666,11 @@
objArrayHandle methods_annotations(THREAD, methods_annotations_oop);
objArrayHandle methods_parameter_annotations(THREAD, methods_parameter_annotations_oop);
objArrayHandle methods_default_annotations(THREAD, methods_default_annotations_oop);
// We check super class after class file is parsed and format is checked
- if (super_class_index > 0) {
+ if (super_class_index > 0 && super_klass.is_null()) {
symbolHandle sk (THREAD, cp->klass_name_at(super_class_index));
if (access_flags.is_interface()) {
// Before attempting to resolve the superclass, check for class format
// errors not checked yet.
guarantee_property(sk() == vmSymbols::java_lang_Object(),
@@ -2562,10 +2683,13 @@
protection_domain,
true,
CHECK_(nullHandle));
KlassHandle kh (THREAD, k);
super_klass = instanceKlassHandle(THREAD, kh());
+ cp->klass_at_put(super_class_index, super_klass()); // eagerly resolve
+ }
+ if (super_klass.not_null()) {
if (super_klass->is_interface()) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbolHandles::java_lang_IncompatibleClassChangeError(),
@@ -2971,10 +3095,11 @@
this_klass->set_has_final_method();
}
this_klass->set_method_ordering(method_ordering());
this_klass->set_initial_method_idnum(methods->length());
this_klass->set_name(cp->klass_name_at(this_class_index));
+ cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve
this_klass->set_protection_domain(protection_domain());
this_klass->set_fields_annotations(fields_annotations());
this_klass->set_methods_annotations(methods_annotations());
this_klass->set_methods_parameter_annotations(methods_parameter_annotations());
this_klass->set_methods_default_annotations(methods_default_annotations());