/* * Copyright (c) 1997, 2022, 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. *
*/ #include"precompiled.hpp" #include"classfile/classFileParser.hpp" #include"classfile/classFileStream.hpp" #include"classfile/classLoader.hpp" #include"classfile/classLoaderData.inline.hpp" #include"classfile/classLoadInfo.hpp" #include"classfile/defaultMethods.hpp" #include"classfile/fieldLayoutBuilder.hpp" #include"classfile/javaClasses.inline.hpp" #include"classfile/moduleEntry.hpp" #include"classfile/packageEntry.hpp" #include"classfile/symbolTable.hpp" #include"classfile/systemDictionary.hpp" #include"classfile/verificationType.hpp" #include"classfile/verifier.hpp" #include"classfile/vmClasses.hpp" #include"classfile/vmSymbols.hpp" #include"jvm.h" #include"logging/log.hpp" #include"logging/logStream.hpp" #include"memory/allocation.hpp" #include"memory/metadataFactory.hpp" #include"memory/oopFactory.hpp" #include"memory/resourceArea.hpp" #include"memory/universe.hpp" #include"oops/annotations.hpp" #include"oops/constantPool.inline.hpp" #include"oops/fieldStreams.inline.hpp" #include"oops/instanceKlass.inline.hpp" #include"oops/instanceMirrorKlass.hpp" #include"oops/klass.inline.hpp" #include"oops/klassVtable.hpp" #include"oops/metadata.hpp" #include"oops/method.inline.hpp" #include"oops/oop.inline.hpp" #include"oops/recordComponent.hpp" #include"oops/symbol.hpp" #include"prims/jvmtiExport.hpp" #include"prims/jvmtiThreadState.hpp" #include"runtime/arguments.hpp" #include"runtime/fieldDescriptor.inline.hpp" #include"runtime/handles.inline.hpp" #include"runtime/javaCalls.hpp" #include"runtime/os.hpp" #include"runtime/perfData.hpp" #include"runtime/reflection.hpp" #include"runtime/safepointVerifiers.hpp" #include"runtime/signature.hpp" #include"runtime/timer.hpp" #include"services/classLoadingService.hpp" #include"services/threadService.hpp" #include"utilities/align.hpp" #include"utilities/bitMap.inline.hpp" #include"utilities/copy.hpp" #include"utilities/formatBuffer.hpp" #include"utilities/exceptions.hpp" #include"utilities/globalDefinitions.hpp" #include"utilities/growableArray.hpp" #include"utilities/macros.hpp" #include"utilities/ostream.hpp" #include"utilities/resourceHash.hpp" #include"utilities/utf8.hpp" #if INCLUDE_CDS #include"classfile/systemDictionaryShared.hpp" #endif #if INCLUDE_JFR #include"jfr/support/jfrTraceIdExtension.hpp" #endif
// We generally try to create the oops directly when parsing, rather than // allocating temporary data structures and copying the bytes twice. A // temporary area is only needed when parsing utf8 entries in the constant // pool and when parsing line number tables.
// We add assert in debug mode when class format is not checked.
// Used for two backward compatibility reasons: // - to check for new additions to the class file format in JDK1.5 // - to check for bug fixes in the format checker in JDK1.5 #define JAVA_1_5_VERSION 49
// Used for backward compatibility reasons: // - to check for javac bug fixes that happened after 1.5 // - also used as the max version when running in jdk6 #define JAVA_6_VERSION 50
// Used for backward compatibility reasons: // - to disallow argument and require ACC_STATIC for <clinit> methods #define JAVA_7_VERSION 51
// Use a local copy of ClassFileStream. It helps the C++ compiler to optimize // this function (_current can be allocated in a register, with scalar // replacement of aggregates). The _current pointer is copied back to // stream() when this function returns. DON'T call another method within // this method that uses stream(). const ClassFileStream cfs1 = *stream; const ClassFileStream* const cfs = &cfs1;
// Used for batching symbol allocations. constchar* names[SymbolTable::symbol_alloc_batch_size]; int lengths[SymbolTable::symbol_alloc_batch_size]; int indices[SymbolTable::symbol_alloc_batch_size]; unsignedint hashValues[SymbolTable::symbol_alloc_batch_size]; int names_count = 0;
// parsing Index 0 is unused for (int index = 1; index < length; index++) { // Each of the following case guarantees one more byte in the stream // for the following tag or the access_flags following constant pool, // so we don't need bounds-check for reading tag. const u1 tag = cfs->get_u1_fast(); switch (tag) { case JVM_CONSTANT_Class : {
cfs->guarantee_more(3, CHECK); // name_index, tag/access_flags const u2 name_index = cfs->get_u2_fast();
cp->klass_index_at_put(index, name_index); break;
} case JVM_CONSTANT_Fieldref: {
cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags const u2 class_index = cfs->get_u2_fast(); const u2 name_and_type_index = cfs->get_u2_fast();
cp->field_at_put(index, class_index, name_and_type_index); break;
} case JVM_CONSTANT_Methodref: {
cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags const u2 class_index = cfs->get_u2_fast(); const u2 name_and_type_index = cfs->get_u2_fast();
cp->method_at_put(index, class_index, name_and_type_index); break;
} case JVM_CONSTANT_InterfaceMethodref: {
cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags const u2 class_index = cfs->get_u2_fast(); const u2 name_and_type_index = cfs->get_u2_fast();
cp->interface_method_at_put(index, class_index, name_and_type_index); break;
} case JVM_CONSTANT_String : {
cfs->guarantee_more(3, CHECK); // string_index, tag/access_flags const u2 string_index = cfs->get_u2_fast();
cp->string_index_at_put(index, string_index); break;
} case JVM_CONSTANT_MethodHandle : case JVM_CONSTANT_MethodType: { if (_major_version < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) {
classfile_parse_error( "Class file version does not support constant tag %u in class file %s",
tag, THREAD); return;
} if (tag == JVM_CONSTANT_MethodHandle) {
cfs->guarantee_more(4, CHECK); // ref_kind, method_index, tag/access_flags const u1 ref_kind = cfs->get_u1_fast(); const u2 method_index = cfs->get_u2_fast();
cp->method_handle_index_at_put(index, ref_kind, method_index);
} elseif (tag == JVM_CONSTANT_MethodType) {
cfs->guarantee_more(3, CHECK); // signature_index, tag/access_flags const u2 signature_index = cfs->get_u2_fast();
cp->method_type_index_at_put(index, signature_index);
} else {
ShouldNotReachHere();
} break;
} case JVM_CONSTANT_Dynamic : { if (_major_version < Verifier::DYNAMICCONSTANT_MAJOR_VERSION) {
classfile_parse_error( "Class file version does not support constant tag %u in class file %s",
tag, THREAD); return;
}
cfs->guarantee_more(5, CHECK); // bsm_index, nt, tag/access_flags const u2 bootstrap_specifier_index = cfs->get_u2_fast(); const u2 name_and_type_index = cfs->get_u2_fast(); if (_max_bootstrap_specifier_index < (int) bootstrap_specifier_index) {
_max_bootstrap_specifier_index = (int) bootstrap_specifier_index; // collect for later
}
cp->dynamic_constant_at_put(index, bootstrap_specifier_index, name_and_type_index); break;
} case JVM_CONSTANT_InvokeDynamic : { if (_major_version < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) {
classfile_parse_error( "Class file version does not support constant tag %u in class file %s",
tag, THREAD); return;
}
cfs->guarantee_more(5, CHECK); // bsm_index, nt, tag/access_flags const u2 bootstrap_specifier_index = cfs->get_u2_fast(); const u2 name_and_type_index = cfs->get_u2_fast(); 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: {
cfs->guarantee_more(5, CHECK); // bytes, tag/access_flags const u4 bytes = cfs->get_u4_fast();
cp->int_at_put(index, (jint)bytes); break;
} case JVM_CONSTANT_Float: {
cfs->guarantee_more(5, CHECK); // bytes, tag/access_flags const u4 bytes = cfs->get_u4_fast();
cp->float_at_put(index, *(jfloat*)&bytes); break;
} case JVM_CONSTANT_Long: { // A mangled type might cause you to overrun allocated memory
guarantee_property(index + 1 < length, "Invalid constant pool entry %u in class file %s",
index,
CHECK);
cfs->guarantee_more(9, CHECK); // bytes, tag/access_flags const u8 bytes = cfs->get_u8_fast();
cp->long_at_put(index, bytes);
index++; // Skip entry following eigth-byte constant, see JVM book p. 98 break;
} case JVM_CONSTANT_Double: { // A mangled type might cause you to overrun allocated memory
guarantee_property(index+1 < length, "Invalid constant pool entry %u in class file %s",
index,
CHECK);
cfs->guarantee_more(9, CHECK); // bytes, tag/access_flags const u8 bytes = cfs->get_u8_fast();
cp->double_at_put(index, *(jdouble*)&bytes);
index++; // Skip entry following eigth-byte constant, see JVM book p. 98 break;
} case JVM_CONSTANT_NameAndType: {
cfs->guarantee_more(5, CHECK); // name_index, signature_index, tag/access_flags const u2 name_index = cfs->get_u2_fast(); const u2 signature_index = cfs->get_u2_fast();
cp->name_and_type_at_put(index, name_index, signature_index); break;
} case JVM_CONSTANT_Utf8 : {
cfs->guarantee_more(2, CHECK); // utf8_length
u2 utf8_length = cfs->get_u2_fast(); const u1* utf8_buffer = cfs->current();
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(utf8_buffer, utf8_length, CHECK);
}
unsignedint hash;
Symbol* const result = SymbolTable::lookup_only((constchar*)utf8_buffer,
utf8_length,
hash); if (result == NULL) {
names[names_count] = (constchar*)utf8_buffer;
lengths[names_count] = utf8_length;
indices[names_count] = index;
hashValues[names_count++] = hash; if (names_count == SymbolTable::symbol_alloc_batch_size) {
SymbolTable::new_symbols(_loader_data,
constantPoolHandle(THREAD, cp),
names_count,
names,
lengths,
indices,
hashValues);
names_count = 0;
}
} else {
cp->symbol_at_put(index, result);
} break;
} case JVM_CONSTANT_Module: case JVM_CONSTANT_Package: { // Record that an error occurred in these two cases but keep parsing so // that ACC_Module can be checked for in the access_flags. Need to // throw NoClassDefFoundError in that case. if (_major_version >= JAVA_9_VERSION) {
cfs->guarantee_more(3, CHECK);
cfs->get_u2_fast();
set_class_bad_constant_seen(tag); break;
}
} default: {
classfile_parse_error("Unknown constant tag %u in class file %s",
tag,
THREAD); return;
}
} // end of switch(tag)
} // end of for
// Allocate the remaining symbols if (names_count > 0) {
SymbolTable::new_symbols(_loader_data,
constantPoolHandle(THREAD, cp),
names_count,
names,
lengths,
indices,
hashValues);
}
// Copy _current pointer of local copy back to stream.
assert(stream->current() == old_current, "non-exclusive use of stream");
stream->set_current(cfs1.current());
}
staticinlinebool valid_cp_range(int index, int length) { return (index > 0 && index < length);
}
// parsing constant pool entries
parse_constant_pool_entries(stream, cp, length, CHECK); if (class_bad_constant_seen() != 0) { // a bad CP entry has been detected previously so stop parsing and just return. return;
}
int index = 1; // declared outside of loops for portability int num_klasses = 0;
// first verification pass - validate cross references // and fixup class and string constants for (index = 1; index < length; index++) { // Index 0 is unused const jbyte tag = cp->tag_at(index).value(); switch (tag) { case JVM_CONSTANT_Class: {
ShouldNotReachHere(); // Only JVM_CONSTANT_ClassIndex should be present break;
} case JVM_CONSTANT_Fieldref: // fall through case JVM_CONSTANT_Methodref: // fall through case JVM_CONSTANT_InterfaceMethodref: { if (!_need_verify) break; constint klass_ref_index = cp->klass_ref_index_at(index); constint name_and_type_ref_index = cp->name_and_type_ref_index_at(index);
check_property(valid_klass_reference_at(klass_ref_index), "Invalid constant pool index %u in class file %s",
klass_ref_index, CHECK);
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); break;
} case JVM_CONSTANT_String: {
ShouldNotReachHere(); // Only JVM_CONSTANT_StringIndex should be present break;
} case JVM_CONSTANT_Integer: break; case JVM_CONSTANT_Float: break; case JVM_CONSTANT_Long: case JVM_CONSTANT_Double: {
index++;
check_property(
(index < length && cp->tag_at(index).is_invalid()), "Improper constant pool long/double index %u in class file %s",
index, CHECK); break;
} case JVM_CONSTANT_NameAndType: { if (!_need_verify) break; constint name_ref_index = cp->name_ref_index_at(index); constint signature_ref_index = cp->signature_ref_index_at(index);
check_property(valid_symbol_at(name_ref_index), "Invalid constant pool index %u in class file %s",
name_ref_index, CHECK);
check_property(valid_symbol_at(signature_ref_index), "Invalid constant pool index %u in class file %s",
signature_ref_index, CHECK); break;
} case JVM_CONSTANT_Utf8: break; case JVM_CONSTANT_UnresolvedClass: // fall-through case JVM_CONSTANT_UnresolvedClassInError: {
ShouldNotReachHere(); // Only JVM_CONSTANT_ClassIndex should be present break;
} case JVM_CONSTANT_ClassIndex: { constint class_index = cp->klass_index_at(index);
check_property(valid_symbol_at(class_index), "Invalid constant pool index %u in class file %s",
class_index, CHECK);
cp->unresolved_klass_at_put(index, class_index, num_klasses++); break;
} case JVM_CONSTANT_StringIndex: { constint string_index = cp->string_index_at(index);
check_property(valid_symbol_at(string_index), "Invalid constant pool index %u in class file %s",
string_index, CHECK);
Symbol* const sym = cp->symbol_at(string_index);
cp->unresolved_string_at_put(index, sym); break;
} case JVM_CONSTANT_MethodHandle: { constint ref_index = cp->method_handle_index_at(index);
check_property(valid_cp_range(ref_index, length), "Invalid constant pool index %u in class file %s",
ref_index, CHECK); const constantTag tag = cp->tag_at(ref_index); constint ref_kind = cp->method_handle_ref_kind_at(index);
switch (ref_kind) { case JVM_REF_getField: case JVM_REF_getStatic: case JVM_REF_putField: case JVM_REF_putStatic: {
check_property(
tag.is_field(), "Invalid constant pool index %u in class file %s (not a field)",
ref_index, CHECK); break;
} case JVM_REF_invokeVirtual: case JVM_REF_newInvokeSpecial: {
check_property(
tag.is_method(), "Invalid constant pool index %u in class file %s (not a method)",
ref_index, CHECK); break;
} case JVM_REF_invokeStatic: case JVM_REF_invokeSpecial: {
check_property(
tag.is_method() ||
((_major_version >= JAVA_8_VERSION) && tag.is_interface_method()), "Invalid constant pool index %u in class file %s (not a method)",
ref_index, CHECK); break;
} case JVM_REF_invokeInterface: {
check_property(
tag.is_interface_method(), "Invalid constant pool index %u in class file %s (not an interface method)",
ref_index, CHECK); break;
} default: {
classfile_parse_error( "Bad method handle kind at constant pool index %u in class file %s",
index, THREAD); return;
}
} // switch(refkind) // Keep the ref_index unchanged. It will be indirected at link-time. break;
} // case MethodHandle case JVM_CONSTANT_MethodType: { constint ref_index = cp->method_type_index_at(index);
check_property(valid_symbol_at(ref_index), "Invalid constant pool index %u in class file %s",
ref_index, CHECK); break;
} case JVM_CONSTANT_Dynamic: { constint name_and_type_ref_index =
cp->bootstrap_name_and_type_ref_index_at(index);
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); // bootstrap specifier index must be checked later, // when BootstrapMethods attr is available
// Mark the constant pool as having a CONSTANT_Dynamic_info structure
cp->set_has_dynamic_constant(); break;
} case JVM_CONSTANT_InvokeDynamic: { constint name_and_type_ref_index =
cp->bootstrap_name_and_type_ref_index_at(index);
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); // bootstrap specifier index must be checked later, // when BootstrapMethods attr is available break;
} default: {
fatal("bad constant pool tag value %u", cp->tag_at(index).value());
ShouldNotReachHere(); break;
}
} // switch(tag)
} // end of for
// second verification pass - checks the strings are of the right format. // but not yet to the other entries for (index = 1; index < length; index++) { const jbyte tag = cp->tag_at(index).value(); switch (tag) { case JVM_CONSTANT_UnresolvedClass: { const Symbol* const class_name = cp->klass_name_at(index); // check the name
verify_legal_class_name(class_name, CHECK); break;
} case JVM_CONSTANT_NameAndType: { if (_need_verify) { constint sig_index = cp->signature_ref_index_at(index); constint name_index = cp->name_ref_index_at(index); const Symbol* const name = cp->symbol_at(name_index); const Symbol* const sig = cp->symbol_at(sig_index);
guarantee_property(sig->utf8_length() != 0, "Illegal zero length constant pool entry at %d in class %s",
sig_index, CHECK);
guarantee_property(name->utf8_length() != 0, "Illegal zero length constant pool entry at %d in class %s",
name_index, CHECK);
if (Signature::is_method(sig)) { // Format check method name and signature
verify_legal_method_name(name, CHECK);
verify_legal_method_signature(name, sig, CHECK);
} else { // Format check field name and signature
verify_legal_field_name(name, CHECK);
verify_legal_field_signature(name, sig, CHECK);
}
} break;
} case JVM_CONSTANT_Dynamic: { constint name_and_type_ref_index =
cp->name_and_type_ref_index_at(index); // already verified to be utf8 constint name_ref_index =
cp->name_ref_index_at(name_and_type_ref_index); // already verified to be utf8 constint signature_ref_index =
cp->signature_ref_index_at(name_and_type_ref_index); const Symbol* const name = cp->symbol_at(name_ref_index); const Symbol* const signature = cp->symbol_at(signature_ref_index); if (_need_verify) { // CONSTANT_Dynamic's name and signature are verified above, when iterating NameAndType_info. // Need only to be sure signature is the right type. if (Signature::is_method(signature)) {
throwIllegalSignature("CONSTANT_Dynamic", name, signature, CHECK);
}
} break;
} case JVM_CONSTANT_InvokeDynamic: case JVM_CONSTANT_Fieldref: case JVM_CONSTANT_Methodref: case JVM_CONSTANT_InterfaceMethodref: { constint name_and_type_ref_index =
cp->name_and_type_ref_index_at(index); // already verified to be utf8 constint name_ref_index =
cp->name_ref_index_at(name_and_type_ref_index); // already verified to be utf8 constint signature_ref_index =
cp->signature_ref_index_at(name_and_type_ref_index); const Symbol* const name = cp->symbol_at(name_ref_index); const Symbol* const signature = cp->symbol_at(signature_ref_index); if (tag == JVM_CONSTANT_Fieldref) { if (_need_verify) { // Field name and signature are verified above, when iterating NameAndType_info. // Need only to be sure signature is non-zero length and the right type. if (Signature::is_method(signature)) {
throwIllegalSignature("Field", name, signature, CHECK);
}
}
} else { if (_need_verify) { // Method name and signature are individually verified above, when iterating // NameAndType_info. Need to check here that signature is non-zero length and // the right type. if (!Signature::is_method(signature)) {
throwIllegalSignature("Method", name, signature, CHECK);
}
} // If a class method name begins with '<', it must be "<init>" and have void signature. constunsignedint name_len = name->utf8_length(); if (tag == JVM_CONSTANT_Methodref && name_len != 0 &&
name->char_at(0) == JVM_SIGNATURE_SPECIAL) { if (name != vmSymbols::object_initializer_name()) {
classfile_parse_error( "Bad method name at constant pool index %u in class file %s",
name_ref_index, THREAD); return;
} elseif (!Signature::is_void_method(signature)) { // must have void signature.
throwIllegalSignature("Method", name, signature, CHECK);
}
}
} break;
} case JVM_CONSTANT_MethodHandle: { constint ref_index = cp->method_handle_index_at(index); constint ref_kind = cp->method_handle_ref_kind_at(index); switch (ref_kind) { case JVM_REF_invokeVirtual: case JVM_REF_invokeStatic: case JVM_REF_invokeSpecial: case JVM_REF_newInvokeSpecial: { constint name_and_type_ref_index =
cp->name_and_type_ref_index_at(ref_index); constint name_ref_index =
cp->name_ref_index_at(name_and_type_ref_index); const Symbol* const name = cp->symbol_at(name_ref_index); if (ref_kind == JVM_REF_newInvokeSpecial) { if (name != vmSymbols::object_initializer_name()) {
classfile_parse_error( "Bad constructor name at constant pool index %u in class file %s",
name_ref_index, THREAD); return;
}
} else { if (name == vmSymbols::object_initializer_name()) {
classfile_parse_error( "Bad method name at constant pool index %u in class file %s",
name_ref_index, THREAD); return;
}
} break;
} // Other ref_kinds are already fully checked in previous pass.
} // switch(ref_kind) break;
} case JVM_CONSTANT_MethodType: { const Symbol* const no_name = vmSymbols::type_name(); // place holder const Symbol* const signature = cp->method_type_signature_at(index);
verify_legal_method_signature(no_name, signature, CHECK); break;
} case JVM_CONSTANT_Utf8: {
assert(cp->symbol_at(index)->refcount() != 0, "count corrupted");
}
} // switch(tag)
} // end of for
}
class NameSigHash: public ResourceObj { public: const Symbol* _name; // name const Symbol* _sig; // signature
NameSigHash* _next; // Next entry in hash table
};
staticvoid initialize_hashtable(NameSigHash** table) {
memset((void*)table, 0, sizeof(NameSigHash*) * HASH_ROW_SIZE);
} // Return false if the name/sig combination is found in table. // Return true if no duplicate is found. And name/sig is added as a new entry in table. // The old format checker uses heap sort to find duplicates. // NOTE: caller should guarantee that GC doesn't happen during the life cycle // of table since we don't expect Symbol*'s to move. staticbool put_after_lookup(const Symbol* name, const Symbol* sig, NameSigHash** table) {
assert(name != NULL, "name in constant pool is NULL");
// First lookup for duplicates int index = hash(name, sig);
NameSigHash* entry = table[index]; while (entry != NULL) { if (entry->_name == name && entry->_sig == sig) { returnfalse;
}
entry = entry->_next;
}
// No duplicate is found, allocate a new entry and fill it.
entry = new NameSigHash();
entry->_name = name;
entry->_sig = sig;
if (itfs_len == 0) {
_local_interfaces = Universe::the_empty_instance_klass_array();
} else {
assert(itfs_len > 0, "only called for len>0");
_local_interfaces = MetadataFactory::new_array<InstanceKlass*>(_loader_data, itfs_len, NULL, CHECK);
int index; for (index = 0; index < itfs_len; index++) { const u2 interface_index = stream->get_u2(CHECK);
Klass* interf;
check_property(
valid_klass_reference_at(interface_index), "Interface name has bad constant pool index %u in class file %s",
interface_index, CHECK); if (cp->tag_at(interface_index).is_klass()) {
interf = cp->resolved_klass_at(interface_index);
} else {
Symbol* const unresolved_klass = 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->char_at(0) != JVM_SIGNATURE_ARRAY, "Bad interface name in class file %s", CHECK);
// Call resolve_super so class circularity is checked
interf = SystemDictionary::resolve_super_or_fail(
_class_name,
unresolved_klass,
Handle(THREAD, _loader_data->class_loader()),
_protection_domain, false,
CHECK);
}
if (!interf->is_interface()) {
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(),
err_msg("class %s can not implement %s, because it is not an interface (%s)",
_class_name->as_klass_external_name(),
interf->external_name(),
interf->class_in_module_of_loader()));
}
if (InstanceKlass::cast(interf)->has_nonstatic_concrete_methods()) {
*has_nonstatic_concrete_methods = true;
}
_local_interfaces->at_put(index, InstanceKlass::cast(interf));
}
if (!_need_verify || itfs_len <= 1) { return;
}
// Check if there's any duplicates in interfaces
ResourceMark rm(THREAD);
NameSigHash** interface_names = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD,
NameSigHash*,
HASH_ROW_SIZE);
initialize_hashtable(interface_names); bool dup = false; const Symbol* name = NULL;
{
debug_only(NoSafepointVerifier nsv;) for (index = 0; index < itfs_len; index++) { const InstanceKlass* const k = _local_interfaces->at(index);
name = k->name(); // If no duplicates, add (name, NULL) in hashtable interface_names. if (!put_after_lookup(name, NULL, interface_names)) {
dup = true; break;
}
}
} if (dup) {
classfile_parse_error("Duplicate interface name \"%s\" in class file %s",
name->as_C_string(), THREAD);
}
}
}
void ClassFileParser::verify_constantvalue(const ConstantPool* const cp, int constantvalue_index, int signature_index,
TRAPS) const { // Make sure the constant pool entry is of a type appropriate to this field
guarantee_property(
(constantvalue_index > 0 &&
constantvalue_index < cp->length()), "Bad initial value index %u in ConstantValue attribute in class file %s",
constantvalue_index, CHECK);
const constantTag value_type = cp->tag_at(constantvalue_index); switch(cp->basic_type_for_signature_at(signature_index)) { case T_LONG: {
guarantee_property(value_type.is_long(), "Inconsistent constant value type in class file %s",
CHECK); break;
} case T_FLOAT: {
guarantee_property(value_type.is_float(), "Inconsistent constant value type in class file %s",
CHECK); break;
} case T_DOUBLE: {
guarantee_property(value_type.is_double(), "Inconsistent constant value type in class file %s",
CHECK); break;
} case T_BYTE: case T_CHAR: case T_SHORT: case T_BOOLEAN: case T_INT: {
guarantee_property(value_type.is_int(), "Inconsistent constant value type in class file %s",
CHECK); break;
} case T_OBJECT: {
guarantee_property((cp->symbol_at(signature_index)->equals("Ljava/lang/String;")
&& value_type.is_string()), "Bad string initial value in class file %s",
CHECK); break;
} default: {
classfile_parse_error("Unable to set initial value %u in class file %s",
constantvalue_index,
THREAD);
}
}
}
class AnnotationCollector : public ResourceObj{ public: enum Location { _in_field, _in_method, _in_class }; enum ID {
_unknown = 0,
_method_CallerSensitive,
_method_ForceInline,
_method_DontInline,
_method_ChangesCurrentThread,
_method_JvmtiMountTransition,
_method_InjectedProfile,
_method_LambdaForm_Compiled,
_method_Hidden,
_method_Scoped,
_method_IntrinsicCandidate,
_jdk_internal_vm_annotation_Contended,
_field_Stable,
_jdk_internal_vm_annotation_ReservedStackAccess,
_jdk_internal_ValueBased,
_annotation_LIMIT
}; const Location _location; int _annotations_present;
u2 _contended_group;
AnnotationCollector(Location location)
: _location(location), _annotations_present(0), _contended_group(0)
{
assert((int)_annotation_LIMIT <= (int)sizeof(_annotations_present) * BitsPerByte, "");
} // If this annotation name has an ID, report it (or _none).
ID annotation_index(const ClassLoaderData* loader_data, const Symbol* name, bool can_access_vm_annotations); // Set the annotation name: void set_annotation(ID id) {
assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
_annotations_present |= nth_bit((int)id);
}
// Safely increment index by val if does not pass limit #define SAFE_ADD(index, limit, val) \ if (index >= limit - val) return limit; \
index += val;
// Skip an annotation. Return >=limit if there is any problem. staticint skip_annotation(const u1* buffer, int limit, int index) {
assert(buffer != NULL, "invariant"); // annotation := atype:u2 do(nmem:u2) {member:u2 value} // value := switch (tag:u1) { ... }
SAFE_ADD(index, limit, 4); // skip atype and read nmem int nmem = Bytes::get_Java_u2((address)buffer + index - 2); while (--nmem >= 0 && index < limit) {
SAFE_ADD(index, limit, 2); // skip member
index = skip_annotation_value(buffer, limit, index);
} return index;
}
// Skip an annotation value. Return >=limit if there is any problem. staticint skip_annotation_value(const u1* buffer, int limit, int index) {
assert(buffer != NULL, "invariant");
// value := switch (tag:u1) { // case B, C, I, S, Z, D, F, J, c: con:u2; // case e: e_class:u2 e_name:u2; // case s: s_con:u2; // case [: do(nval:u2) {value}; // case @: annotation; // case s: s_con:u2; // }
SAFE_ADD(index, limit, 1); // read tag const u1 tag = buffer[index - 1]; switch (tag) { case'B': case'C': case'I': case'S': case'Z': case'D': case'F': case'J': case'c': case's':
SAFE_ADD(index, limit, 2); // skip con or s_con break; case'e':
SAFE_ADD(index, limit, 4); // skip e_class, e_name break; case'[':
{
SAFE_ADD(index, limit, 2); // read nval int nval = Bytes::get_Java_u2((address)buffer + index - 2); while (--nval >= 0 && index < limit) {
index = skip_annotation_value(buffer, limit, index);
}
} break; case'@':
index = skip_annotation(buffer, limit, index); break; default: return limit; // bad tag byte
} return index;
}
// Sift through annotations, looking for those significant to the VM: staticvoid parse_annotations(const ConstantPool* const cp, const u1* buffer, int limit,
AnnotationCollector* coll,
ClassLoaderData* loader_data, constbool can_access_vm_annotations) {
// annotations := do(nann:u2) {annotation} int index = 2; // read nann if (index >= limit) return; int nann = Bytes::get_Java_u2((address)buffer + index - 2); enum { // initial annotation layout
atype_off = 0, // utf8 such as 'Ljava/lang/annotation/Retention;'
count_off = 2, // u2 such as 1 (one value)
member_off = 4, // utf8 such as 'value'
tag_off = 6, // u1 such as 'c' (type) or 'e' (enum)
e_tag_val = 'e',
e_type_off = 7, // utf8 such as 'Ljava/lang/annotation/RetentionPolicy;'
e_con_off = 9, // utf8 payload, such as 'SOURCE', 'CLASS', 'RUNTIME'
e_size = 11, // end of 'e' annotation
c_tag_val = 'c', // payload is type
c_con_off = 7, // utf8 payload, such as 'I'
c_size = 9, // end of 'c' annotation
s_tag_val = 's', // payload is String
s_con_off = 7, // utf8 payload, such as 'Ljava/lang/String;'
s_size = 9,
min_size = 6 // smallest possible size (zero members)
}; // Cannot add min_size to index in case of overflow MAX_INT while ((--nann) >= 0 && (index - 2 <= limit - min_size)) { int index0 = index;
index = skip_annotation(buffer, limit, index); const u1* const abase = buffer + index0; constint atype = Bytes::get_Java_u2((address)abase + atype_off); constint count = Bytes::get_Java_u2((address)abase + count_off); const Symbol* const aname = check_symbol_at(cp, atype); if (aname == NULL) break; // invalid annotation name const Symbol* member = NULL; if (count >= 1) { constint member_index = Bytes::get_Java_u2((address)abase + member_off);
member = check_symbol_at(cp, member_index); if (member == NULL) break; // invalid member name
}
// Here is where parsing particular annotations will take place.
AnnotationCollector::ID id = coll->annotation_index(loader_data, aname, can_access_vm_annotations); if (AnnotationCollector::_unknown == id) continue;
coll->set_annotation(id);
if (AnnotationCollector::_jdk_internal_vm_annotation_Contended == id) { // @Contended can optionally specify the contention group. // // Contended group defines the equivalence class over the fields: // the fields within the same contended group are not treated distinct. // The only exception is default group, which does not incur the // equivalence. Naturally, contention group for classes is meaningless. // // While the contention group is specified as String, annotation // values are already interned, and we might as well use the constant // pool index as the group tag. //
u2 group_index = 0; // default contended group if (count == 1
&& s_size == (index - index0) // match size
&& s_tag_val == *(abase + tag_off)
&& member == vmSymbols::value_name()) {
group_index = Bytes::get_Java_u2((address)abase + s_con_off); if (cp->symbol_at(group_index)->utf8_length() == 0) {
group_index = 0; // default contended group
}
}
coll->set_contended_group(group_index);
}
}
}
// Parse attributes for a field. void ClassFileParser::parse_field_attributes(const ClassFileStream* const cfs,
u2 attributes_count, bool is_static, u2 signature_index,
u2* const constantvalue_index_addr, bool* const is_synthetic_addr,
u2* const generic_signature_index_addr,
ClassFileParser::FieldAnnotationCollector* parsed_annotations,
TRAPS) {
assert(cfs != NULL, "invariant");
assert(constantvalue_index_addr != NULL, "invariant");
assert(is_synthetic_addr != NULL, "invariant");
assert(generic_signature_index_addr != NULL, "invariant");
assert(parsed_annotations != NULL, "invariant");
assert(attributes_count > 0, "attributes_count should be greater than 0");
while (attributes_count--) {
cfs->guarantee_more(6, CHECK); // attribute_name_index, attribute_length const u2 attribute_name_index = cfs->get_u2_fast(); const u4 attribute_length = cfs->get_u4_fast();
check_property(valid_symbol_at(attribute_name_index), "Invalid field attribute index %u in class file %s",
attribute_name_index,
CHECK);
const Symbol* const attribute_name = cp->symbol_at(attribute_name_index); if (is_static && attribute_name == vmSymbols::tag_constant_value()) { // ignore if non-static if (constantvalue_index != 0) {
classfile_parse_error("Duplicate ConstantValue attribute in class file %s", THREAD); return;
}
check_property(
attribute_length == 2, "Invalid ConstantValue field attribute length %u in class file %s",
attribute_length, CHECK);
constantvalue_index = cfs->get_u2(CHECK); if (_need_verify) {
verify_constantvalue(cp, constantvalue_index, signature_index, CHECK);
}
} elseif (attribute_name == vmSymbols::tag_synthetic()) { if (attribute_length != 0) {
classfile_parse_error( "Invalid Synthetic field attribute length %u in class file %s",
attribute_length, THREAD); return;
}
is_synthetic = true;
} elseif (attribute_name == vmSymbols::tag_deprecated()) { // 4276120 if (attribute_length != 0) {
classfile_parse_error( "Invalid Deprecated field attribute length %u in class file %s",
attribute_length, THREAD); return;
}
} elseif (_major_version >= JAVA_1_5_VERSION) { if (attribute_name == vmSymbols::tag_signature()) { if (generic_signature_index != 0) {
classfile_parse_error( "Multiple Signature attributes for field in class file %s", THREAD); return;
} if (attribute_length != 2) {
classfile_parse_error( "Wrong size %u for field's Signature attribute in class file %s",
attribute_length, THREAD); return;
}
generic_signature_index = parse_generic_signature_attribute(cfs, CHECK);
} elseif (attribute_name == vmSymbols::tag_runtime_visible_annotations()) { if (runtime_visible_annotations != NULL) {
classfile_parse_error( "Multiple RuntimeVisibleAnnotations attributes for field in class file %s", THREAD); return;
}
runtime_visible_annotations_length = attribute_length;
runtime_visible_annotations = cfs->current();
assert(runtime_visible_annotations != NULL, "null visible annotations");
cfs->guarantee_more(runtime_visible_annotations_length, CHECK);
parse_annotations(cp,
runtime_visible_annotations,
runtime_visible_annotations_length,
parsed_annotations,
_loader_data,
_can_access_vm_annotations);
cfs->skip_u1_fast(runtime_visible_annotations_length);
} elseif (attribute_name == vmSymbols::tag_runtime_invisible_annotations()) { if (runtime_invisible_annotations_exists) {
classfile_parse_error( "Multiple RuntimeInvisibleAnnotations attributes for field in class file %s", THREAD); return;
}
runtime_invisible_annotations_exists = true; if (PreserveAllAnnotations) {
runtime_invisible_annotations_length = attribute_length;
runtime_invisible_annotations = cfs->current();
assert(runtime_invisible_annotations != NULL, "null invisible annotations");
}
cfs->skip_u1(attribute_length, CHECK);
} elseif (attribute_name == vmSymbols::tag_runtime_visible_type_annotations()) { if (runtime_visible_type_annotations != NULL) {
classfile_parse_error( "Multiple RuntimeVisibleTypeAnnotations attributes for field in class file %s", THREAD); return;
}
runtime_visible_type_annotations_length = attribute_length;
runtime_visible_type_annotations = cfs->current();
assert(runtime_visible_type_annotations != NULL, "null visible type annotations");
cfs->skip_u1(runtime_visible_type_annotations_length, CHECK);
} elseif (attribute_name == vmSymbols::tag_runtime_invisible_type_annotations()) { if (runtime_invisible_type_annotations_exists) {
classfile_parse_error( "Multiple RuntimeInvisibleTypeAnnotations attributes for field in class file %s", THREAD); return;
} else {
runtime_invisible_type_annotations_exists = true;
} if (PreserveAllAnnotations) {
runtime_invisible_type_annotations_length = attribute_length;
runtime_invisible_type_annotations = cfs->current();
assert(runtime_invisible_type_annotations != NULL, "null invisible type annotations");
}
cfs->skip_u1(attribute_length, CHECK);
} else {
cfs->skip_u1(attribute_length, CHECK); // Skip unknown attributes
}
} else {
cfs->skip_u1(attribute_length, CHECK); // Skip unknown attributes
}
}
// The field array starts with tuples of shorts // [access, name index, sig index, initial value index, byte offset]. // A generic signature slot only exists for field with generic // signature attribute. And the access flag is set with // JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE for that field. The generic // signature slots are at the end of the field array and after all // other fields data. // // f1: [access, name index, sig index, initial value index, low_offset, high_offset] // f2: [access, name index, sig index, initial value index, low_offset, high_offset] // ... // fn: [access, name index, sig index, initial value index, low_offset, high_offset] // [generic signature index] // [generic signature index] // ... // // Allocate a temporary resource array for field data. For each field, // a slot is reserved in the temporary array for the generic signature // index. After parsing all fields, the data are copied to a permanent // array and any unused slots will be discarded.
ResourceMark rm(THREAD);
u2* const fa = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD,
u2,
total_fields * (FieldInfo::field_slots + 1));
// The generic signature slots start after all other fields' data. int generic_signature_slot = total_fields * FieldInfo::field_slots; int num_generic_signature = 0; for (int n = 0; n < length; n++) { // access_flags, name_index, descriptor_index, attributes_count
cfs->guarantee_more(8, CHECK);
const u2 name_index = cfs->get_u2_fast();
check_property(valid_symbol_at(name_index), "Invalid constant pool index %u for field name in class file %s",
name_index, CHECK); const Symbol* const name = cp->symbol_at(name_index);
verify_legal_field_name(name, CHECK);
const u2 signature_index = cfs->get_u2_fast();
check_property(valid_symbol_at(signature_index), "Invalid constant pool index %u for field signature in class file %s",
signature_index, CHECK); const Symbol* const sig = cp->symbol_at(signature_index);
verify_legal_field_signature(name, sig, CHECK);
u2 constantvalue_index = 0; bool is_synthetic = false;
u2 generic_signature_index = 0; constbool is_static = access_flags.is_static();
FieldAnnotationCollector parsed_annotations(_loader_data);
const u2 attributes_count = cfs->get_u2_fast(); if (attributes_count > 0) {
parse_field_attributes(cfs,
attributes_count,
is_static,
signature_index,
&constantvalue_index,
&is_synthetic,
&generic_signature_index,
&parsed_annotations,
CHECK);
if (is_synthetic) {
access_flags.set_is_synthetic();
} if (generic_signature_index != 0) {
access_flags.set_field_has_generic_signature();
fa[generic_signature_slot] = generic_signature_index;
generic_signature_slot ++;
num_generic_signature ++;
}
}
FieldInfo* const field = FieldInfo::from_field_array(fa, n);
field->initialize(access_flags.as_short(),
name_index,
signature_index,
constantvalue_index); const BasicType type = cp->basic_type_for_signature_at(signature_index);
// Update FieldAllocationCount for this kind of field
fac->update(is_static, type);
// After field is initialized with type, we can augment it with aux info if (parsed_annotations.has_any_annotations()) {
parsed_annotations.apply_to(field); if (field->is_contended()) {
_has_contended_fields = true;
}
}
}
int index = length; if (num_injected != 0) { for (int n = 0; n < num_injected; n++) { // Check for duplicates if (injected[n].may_be_java) { const Symbol* const name = injected[n].name(); const Symbol* const signature = injected[n].signature(); bool duplicate = false; for (int i = 0; i < length; i++) { const FieldInfo* const f = FieldInfo::from_field_array(fa, i); if (name == cp->symbol_at(f->name_index()) &&
signature == cp->symbol_at(f->signature_index())) { // Symbol is desclared in Java so skip this one
duplicate = true; break;
}
} if (duplicate) { // These will be removed from the field array at the end continue;
}
}
// Injected field
FieldInfo* const field = FieldInfo::from_field_array(fa, index);
field->initialize((u2)JVM_ACC_FIELD_INTERNAL,
(u2)(injected[n].name_index),
(u2)(injected[n].signature_index),
0);
const BasicType type = Signature::basic_type(injected[n].signature());
--> --------------------
--> maximum size reached
--> --------------------
¤ Dauer der Verarbeitung: 0.36 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.