Mercurial > hg > graal-jvmci-8
view src/share/vm/classfile/classFileParser.cpp @ 6972:bd7a7ce2e264
6830717: replay of compilations would help with debugging
Summary: When java process crashed in compiler thread, repeat the compilation process will help finding root cause. This is done with using SA dump application class data and replay data from core dump, then use debug version of jvm to recompile the problematic java method.
Reviewed-by: kvn, twisti, sspitsyn
Contributed-by: yumin.qi@oracle.com
author | minqi |
---|---|
date | Mon, 12 Nov 2012 14:03:53 -0800 |
parents | 18fb7da42534 |
children | 070d523b96a7 |
line wrap: on
line source
/* * Copyright (c) 1997, 2012, 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/classLoader.hpp" #include "classfile/classLoaderData.hpp" #include "classfile/classLoaderData.inline.hpp" #include "classfile/defaultMethods.hpp" #include "classfile/genericSignatures.hpp" #include "classfile/javaClasses.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/verificationType.hpp" #include "classfile/verifier.hpp" #include "classfile/vmSymbols.hpp" #include "memory/allocation.hpp" #include "memory/gcLocker.hpp" #include "memory/metadataFactory.hpp" #include "memory/oopFactory.hpp" #include "memory/universe.inline.hpp" #include "oops/constantPool.hpp" #include "oops/fieldStreams.hpp" #include "oops/instanceKlass.hpp" #include "oops/instanceMirrorKlass.hpp" #include "oops/klass.inline.hpp" #include "oops/klassVtable.hpp" #include "oops/method.hpp" #include "oops/symbol.hpp" #include "prims/jvm.h" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiThreadState.hpp" #include "runtime/javaCalls.hpp" #include "runtime/perfData.hpp" #include "runtime/reflection.hpp" #include "runtime/signature.hpp" #include "runtime/timer.hpp" #include "services/classLoadingService.hpp" #include "services/threadService.hpp" #include "utilities/array.hpp" // 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. #define JAVA_CLASSFILE_MAGIC 0xCAFEBABE #define JAVA_MIN_SUPPORTED_VERSION 45 #define JAVA_MAX_SUPPORTED_VERSION 52 #define JAVA_MAX_SUPPORTED_MINOR_VERSION 0 // 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 check NameAndType_info signatures more aggressively #define JAVA_7_VERSION 51 // Extension method support. #define JAVA_8_VERSION 52 void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, constantPoolHandle cp, int length, TRAPS) { // 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(). ClassFileStream* cfs0 = stream(); ClassFileStream cfs1 = *cfs0; ClassFileStream* cfs = &cfs1; #ifdef ASSERT assert(cfs->allocated_on_stack(),"should be local"); u1* old_current = cfs0->current(); #endif Handle class_loader(THREAD, loader_data->class_loader()); // Used for batching symbol allocations. const char* names[SymbolTable::symbol_alloc_batch_size]; int lengths[SymbolTable::symbol_alloc_batch_size]; int indices[SymbolTable::symbol_alloc_batch_size]; unsigned int 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. u1 tag = cfs->get_u1_fast(); switch (tag) { case JVM_CONSTANT_Class : { cfs->guarantee_more(3, CHECK); // name_index, tag/access_flags 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 u2 class_index = cfs->get_u2_fast(); 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 u2 class_index = cfs->get_u2_fast(); 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 u2 class_index = cfs->get_u2_fast(); 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 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, CHECK); } if (!EnableInvokeDynamic) { classfile_parse_error( "This JVM does not support constant tag %u in class file %s", tag, CHECK); } if (tag == JVM_CONSTANT_MethodHandle) { cfs->guarantee_more(4, CHECK); // ref_kind, method_index, tag/access_flags u1 ref_kind = cfs->get_u1_fast(); u2 method_index = cfs->get_u2_fast(); cp->method_handle_index_at_put(index, ref_kind, method_index); } else if (tag == JVM_CONSTANT_MethodType) { cfs->guarantee_more(3, CHECK); // signature_index, tag/access_flags u2 signature_index = cfs->get_u2_fast(); cp->method_type_index_at_put(index, signature_index); } else { ShouldNotReachHere(); } 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, CHECK); } if (!EnableInvokeDynamic) { classfile_parse_error( "This JVM does not support constant tag %u in class file %s", tag, CHECK); } 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 (_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 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 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 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 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 u2 name_index = cfs->get_u2_fast(); 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(); 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 (EnableInvokeDynamic && 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 = (int) strlen(str); } unsigned int hash; Symbol* result = SymbolTable::lookup_only((char*)utf8_buffer, utf8_length, hash); if (result == NULL) { names[names_count] = (char*)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, cp, names_count, names, lengths, indices, hashValues, CHECK); names_count = 0; } } else { cp->symbol_at_put(index, result); } } break; default: classfile_parse_error( "Unknown constant tag %u in class file %s", tag, CHECK); break; } } // Allocate the remaining symbols if (names_count > 0) { SymbolTable::new_symbols(loader_data, cp, names_count, names, lengths, indices, hashValues, CHECK); } // Copy _current pointer of local copy back to stream(). #ifdef ASSERT assert(cfs0->current() == old_current, "non-exclusive use of stream()"); #endif cfs0->set_current(cfs1.current()); } // This class unreferences constant pool symbols if an error has occurred // while parsing the class before it is assigned into the class. // If it gets an error after that it is unloaded and the constant pool will // be cleaned up then. class ConstantPoolCleaner : public StackObj { constantPoolHandle _cphandle; bool _in_error; public: ConstantPoolCleaner(constantPoolHandle cp) : _cphandle(cp), _in_error(true) {} ~ConstantPoolCleaner() { if (_in_error && _cphandle.not_null()) { _cphandle->unreference_symbols(); } } void set_in_error(bool clean) { _in_error = clean; } }; bool inline valid_cp_range(int index, int length) { return (index > 0 && index < length); } inline Symbol* check_symbol_at(constantPoolHandle cp, int index) { if (valid_cp_range(index, cp->length()) && cp->tag_at(index).is_utf8()) return cp->symbol_at(index); else return NULL; } constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_data, TRAPS) { ClassFileStream* cfs = stream(); constantPoolHandle nullHandle; cfs->guarantee_more(3, CHECK_(nullHandle)); // length, first cp tag u2 length = cfs->get_u2_fast(); guarantee_property( length >= 1, "Illegal constant pool size %u in class file %s", length, CHECK_(nullHandle)); ConstantPool* constant_pool = ConstantPool::allocate(loader_data, length, CHECK_(nullHandle)); constantPoolHandle cp (THREAD, constant_pool); ConstantPoolCleaner cp_in_error(cp); // set constant pool to be cleaned up. // parsing constant pool entries parse_constant_pool_entries(loader_data, cp, length, CHECK_(nullHandle)); int index = 1; // declared outside of loops for portability // first verification pass - validate cross references and fixup class and string constants for (index = 1; index < length; index++) { // Index 0 is unused 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; int klass_ref_index = cp->klass_ref_index_at(index); int name_and_type_ref_index = cp->name_and_type_ref_index_at(index); check_property(valid_cp_range(klass_ref_index, length) && is_klass_reference(cp, klass_ref_index), "Invalid constant pool index %u in class file %s", klass_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)); 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_(nullHandle)); break; case JVM_CONSTANT_NameAndType : { if (!_need_verify) break; int name_ref_index = cp->name_ref_index_at(index); int signature_ref_index = cp->signature_ref_index_at(index); check_property( valid_cp_range(name_ref_index, length) && cp->tag_at(name_ref_index).is_utf8(), "Invalid constant pool index %u in class file %s", name_ref_index, CHECK_(nullHandle)); check_property( valid_cp_range(signature_ref_index, length) && cp->tag_at(signature_ref_index).is_utf8(), "Invalid constant pool index %u in class file %s", signature_ref_index, CHECK_(nullHandle)); 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 : { int class_index = cp->klass_index_at(index); 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)); } break; case JVM_CONSTANT_StringIndex : { int string_index = cp->string_index_at(index); check_property( valid_cp_range(string_index, length) && cp->tag_at(string_index).is_utf8(), "Invalid constant pool index %u in class file %s", string_index, CHECK_(nullHandle)); Symbol* sym = cp->symbol_at(string_index); cp->unresolved_string_at_put(index, sym); } break; case JVM_CONSTANT_MethodHandle : { int ref_index = cp->method_handle_index_at(index); check_property( valid_cp_range(ref_index, length) && EnableInvokeDynamic, "Invalid constant pool index %u in class file %s", ref_index, CHECK_(nullHandle)); constantTag tag = cp->tag_at(ref_index); int 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_(nullHandle)); break; case JVM_REF_invokeVirtual: case JVM_REF_invokeStatic: case JVM_REF_invokeSpecial: case JVM_REF_newInvokeSpecial: check_property( tag.is_method(), "Invalid constant pool index %u in class file %s (not a method)", ref_index, CHECK_(nullHandle)); 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_(nullHandle)); break; default: classfile_parse_error( "Bad method handle kind at constant pool index %u in class file %s", index, CHECK_(nullHandle)); } // Keep the ref_index unchanged. It will be indirected at link-time. } break; case JVM_CONSTANT_MethodType : { int ref_index = cp->method_type_index_at(index); check_property( valid_cp_range(ref_index, length) && cp->tag_at(ref_index).is_utf8() && EnableInvokeDynamic, "Invalid constant pool index %u in class file %s", ref_index, CHECK_(nullHandle)); } break; case JVM_CONSTANT_InvokeDynamic : { int name_and_type_ref_index = cp->invoke_dynamic_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_(nullHandle)); // bootstrap specifier index must be checked later, when BootstrapMethods attr is available break; } default: fatal(err_msg("bad constant pool tag value %u", cp->tag_at(index).value())); ShouldNotReachHere(); break; } // end of switch } // end of for if (_cp_patches != NULL) { // need to treat this_class specially... assert(EnableInvokeDynamic, ""); 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)); } } } if (!_need_verify) { cp_in_error.set_in_error(false); 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: { Symbol* class_name = 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_NameAndType: { if (_need_verify && _major_version >= JAVA_7_VERSION) { int sig_index = cp->signature_ref_index_at(index); int name_index = cp->name_ref_index_at(index); Symbol* name = cp->symbol_at(name_index); Symbol* sig = cp->symbol_at(sig_index); if (sig->byte_at(0) == JVM_SIGNATURE_FUNC) { verify_legal_method_signature(name, sig, CHECK_(nullHandle)); } else { verify_legal_field_signature(name, sig, CHECK_(nullHandle)); } } break; } case JVM_CONSTANT_InvokeDynamic: case JVM_CONSTANT_Fieldref: case JVM_CONSTANT_Methodref: case JVM_CONSTANT_InterfaceMethodref: { int name_and_type_ref_index = cp->name_and_type_ref_index_at(index); // already verified to be utf8 int name_ref_index = cp->name_ref_index_at(name_and_type_ref_index); // already verified to be utf8 int signature_ref_index = cp->signature_ref_index_at(name_and_type_ref_index); Symbol* name = cp->symbol_at(name_ref_index); Symbol* signature = cp->symbol_at(signature_ref_index); if (tag == JVM_CONSTANT_Fieldref) { verify_legal_field_name(name, CHECK_(nullHandle)); if (_need_verify && _major_version >= JAVA_7_VERSION) { // Signature is verified above, when iterating NameAndType_info. // Need only to be sure it's the right type. if (signature->byte_at(0) == JVM_SIGNATURE_FUNC) { throwIllegalSignature( "Field", name, signature, CHECK_(nullHandle)); } } else { verify_legal_field_signature(name, signature, CHECK_(nullHandle)); } } else { verify_legal_method_name(name, CHECK_(nullHandle)); if (_need_verify && _major_version >= JAVA_7_VERSION) { // Signature is verified above, when iterating NameAndType_info. // Need only to be sure it's the right type. if (signature->byte_at(0) != JVM_SIGNATURE_FUNC) { throwIllegalSignature( "Method", name, signature, CHECK_(nullHandle)); } } else { verify_legal_method_signature(name, signature, CHECK_(nullHandle)); } if (tag == JVM_CONSTANT_Methodref) { // 4509014: If a class method name begins with '<', it must be "<init>". assert(name != NULL, "method name in constant pool is null"); unsigned int name_len = name->utf8_length(); assert(name_len > 0, "bad method name"); // already verified as legal name if (name->byte_at(0) == '<') { if (name != vmSymbols::object_initializer_name()) { classfile_parse_error( "Bad method name at constant pool index %u in class file %s", name_ref_index, CHECK_(nullHandle)); } } } } break; } case JVM_CONSTANT_MethodHandle: { int ref_index = cp->method_handle_index_at(index); int 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: { int name_and_type_ref_index = cp->name_and_type_ref_index_at(ref_index); int name_ref_index = cp->name_ref_index_at(name_and_type_ref_index); Symbol* 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, CHECK_(nullHandle)); } } 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, CHECK_(nullHandle)); } } } break; // Other ref_kinds are already fully checked in previous pass. } break; } case JVM_CONSTANT_MethodType: { Symbol* no_name = vmSymbols::type_name(); // place holder Symbol* signature = cp->method_type_signature_at(index); verify_legal_method_signature(no_name, signature, CHECK_(nullHandle)); break; } case JVM_CONSTANT_Utf8: { assert(cp->symbol_at(index)->refcount() != 0, "count corrupted"); } } // end of switch } // end of for cp_in_error.set_in_error(false); return cp; } void ClassFileParser::patch_constant_pool(constantPoolHandle cp, int index, Handle patch, TRAPS) { assert(EnableInvokeDynamic, ""); 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. if (java_lang_Class::is_instance(patch())) { guarantee_property(!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_Klass(patch())); } else { guarantee_property(java_lang_String::is_instance(patch()), "Illegal class patch at %d in class file %s", index, CHECK); Symbol* name = java_lang_String::as_symbol(patch(), CHECK); cp->unresolved_klass_at_put(index, name); } break; case JVM_CONSTANT_String : // skip this patch and don't clear it. Needs the oop array for resolved // references to be created first. return; 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->double_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: Symbol* _name; // name Symbol* _sig; // signature NameSigHash* _next; // Next entry in hash table }; #define HASH_ROW_SIZE 256 unsigned int hash(Symbol* name, Symbol* sig) { unsigned int raw_hash = 0; raw_hash += ((unsigned int)(uintptr_t)name) >> (LogHeapWordSize + 2); raw_hash += ((unsigned int)(uintptr_t)sig) >> LogHeapWordSize; return (raw_hash + (unsigned int)(uintptr_t)name) % HASH_ROW_SIZE; } void 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. bool put_after_lookup(Symbol* name, 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) { return false; } entry = entry->_next; } // No duplicate is found, allocate a new entry and fill it. entry = new NameSigHash(); entry->_name = name; entry->_sig = sig; // Insert into hash table entry->_next = table[index]; table[index] = entry; return true; } Array<Klass*>* ClassFileParser::parse_interfaces(constantPoolHandle cp, int length, ClassLoaderData* loader_data, Handle protection_domain, Symbol* class_name, bool* has_default_methods, TRAPS) { ClassFileStream* cfs = stream(); assert(length > 0, "only called for length>0"); // FIXME: Leak at later OOM. Array<Klass*>* interfaces = MetadataFactory::new_array<Klass*>(loader_data, length, NULL, CHECK_NULL); int index; for (index = 0; index < length; index++) { u2 interface_index = cfs->get_u2(CHECK_NULL); KlassHandle interf; check_property( valid_cp_range(interface_index, cp->length()) && is_klass_reference(cp, interface_index), "Interface name has bad constant pool index %u in class file %s", interface_index, CHECK_NULL); if (cp->tag_at(interface_index).is_klass()) { interf = KlassHandle(THREAD, cp->resolved_klass_at(interface_index)); } else { Symbol* 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->byte_at(0) != JVM_SIGNATURE_ARRAY, "Bad interface name in class file %s", CHECK_NULL); Handle class_loader(THREAD, loader_data->class_loader()); // Call resolve_super so classcircularity is checked Klass* k = SystemDictionary::resolve_super_or_fail(class_name, unresolved_klass, class_loader, protection_domain, false, CHECK_NULL); interf = KlassHandle(THREAD, k); } if (!Klass::cast(interf())->is_interface()) { THROW_MSG_(vmSymbols::java_lang_IncompatibleClassChangeError(), "Implementing class", NULL); } if (InstanceKlass::cast(interf())->has_default_methods()) { *has_default_methods = true; } interfaces->at_put(index, interf()); } if (!_need_verify || length <= 1) { return interfaces; } // 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; { debug_only(No_Safepoint_Verifier nsv;) for (index = 0; index < length; index++) { Klass* k = interfaces->at(index); Symbol* name = InstanceKlass::cast(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 in class file %s", CHECK_NULL); } return interfaces; } void ClassFileParser::verify_constantvalue(int constantvalue_index, int signature_index, constantPoolHandle cp, TRAPS) { // 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); 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, CHECK); } } // Parse attributes for a field. void ClassFileParser::parse_field_attributes(ClassLoaderData* loader_data, constantPoolHandle cp, u2 attributes_count, bool is_static, u2 signature_index, u2* constantvalue_index_addr, bool* is_synthetic_addr, u2* generic_signature_index_addr, AnnotationArray** field_annotations, ClassFileParser::FieldAnnotationCollector* parsed_annotations, TRAPS) { ClassFileStream* cfs = stream(); assert(attributes_count > 0, "length should be greater than 0"); u2 constantvalue_index = 0; u2 generic_signature_index = 0; bool is_synthetic = false; u1* runtime_visible_annotations = NULL; int runtime_visible_annotations_length = 0; u1* runtime_invisible_annotations = NULL; int runtime_invisible_annotations_length = 0; while (attributes_count--) { cfs->guarantee_more(6, CHECK); // attribute_name_index, attribute_length u2 attribute_name_index = cfs->get_u2_fast(); u4 attribute_length = cfs->get_u4_fast(); check_property(valid_cp_range(attribute_name_index, cp->length()) && cp->tag_at(attribute_name_index).is_utf8(), "Invalid field attribute index %u in class file %s", attribute_name_index, CHECK); Symbol* 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", CHECK); } 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(constantvalue_index, signature_index, cp, CHECK); } } else if (attribute_name == vmSymbols::tag_synthetic()) { if (attribute_length != 0) { classfile_parse_error( "Invalid Synthetic field attribute length %u in class file %s", attribute_length, CHECK); } is_synthetic = true; } else if (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, CHECK); } } else if (_major_version >= JAVA_1_5_VERSION) { if (attribute_name == vmSymbols::tag_signature()) { if (attribute_length != 2) { classfile_parse_error( "Wrong size %u for field's Signature attribute in class file %s", attribute_length, CHECK); } generic_signature_index = cfs->get_u2(CHECK); } else if (attribute_name == vmSymbols::tag_runtime_visible_annotations()) { runtime_visible_annotations_length = attribute_length; runtime_visible_annotations = cfs->get_u1_buffer(); assert(runtime_visible_annotations != NULL, "null visible annotations"); cfs->skip_u1(runtime_visible_annotations_length, CHECK); } else if (PreserveAllAnnotations && attribute_name == vmSymbols::tag_runtime_invisible_annotations()) { runtime_invisible_annotations_length = attribute_length; runtime_invisible_annotations = cfs->get_u1_buffer(); assert(runtime_invisible_annotations != NULL, "null invisible annotations"); cfs->skip_u1(runtime_invisible_annotations_length, CHECK); } else { cfs->skip_u1(attribute_length, CHECK); // Skip unknown attributes } } else { cfs->skip_u1(attribute_length, CHECK); // Skip unknown attributes } } *constantvalue_index_addr = constantvalue_index; *is_synthetic_addr = is_synthetic; *generic_signature_index_addr = generic_signature_index; *field_annotations = assemble_annotations(loader_data, runtime_visible_annotations, runtime_visible_annotations_length, runtime_invisible_annotations, runtime_invisible_annotations_length, CHECK); return; } // Field allocation types. Used for computing field offsets. enum FieldAllocationType { STATIC_OOP, // Oops STATIC_BYTE, // Boolean, Byte, char STATIC_SHORT, // shorts STATIC_WORD, // ints STATIC_DOUBLE, // aligned long or double NONSTATIC_OOP, NONSTATIC_BYTE, NONSTATIC_SHORT, NONSTATIC_WORD, NONSTATIC_DOUBLE, MAX_FIELD_ALLOCATION_TYPE, BAD_ALLOCATION_TYPE = -1 }; static FieldAllocationType _basic_type_to_atype[2 * (T_CONFLICT + 1)] = { BAD_ALLOCATION_TYPE, // 0 BAD_ALLOCATION_TYPE, // 1 BAD_ALLOCATION_TYPE, // 2 BAD_ALLOCATION_TYPE, // 3 NONSTATIC_BYTE , // T_BOOLEAN = 4, NONSTATIC_SHORT, // T_CHAR = 5, NONSTATIC_WORD, // T_FLOAT = 6, NONSTATIC_DOUBLE, // T_DOUBLE = 7, NONSTATIC_BYTE, // T_BYTE = 8, NONSTATIC_SHORT, // T_SHORT = 9, NONSTATIC_WORD, // T_INT = 10, NONSTATIC_DOUBLE, // T_LONG = 11, NONSTATIC_OOP, // T_OBJECT = 12, NONSTATIC_OOP, // T_ARRAY = 13, BAD_ALLOCATION_TYPE, // T_VOID = 14, BAD_ALLOCATION_TYPE, // T_ADDRESS = 15, BAD_ALLOCATION_TYPE, // T_NARROWOOP = 16, BAD_ALLOCATION_TYPE, // T_METADATA = 17, BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 18, BAD_ALLOCATION_TYPE, // T_CONFLICT = 19, BAD_ALLOCATION_TYPE, // 0 BAD_ALLOCATION_TYPE, // 1 BAD_ALLOCATION_TYPE, // 2 BAD_ALLOCATION_TYPE, // 3 STATIC_BYTE , // T_BOOLEAN = 4, STATIC_SHORT, // T_CHAR = 5, STATIC_WORD, // T_FLOAT = 6, STATIC_DOUBLE, // T_DOUBLE = 7, STATIC_BYTE, // T_BYTE = 8, STATIC_SHORT, // T_SHORT = 9, STATIC_WORD, // T_INT = 10, STATIC_DOUBLE, // T_LONG = 11, STATIC_OOP, // T_OBJECT = 12, STATIC_OOP, // T_ARRAY = 13, BAD_ALLOCATION_TYPE, // T_VOID = 14, BAD_ALLOCATION_TYPE, // T_ADDRESS = 15, BAD_ALLOCATION_TYPE, // T_NARROWOOP = 16, BAD_ALLOCATION_TYPE, // T_METADATA = 17, BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 18, BAD_ALLOCATION_TYPE, // T_CONFLICT = 19, }; static FieldAllocationType basic_type_to_atype(bool is_static, BasicType type) { assert(type >= T_BOOLEAN && type < T_VOID, "only allowable values"); FieldAllocationType result = _basic_type_to_atype[type + (is_static ? (T_CONFLICT + 1) : 0)]; assert(result != BAD_ALLOCATION_TYPE, "bad type"); return result; } class FieldAllocationCount: public ResourceObj { public: u2 count[MAX_FIELD_ALLOCATION_TYPE]; FieldAllocationCount() { for (int i = 0; i < MAX_FIELD_ALLOCATION_TYPE; i++) { count[i] = 0; } } FieldAllocationType update(bool is_static, BasicType type) { FieldAllocationType atype = basic_type_to_atype(is_static, type); // Make sure there is no overflow with injected fields. assert(count[atype] < 0xFFFF, "More than 65535 fields"); count[atype]++; return atype; } }; Array<u2>* ClassFileParser::parse_fields(ClassLoaderData* loader_data, Symbol* class_name, constantPoolHandle cp, bool is_interface, FieldAllocationCount *fac, Array<AnnotationArray*>** fields_annotations, u2* java_fields_count_ptr, TRAPS) { ClassFileStream* cfs = stream(); cfs->guarantee_more(2, CHECK_NULL); // length u2 length = cfs->get_u2_fast(); *java_fields_count_ptr = length; int num_injected = 0; InjectedField* injected = JavaClasses::get_injected(class_name, &num_injected); int total_fields = length + num_injected; // 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* fa = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, u2, total_fields * (FieldInfo::field_slots + 1)); AnnotationArray* field_annotations = NULL; // 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++) { cfs->guarantee_more(8, CHECK_NULL); // access_flags, name_index, descriptor_index, attributes_count AccessFlags access_flags; jint flags = cfs->get_u2_fast() & JVM_RECOGNIZED_FIELD_MODIFIERS; verify_legal_field_modifiers(flags, is_interface, CHECK_NULL); access_flags.set_flags(flags); u2 name_index = cfs->get_u2_fast(); int cp_size = cp->length(); check_property( valid_cp_range(name_index, cp_size) && cp->tag_at(name_index).is_utf8(), "Invalid constant pool index %u for field name in class file %s", name_index, CHECK_NULL); Symbol* name = cp->symbol_at(name_index); verify_legal_field_name(name, CHECK_NULL); u2 signature_index = cfs->get_u2_fast(); check_property( valid_cp_range(signature_index, cp_size) && cp->tag_at(signature_index).is_utf8(), "Invalid constant pool index %u for field signature in class file %s", signature_index, CHECK_NULL); Symbol* sig = cp->symbol_at(signature_index); verify_legal_field_signature(name, sig, CHECK_NULL); u2 constantvalue_index = 0; bool is_synthetic = false; u2 generic_signature_index = 0; bool is_static = access_flags.is_static(); FieldAnnotationCollector parsed_annotations; u2 attributes_count = cfs->get_u2_fast(); if (attributes_count > 0) { parse_field_attributes(loader_data, cp, attributes_count, is_static, signature_index, &constantvalue_index, &is_synthetic, &generic_signature_index, &field_annotations, &parsed_annotations, CHECK_NULL); if (field_annotations != NULL) { if (*fields_annotations == NULL) { *fields_annotations = MetadataFactory::new_array<AnnotationArray*>( loader_data, length, NULL, CHECK_NULL); } (*fields_annotations)->at_put(n, field_annotations); } 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* field = FieldInfo::from_field_array(fa, n); field->initialize(access_flags.as_short(), name_index, signature_index, constantvalue_index, 0); if (parsed_annotations.has_any_annotations()) parsed_annotations.apply_to(field); BasicType type = cp->basic_type_for_signature_at(signature_index); // Remember how many oops we encountered and compute allocation type FieldAllocationType atype = fac->update(is_static, type); // The correct offset is computed later (all oop fields will be located together) // We temporarily store the allocation type in the offset field field->set_offset(atype); } int index = length; if (num_injected != 0) { for (int n = 0; n < num_injected; n++) { // Check for duplicates if (injected[n].may_be_java) { Symbol* name = injected[n].name(); Symbol* signature = injected[n].signature(); bool duplicate = false; for (int i = 0; i < length; i++) { FieldInfo* 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* field = FieldInfo::from_field_array(fa, index); field->initialize(JVM_ACC_FIELD_INTERNAL, injected[n].name_index, injected[n].signature_index, 0, 0); BasicType type = FieldType::basic_type(injected[n].signature()); // Remember how many oops we encountered and compute allocation type FieldAllocationType atype = fac->update(false, type); // The correct offset is computed later (all oop fields will be located together) // We temporarily store the allocation type in the offset field field->set_offset(atype); index++; } } // Now copy the fields' data from the temporary resource array. // Sometimes injected fields already exist in the Java source so // the fields array could be too long. In that case the // fields array is trimed. Also unused slots that were reserved // for generic signature indexes are discarded. Array<u2>* fields = MetadataFactory::new_array<u2>( loader_data, index * FieldInfo::field_slots + num_generic_signature, CHECK_NULL); { int i = 0; for (; i < index * FieldInfo::field_slots; i++) { fields->at_put(i, fa[i]); } for (int j = total_fields * FieldInfo::field_slots; j < generic_signature_slot; j++) { fields->at_put(i++, fa[j]); } assert(i == fields->length(), ""); } if (_need_verify && length > 1) { // Check duplicated fields ResourceMark rm(THREAD); NameSigHash** names_and_sigs = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, NameSigHash*, HASH_ROW_SIZE); initialize_hashtable(names_and_sigs); bool dup = false; { debug_only(No_Safepoint_Verifier nsv;) for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { Symbol* name = fs.name(); Symbol* sig = fs.signature(); // If no duplicates, add name/signature in hashtable names_and_sigs. if (!put_after_lookup(name, sig, names_and_sigs)) { dup = true; break; } } } if (dup) { classfile_parse_error("Duplicate field name&signature in class file %s", CHECK_NULL); } } return fields; } static void copy_u2_with_conversion(u2* dest, u2* src, int length) { while (length-- > 0) { *dest++ = Bytes::get_Java_u2((u1*) (src++)); } } u2* ClassFileParser::parse_exception_table(ClassLoaderData* loader_data, u4 code_length, u4 exception_table_length, constantPoolHandle cp, TRAPS) { ClassFileStream* cfs = stream(); u2* exception_table_start = cfs->get_u2_buffer(); assert(exception_table_start != NULL, "null exception table"); cfs->guarantee_more(8 * exception_table_length, CHECK_NULL); // start_pc, end_pc, handler_pc, catch_type_index // Will check legal target after parsing code array in verifier. if (_need_verify) { for (unsigned int i = 0; i < exception_table_length; i++) { u2 start_pc = cfs->get_u2_fast(); u2 end_pc = cfs->get_u2_fast(); u2 handler_pc = cfs->get_u2_fast(); u2 catch_type_index = cfs->get_u2_fast(); guarantee_property((start_pc < end_pc) && (end_pc <= code_length), "Illegal exception table range in class file %s", CHECK_NULL); guarantee_property(handler_pc < code_length, "Illegal exception table handler in class file %s", CHECK_NULL); if (catch_type_index != 0) { guarantee_property(valid_cp_range(catch_type_index, cp->length()) && is_klass_reference(cp, catch_type_index), "Catch type in exception table has bad constant type in class file %s", CHECK_NULL); } } } else { cfs->skip_u2_fast(exception_table_length * 4); } return exception_table_start; } void ClassFileParser::parse_linenumber_table( u4 code_attribute_length, u4 code_length, CompressedLineNumberWriteStream** write_stream, TRAPS) { ClassFileStream* cfs = stream(); unsigned int num_entries = cfs->get_u2(CHECK); // Each entry is a u2 start_pc, and a u2 line_number unsigned int length_in_bytes = num_entries * (sizeof(u2) + sizeof(u2)); // Verify line number attribute and table length check_property( code_attribute_length == sizeof(u2) + length_in_bytes, "LineNumberTable attribute has wrong length in class file %s", CHECK); cfs->guarantee_more(length_in_bytes, CHECK); if ((*write_stream) == NULL) { if (length_in_bytes > fixed_buffer_size) { (*write_stream) = new CompressedLineNumberWriteStream(length_in_bytes); } else { (*write_stream) = new CompressedLineNumberWriteStream( linenumbertable_buffer, fixed_buffer_size); } } while (num_entries-- > 0) { u2 bci = cfs->get_u2_fast(); // start_pc u2 line = cfs->get_u2_fast(); // line_number guarantee_property(bci < code_length, "Invalid pc in LineNumberTable in class file %s", CHECK); (*write_stream)->write_pair(bci, line); } } // Class file LocalVariableTable elements. class Classfile_LVT_Element VALUE_OBJ_CLASS_SPEC { public: u2 start_bci; u2 length; u2 name_cp_index; u2 descriptor_cp_index; u2 slot; }; class LVT_Hash: public CHeapObj<mtClass> { public: LocalVariableTableElement *_elem; // element LVT_Hash* _next; // Next entry in hash table }; unsigned int hash(LocalVariableTableElement *elem) { unsigned int raw_hash = elem->start_bci; raw_hash = elem->length + raw_hash * 37; raw_hash = elem->name_cp_index + raw_hash * 37; raw_hash = elem->slot + raw_hash * 37; return raw_hash % HASH_ROW_SIZE; } void initialize_hashtable(LVT_Hash** table) { for (int i = 0; i < HASH_ROW_SIZE; i++) { table[i] = NULL; } } void clear_hashtable(LVT_Hash** table) { for (int i = 0; i < HASH_ROW_SIZE; i++) { LVT_Hash* current = table[i]; LVT_Hash* next; while (current != NULL) { next = current->_next; current->_next = NULL; delete(current); current = next; } table[i] = NULL; } } LVT_Hash* LVT_lookup(LocalVariableTableElement *elem, int index, LVT_Hash** table) { LVT_Hash* entry = table[index]; /* * 3-tuple start_bci/length/slot has to be unique key, * so the following comparison seems to be redundant: * && elem->name_cp_index == entry->_elem->name_cp_index */ while (entry != NULL) { if (elem->start_bci == entry->_elem->start_bci && elem->length == entry->_elem->length && elem->name_cp_index == entry->_elem->name_cp_index && elem->slot == entry->_elem->slot ) { return entry; } entry = entry->_next; } return NULL; } // Return false if the local variable is found in table. // Return true if no duplicate is found. // And local variable is added as a new entry in table. bool LVT_put_after_lookup(LocalVariableTableElement *elem, LVT_Hash** table) { // First lookup for duplicates int index = hash(elem); LVT_Hash* entry = LVT_lookup(elem, index, table); if (entry != NULL) { return false; } // No duplicate is found, allocate a new entry and fill it. if ((entry = new LVT_Hash()) == NULL) { return false; } entry->_elem = elem; // Insert into hash table entry->_next = table[index]; table[index] = entry; return true; } void copy_lvt_element(Classfile_LVT_Element *src, LocalVariableTableElement *lvt) { lvt->start_bci = Bytes::get_Java_u2((u1*) &src->start_bci); lvt->length = Bytes::get_Java_u2((u1*) &src->length); lvt->name_cp_index = Bytes::get_Java_u2((u1*) &src->name_cp_index); lvt->descriptor_cp_index = Bytes::get_Java_u2((u1*) &src->descriptor_cp_index); lvt->signature_cp_index = 0; lvt->slot = Bytes::get_Java_u2((u1*) &src->slot); } // Function is used to parse both attributes: // LocalVariableTable (LVT) and LocalVariableTypeTable (LVTT) u2* ClassFileParser::parse_localvariable_table(u4 code_length, u2 max_locals, u4 code_attribute_length, constantPoolHandle cp, u2* localvariable_table_length, bool isLVTT, TRAPS) { ClassFileStream* cfs = stream(); const char * tbl_name = (isLVTT) ? "LocalVariableTypeTable" : "LocalVariableTable"; *localvariable_table_length = cfs->get_u2(CHECK_NULL); unsigned int size = (*localvariable_table_length) * sizeof(Classfile_LVT_Element) / sizeof(u2); // Verify local variable table attribute has right length if (_need_verify) { guarantee_property(code_attribute_length == (sizeof(*localvariable_table_length) + size * sizeof(u2)), "%s has wrong length in class file %s", tbl_name, CHECK_NULL); } u2* localvariable_table_start = cfs->get_u2_buffer(); assert(localvariable_table_start != NULL, "null local variable table"); if (!_need_verify) { cfs->skip_u2_fast(size); } else { cfs->guarantee_more(size * 2, CHECK_NULL); for(int i = 0; i < (*localvariable_table_length); i++) { u2 start_pc = cfs->get_u2_fast(); u2 length = cfs->get_u2_fast(); u2 name_index = cfs->get_u2_fast(); u2 descriptor_index = cfs->get_u2_fast(); u2 index = cfs->get_u2_fast(); // Assign to a u4 to avoid overflow u4 end_pc = (u4)start_pc + (u4)length; if (start_pc >= code_length) { classfile_parse_error( "Invalid start_pc %u in %s in class file %s", start_pc, tbl_name, CHECK_NULL); } if (end_pc > code_length) { classfile_parse_error( "Invalid length %u in %s in class file %s", length, tbl_name, CHECK_NULL); } int cp_size = cp->length(); guarantee_property( valid_cp_range(name_index, cp_size) && cp->tag_at(name_index).is_utf8(), "Name index %u in %s has bad constant type in class file %s", name_index, tbl_name, CHECK_NULL); guarantee_property( valid_cp_range(descriptor_index, cp_size) && cp->tag_at(descriptor_index).is_utf8(), "Signature index %u in %s has bad constant type in class file %s", descriptor_index, tbl_name, CHECK_NULL); Symbol* name = cp->symbol_at(name_index); Symbol* sig = cp->symbol_at(descriptor_index); verify_legal_field_name(name, CHECK_NULL); u2 extra_slot = 0; if (!isLVTT) { verify_legal_field_signature(name, sig, CHECK_NULL); // 4894874: check special cases for double and long local variables if (sig == vmSymbols::type_signature(T_DOUBLE) || sig == vmSymbols::type_signature(T_LONG)) { extra_slot = 1; } } guarantee_property((index + extra_slot) < max_locals, "Invalid index %u in %s in class file %s", index, tbl_name, CHECK_NULL); } } return localvariable_table_start; } void ClassFileParser::parse_type_array(u2 array_length, u4 code_length, u4* u1_index, u4* u2_index, u1* u1_array, u2* u2_array, constantPoolHandle cp, TRAPS) { ClassFileStream* cfs = stream(); u2 index = 0; // index in the array with long/double occupying two slots u4 i1 = *u1_index; u4 i2 = *u2_index + 1; for(int i = 0; i < array_length; i++) { u1 tag = u1_array[i1++] = cfs->get_u1(CHECK); index++; 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()) && is_klass_reference(cp, class_index), "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( offset < code_length, "Bad uninitialized type offset %u in StackMap in class file %s", offset, CHECK); } else { guarantee_property( tag <= (u1)ITEM_Uninitialized, "Unknown variable type %u in StackMap in class file %s", tag, CHECK); } } u2_array[*u2_index] = index; *u1_index = i1; *u2_index = i2; } Array<u1>* ClassFileParser::parse_stackmap_table( ClassLoaderData* loader_data, u4 code_attribute_length, TRAPS) { if (code_attribute_length == 0) return NULL; ClassFileStream* cfs = stream(); u1* stackmap_table_start = cfs->get_u1_buffer(); assert(stackmap_table_start != NULL, "null stackmap table"); // check code_attribute_length first stream()->skip_u1(code_attribute_length, CHECK_NULL); if (!_need_verify && !DumpSharedSpaces) { return NULL; } Array<u1>* stackmap_data = MetadataFactory::new_array<u1>(loader_data, code_attribute_length, 0, CHECK_NULL); memcpy((void*)stackmap_data->adr_at(0), (void*)stackmap_table_start, code_attribute_length); return stackmap_data; } u2* ClassFileParser::parse_checked_exceptions(u2* checked_exceptions_length, u4 method_attribute_length, constantPoolHandle cp, TRAPS) { ClassFileStream* cfs = stream(); cfs->guarantee_more(2, CHECK_NULL); // checked_exceptions_length *checked_exceptions_length = cfs->get_u2_fast(); unsigned int size = (*checked_exceptions_length) * sizeof(CheckedExceptionElement) / sizeof(u2); u2* checked_exceptions_start = cfs->get_u2_buffer(); assert(checked_exceptions_start != NULL, "null checked exceptions"); if (!_need_verify) { cfs->skip_u2_fast(size); } else { // Verify each value in the checked exception table u2 checked_exception; u2 len = *checked_exceptions_length; cfs->guarantee_more(2 * len, CHECK_NULL); for (int i = 0; i < len; i++) { checked_exception = cfs->get_u2_fast(); check_property( valid_cp_range(checked_exception, cp->length()) && is_klass_reference(cp, checked_exception), "Exception name has bad type at constant pool %u in class file %s", checked_exception, CHECK_NULL); } } // check exceptions attribute length if (_need_verify) { guarantee_property(method_attribute_length == (sizeof(*checked_exceptions_length) + sizeof(u2) * size), "Exceptions attribute has wrong length in class file %s", CHECK_NULL); } return checked_exceptions_start; } void ClassFileParser::throwIllegalSignature( const char* type, Symbol* name, Symbol* sig, TRAPS) { ResourceMark rm(THREAD); Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(), "%s \"%s\" in class %s has illegal signature \"%s\"", type, name->as_C_string(), _class_name->as_C_string(), sig->as_C_string()); } // Skip an annotation. Return >=limit if there is any problem. int ClassFileParser::skip_annotation(u1* buffer, int limit, int index) { // annotation := atype:u2 do(nmem:u2) {member:u2 value} // value := switch (tag:u1) { ... } index += 2; // skip atype if ((index += 2) >= limit) return limit; // read nmem int nmem = Bytes::get_Java_u2(buffer+index-2); while (--nmem >= 0 && index < limit) { index += 2; // skip member index = skip_annotation_value(buffer, limit, index); } return index; } // Skip an annotation value. Return >=limit if there is any problem. int ClassFileParser::skip_annotation_value(u1* buffer, int limit, int index) { // 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; // } if ((index += 1) >= limit) return limit; // read tag 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': index += 2; // skip con or s_con break; case 'e': index += 4; // skip e_class, e_name break; case '[': { if ((index += 2) >= limit) return limit; // read nval int nval = Bytes::get_Java_u2(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: assert(false, "annotation tag"); return limit; // bad tag byte } return index; } // Sift through annotations, looking for those significant to the VM: void ClassFileParser::parse_annotations(u1* buffer, int limit, constantPoolHandle cp, ClassFileParser::AnnotationCollector* coll, TRAPS) { // annotations := do(nann:u2) {annotation} int index = 0; if ((index += 2) >= limit) return; // read nann int nann = Bytes::get_Java_u2(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', c_con_off = 7, // utf8 payload, such as 'I' or 'Ljava/lang/String;' c_size = 9, // end of 'c' annotation min_size = 6 // smallest possible size (zero members) }; while ((--nann) >= 0 && (index-2 + min_size <= limit)) { int index0 = index; index = skip_annotation(buffer, limit, index); u1* abase = buffer + index0; int atype = Bytes::get_Java_u2(abase + atype_off); int count = Bytes::get_Java_u2(abase + count_off); Symbol* aname = check_symbol_at(cp, atype); if (aname == NULL) break; // invalid annotation name Symbol* member = NULL; if (count >= 1) { int member_index = Bytes::get_Java_u2(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(aname); if (id == AnnotationCollector::_unknown) continue; coll->set_annotation(id); // If there are no values, just set the bit and move on: if (count == 0) continue; // For the record, here is how annotation payloads can be collected. // Suppose we want to capture @Retention.value. Here is how: //if (id == AnnotationCollector::_class_Retention) { // Symbol* payload = NULL; // if (count == 1 // && e_size == (index0 - index) // match size // && e_tag_val == *(abase + tag_off) // && (check_symbol_at(cp, Bytes::get_Java_u2(abase + e_type_off)) // == vmSymbols::RetentionPolicy_signature()) // && member == vmSymbols::value_name()) { // payload = check_symbol_at(cp, Bytes::get_Java_u2(abase + e_con_off)); // } // check_property(payload != NULL, // "Invalid @Retention annotation at offset %u in class file %s", // index0, CHECK); // if (payload != NULL) { // payload->increment_refcount(); // coll->_class_RetentionPolicy = payload; // } //} } } ClassFileParser::AnnotationCollector::ID ClassFileParser::AnnotationCollector::annotation_index(Symbol* name) { vmSymbols::SID sid = vmSymbols::find_sid(name); switch (sid) { case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_ForceInline_signature): if (_location != _in_method) break; // only allow for methods return _method_ForceInline; case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_DontInline_signature): if (_location != _in_method) break; // only allow for methods return _method_DontInline; case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_LambdaForm_Compiled_signature): if (_location != _in_method) break; // only allow for methods return _method_LambdaForm_Compiled; case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_LambdaForm_Hidden_signature): if (_location != _in_method) break; // only allow for methods return _method_LambdaForm_Hidden; default: break; } return AnnotationCollector::_unknown; } void ClassFileParser::FieldAnnotationCollector::apply_to(FieldInfo* f) { fatal("no field annotations yet"); } void ClassFileParser::MethodAnnotationCollector::apply_to(methodHandle m) { if (has_annotation(_method_ForceInline)) m->set_force_inline(true); if (has_annotation(_method_DontInline)) m->set_dont_inline(true); if (has_annotation(_method_LambdaForm_Compiled) && m->intrinsic_id() == vmIntrinsics::_none) m->set_intrinsic_id(vmIntrinsics::_compiledLambdaForm); if (has_annotation(_method_LambdaForm_Hidden)) m->set_hidden(true); } void ClassFileParser::ClassAnnotationCollector::apply_to(instanceKlassHandle k) { fatal("no class annotations yet"); } #define MAX_ARGS_SIZE 255 #define MAX_CODE_SIZE 65535 #define INITIAL_MAX_LVT_NUMBER 256 // 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 // entire method attribute is parsed. // // The promoted_flags parameter is used to pass relevant access_flags // from the method back up to the containing klass. These flag values // are added to klass's access_flags. methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, constantPoolHandle cp, bool is_interface, AccessFlags *promoted_flags, AnnotationArray** method_annotations, AnnotationArray** method_parameter_annotations, AnnotationArray** method_default_annotations, TRAPS) { ClassFileStream* cfs = stream(); methodHandle nullHandle; ResourceMark rm(THREAD); // Parse fixed parts cfs->guarantee_more(8, CHECK_(nullHandle)); // access_flags, name_index, descriptor_index, attributes_count int flags = cfs->get_u2_fast(); u2 name_index = cfs->get_u2_fast(); int cp_size = cp->length(); check_property( valid_cp_range(name_index, cp_size) && cp->tag_at(name_index).is_utf8(), "Illegal constant pool index %u for method name in class file %s", name_index, CHECK_(nullHandle)); Symbol* name = cp->symbol_at(name_index); verify_legal_method_name(name, CHECK_(nullHandle)); u2 signature_index = cfs->get_u2_fast(); guarantee_property( valid_cp_range(signature_index, cp_size) && cp->tag_at(signature_index).is_utf8(), "Illegal constant pool index %u for method signature in class file %s", signature_index, CHECK_(nullHandle)); Symbol* signature = cp->symbol_at(signature_index); AccessFlags access_flags; if (name == vmSymbols::class_initializer_name()) { // We ignore the other access flags for a valid class initializer. // (JVM Spec 2nd ed., chapter 4.6) if (_major_version < 51) { // backward compatibility flags = JVM_ACC_STATIC; } else if ((flags & JVM_ACC_STATIC) == JVM_ACC_STATIC) { flags &= JVM_ACC_STATIC | JVM_ACC_STRICT; } } else { verify_legal_method_modifiers(flags, is_interface, name, CHECK_(nullHandle)); } int args_size = -1; // only used when _need_verify is true if (_need_verify) { args_size = ((flags & JVM_ACC_STATIC) ? 0 : 1) + verify_legal_method_signature(name, signature, CHECK_(nullHandle)); if (args_size > MAX_ARGS_SIZE) { classfile_parse_error("Too many arguments in method signature in class file %s", CHECK_(nullHandle)); } } access_flags.set_flags(flags & JVM_RECOGNIZED_METHOD_MODIFIERS); // Default values for code and exceptions attribute elements u2 max_stack = 0; u2 max_locals = 0; u4 code_length = 0; u1* code_start = 0; u2 exception_table_length = 0; u2* exception_table_start = NULL; Array<int>* exception_handlers = Universe::the_empty_int_array(); u2 checked_exceptions_length = 0; u2* checked_exceptions_start = NULL; CompressedLineNumberWriteStream* linenumber_table = NULL; int linenumber_table_length = 0; int total_lvt_length = 0; u2 lvt_cnt = 0; u2 lvtt_cnt = 0; bool lvt_allocated = false; u2 max_lvt_cnt = INITIAL_MAX_LVT_NUMBER; u2 max_lvtt_cnt = INITIAL_MAX_LVT_NUMBER; u2* localvariable_table_length; u2** localvariable_table_start; u2* localvariable_type_table_length; u2** localvariable_type_table_start; bool parsed_code_attribute = false; bool parsed_checked_exceptions_attribute = false; bool parsed_stackmap_attribute = false; // stackmap attribute - JDK1.5 Array<u1>* stackmap_data = NULL; u2 generic_signature_index = 0; MethodAnnotationCollector parsed_annotations; u1* runtime_visible_annotations = NULL; int runtime_visible_annotations_length = 0; u1* runtime_invisible_annotations = NULL; int runtime_invisible_annotations_length = 0; u1* runtime_visible_parameter_annotations = NULL; int runtime_visible_parameter_annotations_length = 0; u1* runtime_invisible_parameter_annotations = NULL; int runtime_invisible_parameter_annotations_length = 0; u1* annotation_default = NULL; int annotation_default_length = 0; // Parse code and exceptions attribute u2 method_attributes_count = cfs->get_u2_fast(); while (method_attributes_count--) { cfs->guarantee_more(6, CHECK_(nullHandle)); // method_attribute_name_index, method_attribute_length u2 method_attribute_name_index = cfs->get_u2_fast(); u4 method_attribute_length = cfs->get_u4_fast(); check_property( valid_cp_range(method_attribute_name_index, cp_size) && cp->tag_at(method_attribute_name_index).is_utf8(), "Invalid method attribute name index %u in class file %s", method_attribute_name_index, CHECK_(nullHandle)); Symbol* method_attribute_name = cp->symbol_at(method_attribute_name_index); if (method_attribute_name == vmSymbols::tag_code()) { // Parse Code attribute if (_need_verify) { guarantee_property( !access_flags.is_native() && !access_flags.is_abstract(), "Code attribute in native or abstract methods in class file %s", CHECK_(nullHandle)); } if (parsed_code_attribute) { classfile_parse_error("Multiple Code attributes in class file %s", CHECK_(nullHandle)); } parsed_code_attribute = true; // Stack size, locals size, and code size if (_major_version == 45 && _minor_version <= 2) { cfs->guarantee_more(4, CHECK_(nullHandle)); max_stack = cfs->get_u1_fast(); max_locals = cfs->get_u1_fast(); code_length = cfs->get_u2_fast(); } else { cfs->guarantee_more(8, CHECK_(nullHandle)); max_stack = cfs->get_u2_fast(); max_locals = cfs->get_u2_fast(); code_length = cfs->get_u4_fast(); } if (_need_verify) { guarantee_property(args_size <= max_locals, "Arguments can't fit into locals in class file %s", CHECK_(nullHandle)); guarantee_property(code_length > 0 && code_length <= MAX_CODE_SIZE, "Invalid method Code length %u in class file %s", code_length, CHECK_(nullHandle)); } // Code pointer code_start = cfs->get_u1_buffer(); assert(code_start != NULL, "null code start"); cfs->guarantee_more(code_length, CHECK_(nullHandle)); cfs->skip_u1_fast(code_length); // Exception handler table cfs->guarantee_more(2, CHECK_(nullHandle)); // exception_table_length exception_table_length = cfs->get_u2_fast(); if (exception_table_length > 0) { exception_table_start = parse_exception_table(loader_data, code_length, exception_table_length, cp, CHECK_(nullHandle)); } // Parse additional attributes in code attribute cfs->guarantee_more(2, CHECK_(nullHandle)); // code_attributes_count u2 code_attributes_count = cfs->get_u2_fast(); unsigned int calculated_attribute_length = 0; if (_major_version > 45 || (_major_version == 45 && _minor_version > 2)) { calculated_attribute_length = sizeof(max_stack) + sizeof(max_locals) + sizeof(code_length); } else { // max_stack, locals and length are smaller in pre-version 45.2 classes calculated_attribute_length = sizeof(u1) + sizeof(u1) + sizeof(u2); } calculated_attribute_length += code_length + sizeof(exception_table_length) + sizeof(code_attributes_count) + exception_table_length * ( sizeof(u2) + // start_pc sizeof(u2) + // end_pc sizeof(u2) + // handler_pc sizeof(u2) ); // catch_type_index while (code_attributes_count--) { cfs->guarantee_more(6, CHECK_(nullHandle)); // code_attribute_name_index, code_attribute_length u2 code_attribute_name_index = cfs->get_u2_fast(); u4 code_attribute_length = cfs->get_u4_fast(); calculated_attribute_length += code_attribute_length + sizeof(code_attribute_name_index) + sizeof(code_attribute_length); check_property(valid_cp_range(code_attribute_name_index, cp_size) && cp->tag_at(code_attribute_name_index).is_utf8(), "Invalid code attribute name index %u in class file %s", code_attribute_name_index, CHECK_(nullHandle)); if (LoadLineNumberTables && cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_line_number_table()) { // Parse and compress line number table parse_linenumber_table(code_attribute_length, code_length, &linenumber_table, CHECK_(nullHandle)); } else if (LoadLocalVariableTables && cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_table()) { // Parse local variable table if (!lvt_allocated) { localvariable_table_length = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, u2, INITIAL_MAX_LVT_NUMBER); localvariable_table_start = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, u2*, INITIAL_MAX_LVT_NUMBER); localvariable_type_table_length = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, u2, INITIAL_MAX_LVT_NUMBER); localvariable_type_table_start = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, u2*, INITIAL_MAX_LVT_NUMBER); lvt_allocated = true; } if (lvt_cnt == max_lvt_cnt) { max_lvt_cnt <<= 1; REALLOC_RESOURCE_ARRAY(u2, localvariable_table_length, lvt_cnt, max_lvt_cnt); REALLOC_RESOURCE_ARRAY(u2*, localvariable_table_start, lvt_cnt, max_lvt_cnt); } localvariable_table_start[lvt_cnt] = parse_localvariable_table(code_length, max_locals, code_attribute_length, cp, &localvariable_table_length[lvt_cnt], false, // is not LVTT CHECK_(nullHandle)); total_lvt_length += localvariable_table_length[lvt_cnt]; lvt_cnt++; } else if (LoadLocalVariableTypeTables && _major_version >= JAVA_1_5_VERSION && cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_type_table()) { if (!lvt_allocated) { localvariable_table_length = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, u2, INITIAL_MAX_LVT_NUMBER); localvariable_table_start = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, u2*, INITIAL_MAX_LVT_NUMBER); localvariable_type_table_length = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, u2, INITIAL_MAX_LVT_NUMBER); localvariable_type_table_start = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, u2*, INITIAL_MAX_LVT_NUMBER); lvt_allocated = true; } // Parse local variable type table if (lvtt_cnt == max_lvtt_cnt) { max_lvtt_cnt <<= 1; REALLOC_RESOURCE_ARRAY(u2, localvariable_type_table_length, lvtt_cnt, max_lvtt_cnt); REALLOC_RESOURCE_ARRAY(u2*, localvariable_type_table_start, lvtt_cnt, max_lvtt_cnt); } localvariable_type_table_start[lvtt_cnt] = parse_localvariable_table(code_length, max_locals, code_attribute_length, cp, &localvariable_type_table_length[lvtt_cnt], true, // is LVTT CHECK_(nullHandle)); lvtt_cnt++; } else if (UseSplitVerifier && _major_version >= Verifier::STACKMAP_ATTRIBUTE_MAJOR_VERSION && cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_stack_map_table()) { // Stack map is only needed by the new verifier in JDK1.5. if (parsed_stackmap_attribute) { classfile_parse_error("Multiple StackMapTable attributes in class file %s", CHECK_(nullHandle)); } stackmap_data = parse_stackmap_table(loader_data, code_attribute_length, CHECK_(nullHandle)); parsed_stackmap_attribute = true; } else { // Skip unknown attributes cfs->skip_u1(code_attribute_length, CHECK_(nullHandle)); } } // check method attribute length if (_need_verify) { guarantee_property(method_attribute_length == calculated_attribute_length, "Code segment has wrong length in class file %s", CHECK_(nullHandle)); } } else if (method_attribute_name == vmSymbols::tag_exceptions()) { // Parse Exceptions attribute if (parsed_checked_exceptions_attribute) { classfile_parse_error("Multiple Exceptions attributes in class file %s", CHECK_(nullHandle)); } parsed_checked_exceptions_attribute = true; checked_exceptions_start = parse_checked_exceptions(&checked_exceptions_length, method_attribute_length, cp, CHECK_(nullHandle)); } else if (method_attribute_name == vmSymbols::tag_synthetic()) { if (method_attribute_length != 0) { classfile_parse_error( "Invalid Synthetic method attribute length %u in class file %s", method_attribute_length, CHECK_(nullHandle)); } // Should we check that there hasn't already been a synthetic attribute? access_flags.set_is_synthetic(); } else if (method_attribute_name == vmSymbols::tag_deprecated()) { // 4276120 if (method_attribute_length != 0) { classfile_parse_error( "Invalid Deprecated method attribute length %u in class file %s", method_attribute_length, CHECK_(nullHandle)); } } else if (_major_version >= JAVA_1_5_VERSION) { if (method_attribute_name == vmSymbols::tag_signature()) { if (method_attribute_length != 2) { classfile_parse_error( "Invalid Signature attribute length %u in class file %s", method_attribute_length, CHECK_(nullHandle)); } cfs->guarantee_more(2, CHECK_(nullHandle)); // generic_signature_index generic_signature_index = cfs->get_u2_fast(); } else if (method_attribute_name == vmSymbols::tag_runtime_visible_annotations()) { runtime_visible_annotations_length = method_attribute_length; runtime_visible_annotations = cfs->get_u1_buffer(); assert(runtime_visible_annotations != NULL, "null visible annotations"); parse_annotations(runtime_visible_annotations, runtime_visible_annotations_length, cp, &parsed_annotations, CHECK_(nullHandle)); cfs->skip_u1(runtime_visible_annotations_length, CHECK_(nullHandle)); } else if (PreserveAllAnnotations && method_attribute_name == vmSymbols::tag_runtime_invisible_annotations()) { runtime_invisible_annotations_length = method_attribute_length; runtime_invisible_annotations = cfs->get_u1_buffer(); assert(runtime_invisible_annotations != NULL, "null invisible annotations"); cfs->skip_u1(runtime_invisible_annotations_length, CHECK_(nullHandle)); } else if (method_attribute_name == vmSymbols::tag_runtime_visible_parameter_annotations()) { runtime_visible_parameter_annotations_length = method_attribute_length; runtime_visible_parameter_annotations = cfs->get_u1_buffer(); assert(runtime_visible_parameter_annotations != NULL, "null visible parameter annotations"); cfs->skip_u1(runtime_visible_parameter_annotations_length, CHECK_(nullHandle)); } else if (PreserveAllAnnotations && method_attribute_name == vmSymbols::tag_runtime_invisible_parameter_annotations()) { runtime_invisible_parameter_annotations_length = method_attribute_length; runtime_invisible_parameter_annotations = cfs->get_u1_buffer(); assert(runtime_invisible_parameter_annotations != NULL, "null invisible parameter annotations"); cfs->skip_u1(runtime_invisible_parameter_annotations_length, CHECK_(nullHandle)); } else if (method_attribute_name == vmSymbols::tag_annotation_default()) { annotation_default_length = method_attribute_length; annotation_default = cfs->get_u1_buffer(); assert(annotation_default != NULL, "null annotation default"); cfs->skip_u1(annotation_default_length, CHECK_(nullHandle)); } else { // Skip unknown attributes cfs->skip_u1(method_attribute_length, CHECK_(nullHandle)); } } else { // Skip unknown attributes cfs->skip_u1(method_attribute_length, CHECK_(nullHandle)); } } if (linenumber_table != NULL) { linenumber_table->write_terminator(); linenumber_table_length = linenumber_table->position(); } // Make sure there's at least one Code attribute in non-native/non-abstract method if (_need_verify) { guarantee_property(access_flags.is_native() || access_flags.is_abstract() || parsed_code_attribute, "Absent Code attribute in method that is not native or abstract in class file %s", CHECK_(nullHandle)); } // All sizing information for a Method* is finally available, now create it Method* m = Method::allocate( loader_data, code_length, access_flags, linenumber_table_length, total_lvt_length, exception_table_length, checked_exceptions_length, ConstMethod::NORMAL, CHECK_(nullHandle)); ClassLoadingService::add_class_method_size(m->size()*HeapWordSize); // Fill in information from fixed part (access_flags already set) m->set_constants(cp()); m->set_name_index(name_index); m->set_signature_index(signature_index); m->set_generic_signature_index(generic_signature_index); #ifdef CC_INTERP // hmm is there a gc issue here?? ResultTypeFinder rtf(cp->symbol_at(signature_index)); m->set_result_index(rtf.type()); #endif if (args_size >= 0) { m->set_size_of_parameters(args_size); } else { m->compute_size_of_parameters(THREAD); } #ifdef ASSERT if (args_size >= 0) { m->compute_size_of_parameters(THREAD); assert(args_size == m->size_of_parameters(), ""); } #endif // Fill in code attribute information m->set_max_stack(max_stack); m->set_max_locals(max_locals); m->constMethod()->set_stackmap_data(stackmap_data); // Copy byte codes m->set_code(code_start); // Copy line number table if (linenumber_table != NULL) { memcpy(m->compressed_linenumber_table(), linenumber_table->buffer(), linenumber_table_length); } // Copy exception table if (exception_table_length > 0) { int size = exception_table_length * sizeof(ExceptionTableElement) / sizeof(u2); copy_u2_with_conversion((u2*) m->exception_table_start(), exception_table_start, size); } // Copy checked exceptions if (checked_exceptions_length > 0) { int size = checked_exceptions_length * sizeof(CheckedExceptionElement) / sizeof(u2); 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. */ 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); } 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)); if (name == vmSymbols::finalize_method_name() && signature == vmSymbols::void_method_signature()) { if (m->is_empty_method()) { _has_empty_finalizer = true; } else { _has_finalizer = true; } } if (name == vmSymbols::object_initializer_name() && signature == vmSymbols::void_method_signature() && m->is_vanilla_constructor()) { _has_vanilla_constructor = true; } return m; } // The promoted_flags parameter is used to pass relevant access_flags // from the methods back up to the containing klass. These flag values // are added to klass's access_flags. Array<Method*>* ClassFileParser::parse_methods(ClassLoaderData* loader_data, constantPoolHandle cp, bool is_interface, AccessFlags* promoted_flags, bool* has_final_method, Array<AnnotationArray*>** methods_annotations, Array<AnnotationArray*>** methods_parameter_annotations, Array<AnnotationArray*>** methods_default_annotations, bool* has_default_methods, TRAPS) { ClassFileStream* cfs = stream(); AnnotationArray* method_annotations = NULL; AnnotationArray* method_parameter_annotations = NULL; AnnotationArray* method_default_annotations = NULL; cfs->guarantee_more(2, CHECK_NULL); // length u2 length = cfs->get_u2_fast(); if (length == 0) { return Universe::the_empty_method_array(); } else { // FIXME: Handle leaks at later failures. Array<Method*>* methods = MetadataFactory::new_array<Method*>(loader_data, length, NULL, CHECK_NULL); HandleMark hm(THREAD); for (int index = 0; index < length; index++) { methodHandle method = parse_method(loader_data, cp, is_interface, promoted_flags, &method_annotations, &method_parameter_annotations, &method_default_annotations, CHECK_NULL); if (method->is_final()) { *has_final_method = true; } if (is_interface && !method->is_abstract() && !method->is_static()) { // default method *has_default_methods = true; } methods->at_put(index, method()); if (*methods_annotations == NULL) { *methods_annotations = MetadataFactory::new_array<AnnotationArray*>(loader_data, length, NULL, CHECK_NULL); } (*methods_annotations)->at_put(index, method_annotations); if (*methods_parameter_annotations == NULL) { *methods_parameter_annotations = MetadataFactory::new_array<AnnotationArray*>(loader_data, length, NULL, CHECK_NULL); } (*methods_parameter_annotations)->at_put(index, method_parameter_annotations); if (*methods_default_annotations == NULL) { *methods_default_annotations = MetadataFactory::new_array<AnnotationArray*>(loader_data, length, NULL, CHECK_NULL); } (*methods_default_annotations)->at_put(index, method_default_annotations); } if (_need_verify && length > 1) { // Check duplicated methods ResourceMark rm(THREAD); NameSigHash** names_and_sigs = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, NameSigHash*, HASH_ROW_SIZE); initialize_hashtable(names_and_sigs); bool dup = false; { debug_only(No_Safepoint_Verifier nsv;) for (int i = 0; i < length; i++) { Method* m = methods->at(i); // If no duplicates, add name/signature in hashtable names_and_sigs. if (!put_after_lookup(m->name(), m->signature(), names_and_sigs)) { dup = true; break; } } } if (dup) { classfile_parse_error("Duplicate method name&signature in class file %s", CHECK_NULL); } } return methods; } } Array<int>* ClassFileParser::sort_methods(ClassLoaderData* loader_data, Array<Method*>* methods, Array<AnnotationArray*>* methods_annotations, Array<AnnotationArray*>* methods_parameter_annotations, Array<AnnotationArray*>* methods_default_annotations, TRAPS) { int length = methods->length(); // If JVMTI original method ordering or sharing is enabled we have to // remember the original class file ordering. // We temporarily use the vtable_index field in the Method* to store the // class file index, so we can read in after calling qsort. // Put the method ordering in the shared archive. if (JvmtiExport::can_maintain_original_method_order() || DumpSharedSpaces) { for (int index = 0; index < length; index++) { Method* m = methods->at(index); assert(!m->valid_vtable_index(), "vtable index should not be set"); m->set_vtable_index(index); } } // 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); // If JVMTI original method ordering or sharing is enabled construct int // array remembering the original ordering if (JvmtiExport::can_maintain_original_method_order() || DumpSharedSpaces) { Array<int>* method_ordering = MetadataFactory::new_array<int>(loader_data, length, CHECK_NULL); for (int index = 0; index < length; index++) { Method* m = methods->at(index); int old_index = m->vtable_index(); assert(old_index >= 0 && old_index < length, "invalid method index"); method_ordering->at_put(index, old_index); m->set_vtable_index(Method::invalid_vtable_index); } return method_ordering; } else { return Universe::the_empty_int_array(); } } void ClassFileParser::parse_classfile_sourcefile_attribute(constantPoolHandle cp, TRAPS) { ClassFileStream* cfs = stream(); cfs->guarantee_more(2, CHECK); // sourcefile_index u2 sourcefile_index = cfs->get_u2_fast(); check_property( valid_cp_range(sourcefile_index, cp->length()) && cp->tag_at(sourcefile_index).is_utf8(), "Invalid SourceFile attribute at constant pool index %u in class file %s", sourcefile_index, CHECK); set_class_sourcefile(cp->symbol_at(sourcefile_index)); } void ClassFileParser::parse_classfile_source_debug_extension_attribute(constantPoolHandle cp, int length, TRAPS) { ClassFileStream* cfs = stream(); u1* sde_buffer = cfs->get_u1_buffer(); assert(sde_buffer != NULL, "null sde buffer"); // Don't bother storing it if there is no way to retrieve it if (JvmtiExport::can_get_source_debug_extension()) { assert((length+1) > length, "Overflow checking"); u1* sde = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, u1, length+1); for (int i = 0; i < length; i++) { sde[i] = sde_buffer[i]; } sde[length] = '\0'; set_class_sde_buffer((char*)sde, length); } // Got utf8 string, set stream position forward cfs->skip_u1(length, CHECK); } // Inner classes can be static, private or protected (classic VM does this) #define RECOGNIZED_INNER_CLASS_MODIFIERS (JVM_RECOGNIZED_CLASS_MODIFIERS | JVM_ACC_PRIVATE | JVM_ACC_PROTECTED | JVM_ACC_STATIC) // Return number of classes in the inner classes attribute table u2 ClassFileParser::parse_classfile_inner_classes_attribute(ClassLoaderData* loader_data, u1* inner_classes_attribute_start, bool parsed_enclosingmethod_attribute, u2 enclosing_method_class_index, u2 enclosing_method_method_index, constantPoolHandle cp, TRAPS) { ClassFileStream* cfs = stream(); u1* current_mark = cfs->current(); u2 length = 0; if (inner_classes_attribute_start != NULL) { cfs->set_current(inner_classes_attribute_start); cfs->guarantee_more(2, CHECK_0); // length length = cfs->get_u2_fast(); } // 4-tuples of shorts of inner classes data and 2 shorts of enclosing // method data: // [inner_class_info_index, // outer_class_info_index, // inner_name_index, // inner_class_access_flags, // ... // enclosing_method_class_index, // enclosing_method_method_index] int size = length * 4 + (parsed_enclosingmethod_attribute ? 2 : 0); // FIXME: Will leak on exceptions. Array<u2>* inner_classes = MetadataFactory::new_array<u2>(loader_data, size, CHECK_0); int index = 0; int cp_size = cp->length(); cfs->guarantee_more(8 * length, CHECK_0); // 4-tuples of u2 for (int n = 0; n < length; n++) { // Inner class index u2 inner_class_info_index = cfs->get_u2_fast(); check_property( inner_class_info_index == 0 || (valid_cp_range(inner_class_info_index, cp_size) && is_klass_reference(cp, inner_class_info_index)), "inner_class_info_index %u has bad constant type in class file %s", inner_class_info_index, CHECK_0); // Outer class index u2 outer_class_info_index = cfs->get_u2_fast(); check_property( outer_class_info_index == 0 || (valid_cp_range(outer_class_info_index, cp_size) && is_klass_reference(cp, outer_class_info_index)), "outer_class_info_index %u has bad constant type in class file %s", outer_class_info_index, CHECK_0); // Inner class name u2 inner_name_index = cfs->get_u2_fast(); check_property( inner_name_index == 0 || (valid_cp_range(inner_name_index, cp_size) && cp->tag_at(inner_name_index).is_utf8()), "inner_name_index %u has bad constant type in class file %s", inner_name_index, CHECK_0); if (_need_verify) { guarantee_property(inner_class_info_index != outer_class_info_index, "Class is both outer and inner class in class file %s", CHECK_0); } // Access flags AccessFlags inner_access_flags; jint flags = cfs->get_u2_fast() & RECOGNIZED_INNER_CLASS_MODIFIERS; if ((flags & JVM_ACC_INTERFACE) && _major_version < JAVA_6_VERSION) { // Set abstract bit for old class files for backward compatibility flags |= JVM_ACC_ABSTRACT; } verify_legal_class_modifiers(flags, CHECK_0); inner_access_flags.set_flags(flags); inner_classes->at_put(index++, inner_class_info_index); inner_classes->at_put(index++, outer_class_info_index); inner_classes->at_put(index++, inner_name_index); inner_classes->at_put(index++, inner_access_flags.as_short()); } // 4347400: make sure there's no duplicate entry in the classes array if (_need_verify && _major_version >= JAVA_1_5_VERSION) { for(int i = 0; i < length * 4; i += 4) { for(int j = i + 4; j < length * 4; j += 4) { guarantee_property((inner_classes->at(i) != inner_classes->at(j) || inner_classes->at(i+1) != inner_classes->at(j+1) || inner_classes->at(i+2) != inner_classes->at(j+2) || inner_classes->at(i+3) != inner_classes->at(j+3)), "Duplicate entry in InnerClasses in class file %s", CHECK_0); } } } // Set EnclosingMethod class and method indexes. if (parsed_enclosingmethod_attribute) { inner_classes->at_put(index++, enclosing_method_class_index); inner_classes->at_put(index++, enclosing_method_method_index); } assert(index == size, "wrong size"); // Update InstanceKlass with inner class info. set_class_inner_classes(inner_classes); // Restore buffer's current position. cfs->set_current(current_mark); return length; } void ClassFileParser::parse_classfile_synthetic_attribute(constantPoolHandle cp, TRAPS) { set_class_synthetic_flag(true); } void ClassFileParser::parse_classfile_signature_attribute(constantPoolHandle cp, TRAPS) { ClassFileStream* cfs = stream(); u2 signature_index = cfs->get_u2(CHECK); check_property( valid_cp_range(signature_index, cp->length()) && cp->tag_at(signature_index).is_utf8(), "Invalid constant pool index %u in Signature attribute in class file %s", signature_index, CHECK); set_class_generic_signature(cp->symbol_at(signature_index)); } void ClassFileParser::parse_classfile_bootstrap_methods_attribute(ClassLoaderData* loader_data, constantPoolHandle cp, 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); Array<u2>* operands = MetadataFactory::new_array<u2>(loader_data, index_size + operand_count, CHECK); 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. ConstantPool::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", bootstrap_method_index, CHECK); operands->at_put(operand_fill_index++, bootstrap_method_index); operands->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 argument_index = cfs->get_u2_fast(); check_property( valid_cp_range(argument_index, cp_size) && cp->tag_at(argument_index).is_loadable_constant(), "argument_index %u has bad constant type in class file %s", argument_index, CHECK); operands->at_put(operand_fill_index++, argument_index); } } assert(operand_fill_index == operands->length(), "exact fill"); assert(ConstantPool::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(ClassLoaderData* loader_data, constantPoolHandle cp, ClassFileParser::ClassAnnotationCollector* parsed_annotations, TRAPS) { ClassFileStream* cfs = stream(); // Set inner classes attribute to default sentinel set_class_inner_classes(Universe::the_empty_short_array()); cfs->guarantee_more(2, CHECK); // attributes_count u2 attributes_count = cfs->get_u2_fast(); 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; int runtime_invisible_annotations_length = 0; u1* inner_classes_attribute_start = NULL; u4 inner_classes_attribute_length = 0; u2 enclosing_method_class_index = 0; u2 enclosing_method_method_index = 0; // Iterate over attributes while (attributes_count--) { cfs->guarantee_more(6, CHECK); // attribute_name_index, attribute_length u2 attribute_name_index = cfs->get_u2_fast(); u4 attribute_length = cfs->get_u4_fast(); check_property( valid_cp_range(attribute_name_index, cp->length()) && cp->tag_at(attribute_name_index).is_utf8(), "Attribute name has bad constant pool index %u in class file %s", attribute_name_index, CHECK); Symbol* tag = cp->symbol_at(attribute_name_index); if (tag == vmSymbols::tag_source_file()) { // Check for SourceFile tag if (_need_verify) { guarantee_property(attribute_length == 2, "Wrong SourceFile attribute length in class file %s", CHECK); } if (parsed_sourcefile_attribute) { classfile_parse_error("Multiple SourceFile attributes in class file %s", CHECK); } else { parsed_sourcefile_attribute = true; } parse_classfile_sourcefile_attribute(cp, CHECK); } else if (tag == vmSymbols::tag_source_debug_extension()) { // Check for SourceDebugExtension tag parse_classfile_source_debug_extension_attribute(cp, (int)attribute_length, CHECK); } else if (tag == vmSymbols::tag_inner_classes()) { // Check for InnerClasses tag if (parsed_innerclasses_attribute) { classfile_parse_error("Multiple InnerClasses attributes in class file %s", CHECK); } else { parsed_innerclasses_attribute = true; } inner_classes_attribute_start = cfs->get_u1_buffer(); inner_classes_attribute_length = attribute_length; cfs->skip_u1(inner_classes_attribute_length, CHECK); } else if (tag == vmSymbols::tag_synthetic()) { // Check for Synthetic tag // Shouldn't we check that the synthetic flags wasn't already set? - not required in spec if (attribute_length != 0) { classfile_parse_error( "Invalid Synthetic classfile attribute length %u in class file %s", attribute_length, CHECK); } parse_classfile_synthetic_attribute(cp, CHECK); } else if (tag == vmSymbols::tag_deprecated()) { // Check for Deprecatd tag - 4276120 if (attribute_length != 0) { classfile_parse_error( "Invalid Deprecated classfile attribute length %u in class file %s", attribute_length, CHECK); } } else if (_major_version >= JAVA_1_5_VERSION) { if (tag == vmSymbols::tag_signature()) { if (attribute_length != 2) { classfile_parse_error( "Wrong Signature attribute length %u in class file %s", attribute_length, CHECK); } parse_classfile_signature_attribute(cp, CHECK); } else if (tag == vmSymbols::tag_runtime_visible_annotations()) { runtime_visible_annotations_length = attribute_length; runtime_visible_annotations = cfs->get_u1_buffer(); assert(runtime_visible_annotations != NULL, "null visible annotations"); parse_annotations(runtime_visible_annotations, runtime_visible_annotations_length, cp, parsed_annotations, CHECK); cfs->skip_u1(runtime_visible_annotations_length, CHECK); } else if (PreserveAllAnnotations && tag == vmSymbols::tag_runtime_invisible_annotations()) { runtime_invisible_annotations_length = attribute_length; runtime_invisible_annotations = cfs->get_u1_buffer(); assert(runtime_invisible_annotations != NULL, "null invisible annotations"); cfs->skip_u1(runtime_invisible_annotations_length, CHECK); } else if (tag == vmSymbols::tag_enclosing_method()) { if (parsed_enclosingmethod_attribute) { classfile_parse_error("Multiple EnclosingMethod attributes in class file %s", CHECK); } else { parsed_enclosingmethod_attribute = true; } cfs->guarantee_more(4, CHECK); // class_index, method_index enclosing_method_class_index = cfs->get_u2_fast(); enclosing_method_method_index = cfs->get_u2_fast(); if (enclosing_method_class_index == 0) { classfile_parse_error("Invalid class index in EnclosingMethod attribute in class file %s", CHECK); } // Validate the constant pool indices and types if (!cp->is_within_bounds(enclosing_method_class_index) || !is_klass_reference(cp, enclosing_method_class_index)) { classfile_parse_error("Invalid or out-of-bounds class index in EnclosingMethod attribute in class file %s", CHECK); } if (enclosing_method_method_index != 0 && (!cp->is_within_bounds(enclosing_method_method_index) || !cp->tag_at(enclosing_method_method_index).is_name_and_type())) { classfile_parse_error("Invalid or out-of-bounds method index in EnclosingMethod attribute in class file %s", CHECK); } } 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(loader_data, cp, attribute_length, CHECK); } else { // Unknown attribute cfs->skip_u1(attribute_length, CHECK); } } else { // Unknown attribute cfs->skip_u1(attribute_length, CHECK); } } AnnotationArray* annotations = assemble_annotations(loader_data, runtime_visible_annotations, runtime_visible_annotations_length, runtime_invisible_annotations, runtime_invisible_annotations_length, CHECK); set_class_annotations(annotations); if (parsed_innerclasses_attribute || parsed_enclosingmethod_attribute) { u2 num_of_classes = parse_classfile_inner_classes_attribute( loader_data, inner_classes_attribute_start, parsed_innerclasses_attribute, enclosing_method_class_index, enclosing_method_method_index, cp, CHECK); if (parsed_innerclasses_attribute &&_need_verify && _major_version >= JAVA_1_5_VERSION) { guarantee_property( inner_classes_attribute_length == sizeof(num_of_classes) + 4 * sizeof(u2) * num_of_classes, "Wrong InnerClasses attribute length in class file %s", CHECK); } } if (_max_bootstrap_specifier_index >= 0) { guarantee_property(parsed_bootstrap_methods_attribute, "Missing BootstrapMethods attribute in class file %s", CHECK); } } void ClassFileParser::apply_parsed_class_attributes(instanceKlassHandle k) { if (_synthetic_flag) k->set_is_synthetic(); if (_sourcefile != NULL) { _sourcefile->increment_refcount(); k->set_source_file_name(_sourcefile); } if (_generic_signature != NULL) { _generic_signature->increment_refcount(); k->set_generic_signature(_generic_signature); } if (_sde_buffer != NULL) { 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, u1* runtime_visible_annotations, int runtime_visible_annotations_length, u1* runtime_invisible_annotations, int runtime_invisible_annotations_length, TRAPS) { AnnotationArray* annotations = NULL; if (runtime_visible_annotations != NULL || runtime_invisible_annotations != NULL) { annotations = MetadataFactory::new_array<u1>(loader_data, runtime_visible_annotations_length + runtime_invisible_annotations_length, CHECK_(annotations)); if (runtime_visible_annotations != NULL) { for (int i = 0; i < runtime_visible_annotations_length; i++) { annotations->at_put(i, runtime_visible_annotations[i]); } } if (runtime_invisible_annotations != NULL) { for (int i = 0; i < runtime_invisible_annotations_length; i++) { int append = runtime_visible_annotations_length+i; annotations->at_put(append, runtime_invisible_annotations[i]); } } } return annotations; } #ifndef PRODUCT static void parseAndPrintGenericSignatures( instanceKlassHandle this_klass, TRAPS) { assert(ParseAllGenericSignatures == true, "Shouldn't call otherwise"); ResourceMark rm; if (this_klass->generic_signature() != NULL) { using namespace generic; ClassDescriptor* spec = ClassDescriptor::parse_generic_signature(this_klass(), CHECK); tty->print_cr("Parsing %s", this_klass->generic_signature()->as_C_string()); spec->print_on(tty); for (int i = 0; i < this_klass->methods()->length(); ++i) { Method* m = this_klass->methods()->at(i); MethodDescriptor* method_spec = MethodDescriptor::parse_generic_signature(m, spec); Symbol* sig = m->generic_signature(); if (sig == NULL) { sig = m->signature(); } tty->print_cr("Parsing %s", sig->as_C_string()); method_spec->print_on(tty); } } } #endif // ndef PRODUCT instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, Handle class_loader, Handle protection_domain, KlassHandle host_klass, GrowableArray<Handle>* cp_patches, TempNewSymbol& parsed_name, bool verify, TRAPS) { // When a retransformable agent is attached, JVMTI caches the // class bytes that existed before the first retransformation. // If RedefineClasses() was used before the retransformable // agent attached, then the cached class bytes may not be the // original class bytes. unsigned char *cached_class_file_bytes = NULL; jint cached_class_file_length; ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(class_loader()); bool has_default_methods = false; ResourceMark rm(THREAD); ClassFileStream* cfs = stream(); // Timing assert(THREAD->is_Java_thread(), "must be a JavaThread"); JavaThread* jt = (JavaThread*) THREAD; PerfClassTraceTime ctimer(ClassLoader::perf_class_parse_time(), ClassLoader::perf_class_parse_selftime(), NULL, jt->get_thread_stat()->perf_recursion_counts_addr(), jt->get_thread_stat()->perf_timers_addr(), PerfClassTraceTime::PARSE_CLASS); init_parsed_class_attributes(); if (JvmtiExport::should_post_class_file_load_hook()) { // Get the cached class file bytes (if any) from the class that // is being redefined or retransformed. We use jvmti_thread_state() // instead of JvmtiThreadState::state_for(jt) so we don't allocate // a JvmtiThreadState any earlier than necessary. This will help // avoid the bug described by 7126851. JvmtiThreadState *state = jt->jvmti_thread_state(); if (state != NULL) { KlassHandle *h_class_being_redefined = state->get_class_being_redefined(); if (h_class_being_redefined != NULL) { instanceKlassHandle ikh_class_being_redefined = instanceKlassHandle(THREAD, (*h_class_being_redefined)()); cached_class_file_bytes = ikh_class_being_redefined->get_cached_class_file_bytes(); cached_class_file_length = ikh_class_being_redefined->get_cached_class_file_len(); } } unsigned char* ptr = cfs->buffer(); unsigned char* end_ptr = cfs->buffer() + cfs->length(); JvmtiExport::post_class_file_load_hook(name, class_loader, protection_domain, &ptr, &end_ptr, &cached_class_file_bytes, &cached_class_file_length); if (ptr != cfs->buffer()) { // JVMTI agent has modified class file data. // Set new class file stream using JVMTI agent modified // class file data. cfs = new ClassFileStream(ptr, end_ptr - ptr, cfs->source()); set_stream(cfs); } } _host_klass = host_klass; _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(), verify); // Set the verify flag in stream cfs->set_verify(_need_verify); // Save the class file name for easier error message printing. _class_name = (name != NULL) ? name : vmSymbols::unknown_class_name(); cfs->guarantee_more(8, CHECK_(nullHandle)); // magic, major, minor // Magic value u4 magic = cfs->get_u4_fast(); guarantee_property(magic == JAVA_CLASSFILE_MAGIC, "Incompatible magic value %u in class file %s", magic, CHECK_(nullHandle)); // Version numbers u2 minor_version = cfs->get_u2_fast(); u2 major_version = cfs->get_u2_fast(); // Check version numbers - we check this even with verifier off if (!is_supported_version(major_version, minor_version)) { if (name == NULL) { Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_UnsupportedClassVersionError(), "Unsupported major.minor version %u.%u", major_version, minor_version); } else { ResourceMark rm(THREAD); Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_UnsupportedClassVersionError(), "%s : Unsupported major.minor version %u.%u", name->as_C_string(), major_version, minor_version); } return nullHandle; } _major_version = major_version; _minor_version = minor_version; // Check if verification needs to be relaxed for this class file // Do not restrict it to jdk1.0 or jdk1.1 to maintain backward compatibility (4982376) _relax_verify = Verifier::relax_verify_for(class_loader()); // Constant pool constantPoolHandle cp = parse_constant_pool(loader_data, CHECK_(nullHandle)); ConstantPoolCleaner error_handler(cp); // set constant pool to be cleaned up. int cp_size = cp->length(); cfs->guarantee_more(8, CHECK_(nullHandle)); // flags, this_class, super_class, infs_len // Access flags AccessFlags access_flags; jint flags = cfs->get_u2_fast() & JVM_RECOGNIZED_CLASS_MODIFIERS; if ((flags & JVM_ACC_INTERFACE) && _major_version < JAVA_6_VERSION) { // Set abstract bit for old class files for backward compatibility flags |= JVM_ACC_ABSTRACT; } verify_legal_class_modifiers(flags, CHECK_(nullHandle)); access_flags.set_flags(flags); // This class and superclass instanceKlassHandle super_klass; u2 this_class_index = cfs->get_u2_fast(); check_property( valid_cp_range(this_class_index, cp_size) && cp->tag_at(this_class_index).is_unresolved_klass(), "Invalid this class index %u in constant pool in class file %s", this_class_index, CHECK_(nullHandle)); Symbol* class_name = cp->unresolved_klass_at(this_class_index); assert(class_name != NULL, "class_name can't be null"); // It's important to set parsed_name *before* resolving the super class. // (it's used for cleanup by the caller if parsing fails) parsed_name = class_name; // parsed_name is returned and can be used if there's an error, so add to // its reference count. Caller will decrement the refcount. parsed_name->increment_refcount(); // Update _class_name which could be null previously to be class_name _class_name = class_name; // Don't need to check whether this class name is legal or not. // It has been checked when constant pool is parsed. // However, make sure it is not an array type. if (_need_verify) { guarantee_property(class_name->byte_at(0) != JVM_SIGNATURE_ARRAY, "Bad class name in class file %s", CHECK_(nullHandle)); } Klass* preserve_this_klass; // for storing result across HandleMark // release all handles when parsing is done { HandleMark hm(THREAD); // Checks if name in class file matches requested name if (name != NULL && class_name != name) { ResourceMark rm(THREAD); Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_NoClassDefFoundError(), "%s (wrong name: %s)", name->as_C_string(), class_name->as_C_string() ); return nullHandle; } if (TraceClassLoadingPreorder) { tty->print("[Loading %s", name->as_klass_external_name()); if (cfs->source() != NULL) tty->print(" from %s", cfs->source()); tty->print_cr("]"); } u2 super_class_index = cfs->get_u2_fast(); if (super_class_index == 0) { check_property(class_name == vmSymbols::java_lang_Object(), "Invalid superclass index %u in class file %s", super_class_index, CHECK_(nullHandle)); } else { check_property(valid_cp_range(super_class_index, cp_size) && is_klass_reference(cp, super_class_index), "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(!is_array, "Bad superclass name in class file %s", CHECK_(nullHandle)); } } // Interfaces u2 itfs_len = cfs->get_u2_fast(); Array<Klass*>* local_interfaces; if (itfs_len == 0) { local_interfaces = Universe::the_empty_klass_array(); } else { local_interfaces = parse_interfaces( cp, itfs_len, loader_data, protection_domain, _class_name, &has_default_methods, CHECK_(nullHandle)); } u2 java_fields_count = 0; // Fields (offsets are filled in later) FieldAllocationCount fac; Array<AnnotationArray*>* fields_annotations = NULL; Array<u2>* fields = parse_fields(loader_data, class_name, cp, access_flags.is_interface(), &fac, &fields_annotations, &java_fields_count, CHECK_(nullHandle)); // Methods bool has_final_method = false; AccessFlags promoted_flags; promoted_flags.set_flags(0); // These need to be oop pointers because they are allocated lazily // inside parse_methods inside a nested HandleMark Array<AnnotationArray*>* methods_annotations = NULL; Array<AnnotationArray*>* methods_parameter_annotations = NULL; Array<AnnotationArray*>* methods_default_annotations = NULL; Array<Method*>* methods = parse_methods(loader_data, cp, access_flags.is_interface(), &promoted_flags, &has_final_method, &methods_annotations, &methods_parameter_annotations, &methods_default_annotations, &has_default_methods, CHECK_(nullHandle)); // Additional attributes ClassAnnotationCollector parsed_annotations; parse_classfile_attributes(loader_data, cp, &parsed_annotations, CHECK_(nullHandle)); // Make sure this is the end of class file stream guarantee_property(cfs->at_eos(), "Extra bytes at the end of class file %s", CHECK_(nullHandle)); // We check super class after class file is parsed and format is checked if (super_class_index > 0 && super_klass.is_null()) { Symbol* sk = 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(), "Interfaces must have java.lang.Object as superclass in class file %s", CHECK_(nullHandle)); } Klass* k = SystemDictionary::resolve_super_or_fail(class_name, sk, class_loader, protection_domain, true, CHECK_(nullHandle)); KlassHandle kh (THREAD, k); super_klass = instanceKlassHandle(THREAD, kh()); } if (super_klass.not_null()) { if (super_klass->has_default_methods()) { has_default_methods = true; } if (super_klass->is_interface()) { ResourceMark rm(THREAD); Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_IncompatibleClassChangeError(), "class %s has interface %s as super class", class_name->as_klass_external_name(), super_klass->external_name() ); return nullHandle; } // Make sure super class is not final if (super_klass->is_final()) { THROW_MSG_(vmSymbols::java_lang_VerifyError(), "Cannot inherit from final class", nullHandle); } } // Compute the transitive list of all unique interfaces implemented by this class Array<Klass*>* transitive_interfaces = compute_transitive_interfaces(loader_data, super_klass, local_interfaces, CHECK_(nullHandle)); // sort methods Array<int>* method_ordering = sort_methods(loader_data, methods, methods_annotations, methods_parameter_annotations, methods_default_annotations, CHECK_(nullHandle)); // promote flags from parse_methods() to the klass' flags access_flags.add_promoted_flags(promoted_flags.as_int()); // Size of Java vtable (in words) int vtable_size = 0; int itable_size = 0; int num_miranda_methods = 0; GrowableArray<Method*> all_mirandas(20); klassVtable::compute_vtable_size_and_num_mirandas( &vtable_size, &num_miranda_methods, &all_mirandas, super_klass(), methods, access_flags, class_loader, class_name, local_interfaces, CHECK_(nullHandle)); // Size of Java itable (in words) itable_size = access_flags.is_interface() ? 0 : klassItable::compute_itable_size(transitive_interfaces); // Field size and offset computation int nonstatic_field_size = super_klass() == NULL ? 0 : super_klass->nonstatic_field_size(); #ifndef PRODUCT int orig_nonstatic_field_size = 0; #endif int static_field_size = 0; int next_static_oop_offset; int next_static_double_offset; int next_static_word_offset; int next_static_short_offset; int next_static_byte_offset; int next_static_type_offset; int next_nonstatic_oop_offset; int next_nonstatic_double_offset; int next_nonstatic_word_offset; int next_nonstatic_short_offset; int next_nonstatic_byte_offset; int next_nonstatic_type_offset; int first_nonstatic_oop_offset; int first_nonstatic_field_offset; int next_nonstatic_field_offset; // Calculate the starting byte offsets next_static_oop_offset = InstanceMirrorKlass::offset_of_static_fields(); next_static_double_offset = next_static_oop_offset + (fac.count[STATIC_OOP] * heapOopSize); if ( fac.count[STATIC_DOUBLE] && (Universe::field_type_should_be_aligned(T_DOUBLE) || Universe::field_type_should_be_aligned(T_LONG)) ) { next_static_double_offset = align_size_up(next_static_double_offset, BytesPerLong); } next_static_word_offset = next_static_double_offset + (fac.count[STATIC_DOUBLE] * BytesPerLong); next_static_short_offset = next_static_word_offset + (fac.count[STATIC_WORD] * BytesPerInt); next_static_byte_offset = next_static_short_offset + (fac.count[STATIC_SHORT] * BytesPerShort); next_static_type_offset = align_size_up((next_static_byte_offset + fac.count[STATIC_BYTE] ), wordSize ); static_field_size = (next_static_type_offset - next_static_oop_offset) / wordSize; first_nonstatic_field_offset = instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size * heapOopSize; next_nonstatic_field_offset = first_nonstatic_field_offset; unsigned int nonstatic_double_count = fac.count[NONSTATIC_DOUBLE]; unsigned int nonstatic_word_count = fac.count[NONSTATIC_WORD]; unsigned int nonstatic_short_count = fac.count[NONSTATIC_SHORT]; unsigned int nonstatic_byte_count = fac.count[NONSTATIC_BYTE]; unsigned int nonstatic_oop_count = fac.count[NONSTATIC_OOP]; bool super_has_nonstatic_fields = (super_klass() != NULL && super_klass->has_nonstatic_fields()); bool has_nonstatic_fields = super_has_nonstatic_fields || ((nonstatic_double_count + nonstatic_word_count + nonstatic_short_count + nonstatic_byte_count + nonstatic_oop_count) != 0); // Prepare list of oops for oop map generation. int* nonstatic_oop_offsets; unsigned int* nonstatic_oop_counts; unsigned int nonstatic_oop_map_count = 0; nonstatic_oop_offsets = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, int, nonstatic_oop_count + 1); nonstatic_oop_counts = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, unsigned int, nonstatic_oop_count + 1); first_nonstatic_oop_offset = 0; // will be set for first oop field #ifndef PRODUCT if( PrintCompactFieldsSavings ) { next_nonstatic_double_offset = next_nonstatic_field_offset + (nonstatic_oop_count * heapOopSize); if ( nonstatic_double_count > 0 ) { next_nonstatic_double_offset = align_size_up(next_nonstatic_double_offset, BytesPerLong); } next_nonstatic_word_offset = next_nonstatic_double_offset + (nonstatic_double_count * BytesPerLong); next_nonstatic_short_offset = next_nonstatic_word_offset + (nonstatic_word_count * BytesPerInt); next_nonstatic_byte_offset = next_nonstatic_short_offset + (nonstatic_short_count * BytesPerShort); next_nonstatic_type_offset = align_size_up((next_nonstatic_byte_offset + nonstatic_byte_count ), heapOopSize ); orig_nonstatic_field_size = nonstatic_field_size + ((next_nonstatic_type_offset - first_nonstatic_field_offset)/heapOopSize); } #endif bool compact_fields = CompactFields; int allocation_style = FieldsAllocationStyle; if( allocation_style < 0 || allocation_style > 2 ) { // Out of range? assert(false, "0 <= FieldsAllocationStyle <= 2"); allocation_style = 1; // Optimistic } // The next classes have predefined hard-coded fields offsets // (see in JavaClasses::compute_hard_coded_offsets()). // Use default fields allocation order for them. if( (allocation_style != 0 || compact_fields ) && class_loader.is_null() && (class_name == vmSymbols::java_lang_AssertionStatusDirectives() || class_name == vmSymbols::java_lang_Class() || class_name == vmSymbols::java_lang_ClassLoader() || class_name == vmSymbols::java_lang_ref_Reference() || class_name == vmSymbols::java_lang_ref_SoftReference() || class_name == vmSymbols::java_lang_StackTraceElement() || class_name == vmSymbols::java_lang_String() || class_name == vmSymbols::java_lang_Throwable() || class_name == vmSymbols::java_lang_Boolean() || class_name == vmSymbols::java_lang_Character() || class_name == vmSymbols::java_lang_Float() || class_name == vmSymbols::java_lang_Double() || class_name == vmSymbols::java_lang_Byte() || class_name == vmSymbols::java_lang_Short() || class_name == vmSymbols::java_lang_Integer() || class_name == vmSymbols::java_lang_Long())) { allocation_style = 0; // Allocate oops first compact_fields = false; // Don't compact fields } if( allocation_style == 0 ) { // Fields order: oops, longs/doubles, ints, shorts/chars, bytes next_nonstatic_oop_offset = next_nonstatic_field_offset; next_nonstatic_double_offset = next_nonstatic_oop_offset + (nonstatic_oop_count * heapOopSize); } else if( allocation_style == 1 ) { // Fields order: longs/doubles, ints, shorts/chars, bytes, oops next_nonstatic_double_offset = next_nonstatic_field_offset; } else if( allocation_style == 2 ) { // Fields allocation: oops fields in super and sub classes are together. if( nonstatic_field_size > 0 && super_klass() != NULL && super_klass->nonstatic_oop_map_size() > 0 ) { int map_count = super_klass->nonstatic_oop_map_count(); OopMapBlock* first_map = super_klass->start_of_nonstatic_oop_maps(); OopMapBlock* last_map = first_map + map_count - 1; int next_offset = last_map->offset() + (last_map->count() * heapOopSize); if (next_offset == next_nonstatic_field_offset) { allocation_style = 0; // allocate oops first next_nonstatic_oop_offset = next_nonstatic_field_offset; next_nonstatic_double_offset = next_nonstatic_oop_offset + (nonstatic_oop_count * heapOopSize); } } if( allocation_style == 2 ) { allocation_style = 1; // allocate oops last next_nonstatic_double_offset = next_nonstatic_field_offset; } } else { ShouldNotReachHere(); } int nonstatic_oop_space_count = 0; int nonstatic_word_space_count = 0; int nonstatic_short_space_count = 0; int nonstatic_byte_space_count = 0; int nonstatic_oop_space_offset; int nonstatic_word_space_offset; int nonstatic_short_space_offset; int nonstatic_byte_space_offset; if( nonstatic_double_count > 0 ) { int offset = next_nonstatic_double_offset; next_nonstatic_double_offset = align_size_up(offset, BytesPerLong); if( compact_fields && offset != next_nonstatic_double_offset ) { // Allocate available fields into the gap before double field. int length = next_nonstatic_double_offset - offset; assert(length == BytesPerInt, ""); nonstatic_word_space_offset = offset; if( nonstatic_word_count > 0 ) { nonstatic_word_count -= 1; nonstatic_word_space_count = 1; // Only one will fit length -= BytesPerInt; offset += BytesPerInt; } nonstatic_short_space_offset = offset; while( length >= BytesPerShort && nonstatic_short_count > 0 ) { nonstatic_short_count -= 1; nonstatic_short_space_count += 1; length -= BytesPerShort; offset += BytesPerShort; } nonstatic_byte_space_offset = offset; while( length > 0 && nonstatic_byte_count > 0 ) { nonstatic_byte_count -= 1; nonstatic_byte_space_count += 1; length -= 1; } // Allocate oop field in the gap if there are no other fields for that. nonstatic_oop_space_offset = offset; if( length >= heapOopSize && nonstatic_oop_count > 0 && allocation_style != 0 ) { // when oop fields not first nonstatic_oop_count -= 1; nonstatic_oop_space_count = 1; // Only one will fit length -= heapOopSize; offset += heapOopSize; } } } next_nonstatic_word_offset = next_nonstatic_double_offset + (nonstatic_double_count * BytesPerLong); next_nonstatic_short_offset = next_nonstatic_word_offset + (nonstatic_word_count * BytesPerInt); next_nonstatic_byte_offset = next_nonstatic_short_offset + (nonstatic_short_count * BytesPerShort); int notaligned_offset; if( allocation_style == 0 ) { notaligned_offset = next_nonstatic_byte_offset + nonstatic_byte_count; } else { // allocation_style == 1 next_nonstatic_oop_offset = next_nonstatic_byte_offset + nonstatic_byte_count; if( nonstatic_oop_count > 0 ) { next_nonstatic_oop_offset = align_size_up(next_nonstatic_oop_offset, heapOopSize); } notaligned_offset = next_nonstatic_oop_offset + (nonstatic_oop_count * heapOopSize); } next_nonstatic_type_offset = align_size_up(notaligned_offset, heapOopSize ); nonstatic_field_size = nonstatic_field_size + ((next_nonstatic_type_offset - first_nonstatic_field_offset)/heapOopSize); // Iterate over fields again and compute correct offsets. // The field allocation type was temporarily stored in the offset slot. // oop fields are located before non-oop fields (static and non-static). for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { int real_offset; FieldAllocationType atype = (FieldAllocationType) fs.offset(); switch (atype) { case STATIC_OOP: real_offset = next_static_oop_offset; next_static_oop_offset += heapOopSize; break; case STATIC_BYTE: real_offset = next_static_byte_offset; next_static_byte_offset += 1; break; case STATIC_SHORT: real_offset = next_static_short_offset; next_static_short_offset += BytesPerShort; break; case STATIC_WORD: real_offset = next_static_word_offset; next_static_word_offset += BytesPerInt; break; case STATIC_DOUBLE: real_offset = next_static_double_offset; next_static_double_offset += BytesPerLong; break; case NONSTATIC_OOP: if( nonstatic_oop_space_count > 0 ) { real_offset = nonstatic_oop_space_offset; nonstatic_oop_space_offset += heapOopSize; nonstatic_oop_space_count -= 1; } else { real_offset = next_nonstatic_oop_offset; next_nonstatic_oop_offset += heapOopSize; } // Update oop maps if( nonstatic_oop_map_count > 0 && nonstatic_oop_offsets[nonstatic_oop_map_count - 1] == real_offset - int(nonstatic_oop_counts[nonstatic_oop_map_count - 1]) * heapOopSize ) { // Extend current oop map nonstatic_oop_counts[nonstatic_oop_map_count - 1] += 1; } else { // Create new oop map nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset; nonstatic_oop_counts [nonstatic_oop_map_count] = 1; nonstatic_oop_map_count += 1; if( first_nonstatic_oop_offset == 0 ) { // Undefined first_nonstatic_oop_offset = real_offset; } } break; case NONSTATIC_BYTE: if( nonstatic_byte_space_count > 0 ) { real_offset = nonstatic_byte_space_offset; nonstatic_byte_space_offset += 1; nonstatic_byte_space_count -= 1; } else { real_offset = next_nonstatic_byte_offset; next_nonstatic_byte_offset += 1; } break; case NONSTATIC_SHORT: if( nonstatic_short_space_count > 0 ) { real_offset = nonstatic_short_space_offset; nonstatic_short_space_offset += BytesPerShort; nonstatic_short_space_count -= 1; } else { real_offset = next_nonstatic_short_offset; next_nonstatic_short_offset += BytesPerShort; } break; case NONSTATIC_WORD: if( nonstatic_word_space_count > 0 ) { real_offset = nonstatic_word_space_offset; nonstatic_word_space_offset += BytesPerInt; nonstatic_word_space_count -= 1; } else { real_offset = next_nonstatic_word_offset; next_nonstatic_word_offset += BytesPerInt; } break; case NONSTATIC_DOUBLE: real_offset = next_nonstatic_double_offset; next_nonstatic_double_offset += BytesPerLong; break; default: ShouldNotReachHere(); } fs.set_offset(real_offset); } // Size of instances int instance_size; next_nonstatic_type_offset = align_size_up(notaligned_offset, wordSize ); instance_size = align_object_size(next_nonstatic_type_offset / wordSize); assert(instance_size == align_object_size(align_size_up((instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size*heapOopSize), wordSize) / wordSize), "consistent layout helper value"); // Number of non-static oop map blocks allocated at end of klass. 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) { rt = REF_NONE; } else { rt = super_klass->reference_type(); } // We can now create the basic Klass* for this klass int total_oop_map_size2 = InstanceKlass::nonstatic_oop_map_size(total_oop_map_count); Klass* ik = InstanceKlass::allocate_instance_klass(loader_data, vtable_size, itable_size, static_field_size, total_oop_map_size2, rt, access_flags, name, super_klass(), host_klass, CHECK_(nullHandle)); // Add all classes to our internal class loader list here, // including classes in the bootstrap (NULL) class loader. loader_data->add_class(ik); instanceKlassHandle this_klass (THREAD, ik); assert(this_klass->static_field_size() == static_field_size, "sanity"); assert(this_klass->nonstatic_oop_map_count() == total_oop_map_count, "sanity"); // Fill in information already parsed this_klass->set_should_verify_class(verify); jint lh = Klass::instance_layout_helper(instance_size, false); this_klass->set_layout_helper(lh); assert(this_klass->oop_is_instance(), "layout is correct"); assert(this_klass->size_helper() == instance_size, "correct size_helper"); // Not yet: supers are done below to support the new subtype-checking fields //this_klass->set_super(super_klass()); this_klass->set_class_loader_data(loader_data); this_klass->set_nonstatic_field_size(nonstatic_field_size); this_klass->set_has_nonstatic_fields(has_nonstatic_fields); this_klass->set_static_oop_field_count(fac.count[STATIC_OOP]); cp->set_pool_holder(this_klass()); error_handler.set_in_error(false); // turn off error handler for cp this_klass->set_constants(cp()); this_klass->set_local_interfaces(local_interfaces); this_klass->set_fields(fields, java_fields_count); this_klass->set_methods(methods); if (has_final_method) { this_klass->set_has_final_method(); } this_klass->set_method_ordering(method_ordering); // The InstanceKlass::_methods_jmethod_ids cache and the // InstanceKlass::_methods_cached_itable_indices cache are // both managed on the assumption that the initial cache // size is equal to the number of methods in the class. If // that changes, then InstanceKlass::idnum_can_increment() // has to be changed accordingly. this_klass->set_initial_method_idnum(methods->length()); this_klass->set_name(cp->klass_name_at(this_class_index)); if (is_anonymous()) // I am well known to myself cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve if (fields_annotations != NULL || methods_annotations != NULL || methods_parameter_annotations != NULL || methods_default_annotations != NULL) { // Allocate an annotation type if needed. 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); } this_klass->set_minor_version(minor_version); this_klass->set_major_version(major_version); this_klass->set_has_default_methods(has_default_methods); // Set up Method*::intrinsic_id as soon as we know the names of methods. // (We used to do this lazily, but now we query it in Rewriter, // which is eagerly done for every method, so we might as well do it now, // when everything is fresh in memory.) if (Method::klass_id_for_intrinsics(this_klass()) != vmSymbols::NO_SID) { for (int j = 0; j < methods->length(); j++) { methods->at(j)->init_intrinsic_id(); } } if (cached_class_file_bytes != NULL) { // JVMTI: we have an InstanceKlass now, tell it about the cached bytes this_klass->set_cached_class_file(cached_class_file_bytes, cached_class_file_length); } // 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); // Miranda methods if ((num_miranda_methods > 0) || // if this class introduced new miranda methods or (super_klass.not_null() && (super_klass->has_miranda_methods())) // super class exists and this class inherited miranda methods ) { this_klass->set_has_miranda_methods(); // then set a flag } this_klass->set_transitive_interfaces(transitive_interfaces); // Fill in information needed to compute superclasses. this_klass->initialize_supers(super_klass(), CHECK_(nullHandle)); // Initialize itable offset tables klassItable::setup_itable_offset_table(this_klass); // Compute transitive closure of interfaces this class implements // Do final class setup fill_oop_maps(this_klass, nonstatic_oop_map_count, nonstatic_oop_offsets, nonstatic_oop_counts); // Fill in has_finalizer, has_vanilla_constructor, and layout_helper set_precomputed_flags(this_klass); // reinitialize modifiers, using the InnerClasses attribute int computed_modifiers = this_klass->compute_modifier_flags(CHECK_(nullHandle)); this_klass->set_modifier_flags(computed_modifiers); // check if this class can access its super class check_super_class_access(this_klass, CHECK_(nullHandle)); // check if this class can access its superinterfaces check_super_interface_access(this_klass, CHECK_(nullHandle)); // check if this class overrides any final method check_final_method_override(this_klass, CHECK_(nullHandle)); // check that if this class is an interface then it doesn't have static methods if (this_klass->is_interface()) { check_illegal_static_method(this_klass, CHECK_(nullHandle)); } #ifdef ASSERT if (ParseAllGenericSignatures) { parseAndPrintGenericSignatures(this_klass, CHECK_(nullHandle)); } #endif // Generate any default methods - default methods are interface methods // that have a default implementation. This is new with Lambda project. if (has_default_methods && !access_flags.is_interface() && local_interfaces->length() > 0) { DefaultMethods::generate_default_methods( this_klass(), &all_mirandas, CHECK_(nullHandle)); } // Allocate mirror and initialize static fields java_lang_Class::create_mirror(this_klass, CHECK_(nullHandle)); // Allocate a simple java object for locking during class initialization. // This needs to be a java object because it can be held across a java call. typeArrayOop r = oopFactory::new_typeArray(T_INT, 0, CHECK_NULL); this_klass->set_init_lock(r); // TODO: Move these oops to the mirror this_klass->set_protection_domain(protection_domain()); // Update the loader_data graph. record_defined_class_dependencies(this_klass, CHECK_NULL); ClassLoadingService::notify_class_loaded(InstanceKlass::cast(this_klass()), false /* not shared class */); if (TraceClassLoading) { ResourceMark rm; // print in a single call to reduce interleaving of output if (cfs->source() != NULL) { tty->print("[Loaded %s from %s]\n", this_klass->external_name(), cfs->source()); } else if (class_loader.is_null()) { if (THREAD->is_Java_thread()) { Klass* caller = ((JavaThread*)THREAD)->security_get_caller_class(1); tty->print("[Loaded %s by instance of %s]\n", this_klass->external_name(), InstanceKlass::cast(caller)->external_name()); } else { tty->print("[Loaded %s]\n", this_klass->external_name()); } } else { tty->print("[Loaded %s from %s]\n", this_klass->external_name(), InstanceKlass::cast(class_loader->klass())->external_name()); } } if (TraceClassResolution) { ResourceMark rm; // print out the superclass. const char * from = Klass::cast(this_klass())->external_name(); if (this_klass->java_super() != NULL) { tty->print("RESOLVE %s %s (super)\n", from, InstanceKlass::cast(this_klass->java_super())->external_name()); } // print out each of the interface classes referred to by this class. Array<Klass*>* local_interfaces = this_klass->local_interfaces(); if (local_interfaces != NULL) { int length = local_interfaces->length(); for (int i = 0; i < length; i++) { Klass* k = local_interfaces->at(i); InstanceKlass* to_class = InstanceKlass::cast(k); const char * to = to_class->external_name(); tty->print("RESOLVE %s %s (interface)\n", from, to); } } } #ifndef PRODUCT if( PrintCompactFieldsSavings ) { ResourceMark rm; if( nonstatic_field_size < orig_nonstatic_field_size ) { tty->print("[Saved %d of %d bytes in %s]\n", (orig_nonstatic_field_size - nonstatic_field_size)*heapOopSize, orig_nonstatic_field_size*heapOopSize, this_klass->external_name()); } else if( nonstatic_field_size > orig_nonstatic_field_size ) { tty->print("[Wasted %d over %d bytes in %s]\n", (nonstatic_field_size - orig_nonstatic_field_size)*heapOopSize, orig_nonstatic_field_size*heapOopSize, this_klass->external_name()); } } #endif // preserve result across HandleMark preserve_this_klass = this_klass(); } // Create new handle outside HandleMark (might be needed for // Extended Class Redefinition) instanceKlassHandle this_klass (THREAD, preserve_this_klass); debug_only(this_klass->verify();) return this_klass; } unsigned int ClassFileParser::compute_oop_map_count(instanceKlassHandle super, unsigned int nonstatic_oop_map_count, int first_nonstatic_oop_offset) { unsigned int map_count = super.is_null() ? 0 : super->nonstatic_oop_map_count(); if (nonstatic_oop_map_count > 0) { // We have oops to add to map if (map_count == 0) { map_count = nonstatic_oop_map_count; } else { // Check whether we should add a new map block or whether the last one can // be extended OopMapBlock* const first_map = super->start_of_nonstatic_oop_maps(); OopMapBlock* const last_map = first_map + map_count - 1; int next_offset = last_map->offset() + last_map->count() * heapOopSize; if (next_offset == first_nonstatic_oop_offset) { // There is no gap bettwen superklass's last oop field and first // local oop field, merge maps. nonstatic_oop_map_count -= 1; } else { // Superklass didn't end with a oop field, add extra maps assert(next_offset < first_nonstatic_oop_offset, "just checking"); } map_count += nonstatic_oop_map_count; } } return map_count; } void ClassFileParser::fill_oop_maps(instanceKlassHandle k, unsigned int nonstatic_oop_map_count, int* nonstatic_oop_offsets, unsigned int* nonstatic_oop_counts) { OopMapBlock* this_oop_map = k->start_of_nonstatic_oop_maps(); const InstanceKlass* const super = k->superklass(); const unsigned int super_count = super ? super->nonstatic_oop_map_count() : 0; if (super_count > 0) { // Copy maps from superklass OopMapBlock* super_oop_map = super->start_of_nonstatic_oop_maps(); for (unsigned int i = 0; i < super_count; ++i) { *this_oop_map++ = *super_oop_map++; } } if (nonstatic_oop_map_count > 0) { if (super_count + nonstatic_oop_map_count > k->nonstatic_oop_map_count()) { // The counts differ because there is no gap between superklass's last oop // field and the first local oop field. Extend the last oop map copied // from the superklass instead of creating new one. nonstatic_oop_map_count--; nonstatic_oop_offsets++; this_oop_map--; this_oop_map->set_count(this_oop_map->count() + *nonstatic_oop_counts++); this_oop_map++; } // Add new map blocks, fill them while (nonstatic_oop_map_count-- > 0) { this_oop_map->set_offset(*nonstatic_oop_offsets++); this_oop_map->set_count(*nonstatic_oop_counts++); this_oop_map++; } assert(k->start_of_nonstatic_oop_maps() + k->nonstatic_oop_map_count() == this_oop_map, "sanity"); } } void ClassFileParser::set_precomputed_flags(instanceKlassHandle k) { Klass* super = k->super(); // Check if this klass has an empty finalize method (i.e. one with return bytecode only), // in which case we don't have to register objects as finalizable if (!_has_empty_finalizer) { if (_has_finalizer || (super != NULL && super->has_finalizer())) { k->set_has_finalizer(); } } #ifdef ASSERT bool f = false; Method* m = k->lookup_method(vmSymbols::finalize_method_name(), vmSymbols::void_method_signature()); if (m != NULL && !m->is_empty_method()) { f = true; } assert(f == k->has_finalizer(), "inconsistent has_finalizer"); #endif // Check if this klass supports the java.lang.Cloneable interface if (SystemDictionary::Cloneable_klass_loaded()) { if (k->is_subtype_of(SystemDictionary::Cloneable_klass())) { k->set_is_cloneable(); } } // Check if this klass has a vanilla default constructor if (super == NULL) { // java.lang.Object has empty default constructor k->set_has_vanilla_constructor(); } else { if (Klass::cast(super)->has_vanilla_constructor() && _has_vanilla_constructor) { k->set_has_vanilla_constructor(); } #ifdef ASSERT bool v = false; if (Klass::cast(super)->has_vanilla_constructor()) { Method* constructor = k->find_method(vmSymbols::object_initializer_name( ), vmSymbols::void_method_signature()); if (constructor != NULL && constructor->is_vanilla_constructor()) { v = true; } } assert(v == k->has_vanilla_constructor(), "inconsistent has_vanilla_constructor"); #endif } // If it cannot be fast-path allocated, set a bit in the layout helper. // See documentation of InstanceKlass::can_be_fastpath_allocated(). assert(k->size_helper() > 0, "layout_helper is initialized"); if ((!RegisterFinalizersAtInit && k->has_finalizer()) || k->is_abstract() || k->is_interface() || (k->name() == vmSymbols::java_lang_Class() && k->class_loader_data()->is_the_null_class_loader_data()) || k->size_helper() >= FastAllocateSizeLimit) { // Forbid fast-path allocation. jint lh = Klass::instance_layout_helper(k->size_helper(), true); k->set_layout_helper(lh); } } // Attach super classes and interface classes to class loader data void ClassFileParser::record_defined_class_dependencies(instanceKlassHandle defined_klass, TRAPS) { ClassLoaderData * defining_loader_data = defined_klass->class_loader_data(); if (defining_loader_data->is_the_null_class_loader_data()) { // Dependencies to null class loader data are implicit. return; } else { // add super class dependency Klass* super = defined_klass->super(); if (super != NULL) { defining_loader_data->record_dependency(super, CHECK); } // add super interface dependencies Array<Klass*>* local_interfaces = defined_klass->local_interfaces(); if (local_interfaces != NULL) { int length = local_interfaces->length(); for (int i = 0; i < length; i++) { defining_loader_data->record_dependency(local_interfaces->at(i), CHECK); } } } } // utility method for appending and array with check for duplicates void append_interfaces(GrowableArray<Klass*>* result, Array<Klass*>* ifs) { // iterate over new interfaces for (int i = 0; i < ifs->length(); i++) { Klass* e = ifs->at(i); assert(e->is_klass() && InstanceKlass::cast(e)->is_interface(), "just checking"); // add new interface result->append_if_missing(e); } } Array<Klass*>* ClassFileParser::compute_transitive_interfaces(ClassLoaderData* loader_data, instanceKlassHandle super, Array<Klass*>* local_ifs, TRAPS) { // Compute maximum size for transitive interfaces int max_transitive_size = 0; int super_size = 0; // Add superclass transitive interfaces size if (super.not_null()) { super_size = super->transitive_interfaces()->length(); max_transitive_size += super_size; } // Add local interfaces' super interfaces int local_size = local_ifs->length(); for (int i = 0; i < local_size; i++) { Klass* l = local_ifs->at(i); max_transitive_size += InstanceKlass::cast(l)->transitive_interfaces()->length(); } // Finally add local interfaces max_transitive_size += local_size; // Construct array if (max_transitive_size == 0) { // no interfaces, use canonicalized array return Universe::the_empty_klass_array(); } else if (max_transitive_size == super_size) { // no new local interfaces added, share superklass' transitive interface array return super->transitive_interfaces(); } else if (max_transitive_size == local_size) { // only local interfaces added, share local interface array return local_ifs; } else { ResourceMark rm; GrowableArray<Klass*>* result = new GrowableArray<Klass*>(max_transitive_size); // Copy down from superclass if (super.not_null()) { append_interfaces(result, super->transitive_interfaces()); } // Copy down from local interfaces' superinterfaces for (int i = 0; i < local_ifs->length(); i++) { Klass* l = local_ifs->at(i); append_interfaces(result, InstanceKlass::cast(l)->transitive_interfaces()); } // Finally add local interfaces append_interfaces(result, local_ifs); // length will be less than the max_transitive_size if duplicates were removed int length = result->length(); assert(length <= max_transitive_size, "just checking"); Array<Klass*>* new_result = MetadataFactory::new_array<Klass*>(loader_data, length, CHECK_NULL); for (int i = 0; i < length; i++) { Klass* e = result->at(i); assert(e != NULL, "just checking"); new_result->at_put(i, e); } return new_result; } } void ClassFileParser::check_super_class_access(instanceKlassHandle this_klass, TRAPS) { Klass* super = this_klass->super(); if ((super != NULL) && (!Reflection::verify_class_access(this_klass(), super, false))) { ResourceMark rm(THREAD); Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalAccessError(), "class %s cannot access its superclass %s", this_klass->external_name(), InstanceKlass::cast(super)->external_name() ); return; } } void ClassFileParser::check_super_interface_access(instanceKlassHandle this_klass, TRAPS) { Array<Klass*>* local_interfaces = this_klass->local_interfaces(); int lng = local_interfaces->length(); for (int i = lng - 1; i >= 0; i--) { Klass* k = local_interfaces->at(i); assert (k != NULL && Klass::cast(k)->is_interface(), "invalid interface"); if (!Reflection::verify_class_access(this_klass(), k, false)) { ResourceMark rm(THREAD); Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalAccessError(), "class %s cannot access its superinterface %s", this_klass->external_name(), InstanceKlass::cast(k)->external_name() ); return; } } } void ClassFileParser::check_final_method_override(instanceKlassHandle this_klass, TRAPS) { Array<Method*>* methods = this_klass->methods(); int num_methods = methods->length(); // go thru each method and check if it overrides a final method for (int index = 0; index < num_methods; index++) { Method* m = methods->at(index); // skip private, static and <init> methods if ((!m->is_private()) && (!m->is_static()) && (m->name() != vmSymbols::object_initializer_name())) { Symbol* name = m->name(); Symbol* signature = m->signature(); Klass* k = this_klass->super(); Method* super_m = NULL; while (k != NULL) { // skip supers that don't have final methods. if (k->has_final_method()) { // lookup a matching method in the super class hierarchy super_m = InstanceKlass::cast(k)->lookup_method(name, signature); if (super_m == NULL) { break; // didn't find any match; get out } if (super_m->is_final() && // matching method in super is final (Reflection::verify_field_access(this_klass(), super_m->method_holder(), super_m->method_holder(), super_m->access_flags(), false)) // this class can access super final method and therefore override ) { ResourceMark rm(THREAD); Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_VerifyError(), "class %s overrides final method %s.%s", this_klass->external_name(), name->as_C_string(), signature->as_C_string() ); return; } // continue to look from super_m's holder's super. k = super_m->method_holder()->super(); continue; } k = k->super(); } } } } // assumes that this_klass is an interface void ClassFileParser::check_illegal_static_method(instanceKlassHandle this_klass, TRAPS) { assert(this_klass->is_interface(), "not an interface"); Array<Method*>* methods = this_klass->methods(); int num_methods = methods->length(); for (int index = 0; index < num_methods; index++) { Method* m = methods->at(index); // if m is static and not the init method, throw a verify error if ((m->is_static()) && (m->name() != vmSymbols::class_initializer_name())) { ResourceMark rm(THREAD); Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_VerifyError(), "Illegal static method %s in interface %s", m->name()->as_C_string(), this_klass->external_name() ); return; } } } // utility methods for format checking void ClassFileParser::verify_legal_class_modifiers(jint flags, TRAPS) { if (!_need_verify) { return; } const bool is_interface = (flags & JVM_ACC_INTERFACE) != 0; const bool is_abstract = (flags & JVM_ACC_ABSTRACT) != 0; const bool is_final = (flags & JVM_ACC_FINAL) != 0; const bool is_super = (flags & JVM_ACC_SUPER) != 0; const bool is_enum = (flags & JVM_ACC_ENUM) != 0; const bool is_annotation = (flags & JVM_ACC_ANNOTATION) != 0; const bool major_gte_15 = _major_version >= JAVA_1_5_VERSION; if ((is_abstract && is_final) || (is_interface && !is_abstract) || (is_interface && major_gte_15 && (is_super || is_enum)) || (!is_interface && major_gte_15 && is_annotation)) { ResourceMark rm(THREAD); Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(), "Illegal class modifiers in class %s: 0x%X", _class_name->as_C_string(), flags ); return; } } bool ClassFileParser::has_illegal_visibility(jint flags) { const bool is_public = (flags & JVM_ACC_PUBLIC) != 0; const bool is_protected = (flags & JVM_ACC_PROTECTED) != 0; const bool is_private = (flags & JVM_ACC_PRIVATE) != 0; return ((is_public && is_protected) || (is_public && is_private) || (is_protected && is_private)); } bool ClassFileParser::is_supported_version(u2 major, u2 minor) { u2 max_version = JDK_Version::is_gte_jdk17x_version() ? JAVA_MAX_SUPPORTED_VERSION : (JDK_Version::is_gte_jdk16x_version() ? JAVA_6_VERSION : JAVA_1_5_VERSION); return (major >= JAVA_MIN_SUPPORTED_VERSION) && (major <= max_version) && ((major != max_version) || (minor <= JAVA_MAX_SUPPORTED_MINOR_VERSION)); } void ClassFileParser::verify_legal_field_modifiers( jint flags, bool is_interface, TRAPS) { if (!_need_verify) { return; } const bool is_public = (flags & JVM_ACC_PUBLIC) != 0; const bool is_protected = (flags & JVM_ACC_PROTECTED) != 0; const bool is_private = (flags & JVM_ACC_PRIVATE) != 0; const bool is_static = (flags & JVM_ACC_STATIC) != 0; const bool is_final = (flags & JVM_ACC_FINAL) != 0; const bool is_volatile = (flags & JVM_ACC_VOLATILE) != 0; const bool is_transient = (flags & JVM_ACC_TRANSIENT) != 0; const bool is_enum = (flags & JVM_ACC_ENUM) != 0; const bool major_gte_15 = _major_version >= JAVA_1_5_VERSION; bool is_illegal = false; if (is_interface) { if (!is_public || !is_static || !is_final || is_private || is_protected || is_volatile || is_transient || (major_gte_15 && is_enum)) { is_illegal = true; } } else { // not interface if (has_illegal_visibility(flags) || (is_final && is_volatile)) { is_illegal = true; } } if (is_illegal) { ResourceMark rm(THREAD); Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(), "Illegal field modifiers in class %s: 0x%X", _class_name->as_C_string(), flags); return; } } void ClassFileParser::verify_legal_method_modifiers( jint flags, bool is_interface, Symbol* name, TRAPS) { if (!_need_verify) { return; } const bool is_public = (flags & JVM_ACC_PUBLIC) != 0; const bool is_private = (flags & JVM_ACC_PRIVATE) != 0; const bool is_static = (flags & JVM_ACC_STATIC) != 0; const bool is_final = (flags & JVM_ACC_FINAL) != 0; const bool is_native = (flags & JVM_ACC_NATIVE) != 0; const bool is_abstract = (flags & JVM_ACC_ABSTRACT) != 0; const bool is_bridge = (flags & JVM_ACC_BRIDGE) != 0; const bool is_strict = (flags & JVM_ACC_STRICT) != 0; const bool is_synchronized = (flags & JVM_ACC_SYNCHRONIZED) != 0; const bool major_gte_15 = _major_version >= JAVA_1_5_VERSION; const bool major_gte_8 = _major_version >= JAVA_8_VERSION; const bool is_initializer = (name == vmSymbols::object_initializer_name()); bool is_illegal = false; if (is_interface) { if (!is_public || is_static || is_final || is_native || ((is_synchronized || is_strict) && major_gte_15 && (!major_gte_8 || is_abstract)) || (!major_gte_8 && !is_abstract)) { is_illegal = true; } } else { // not interface if (is_initializer) { if (is_static || is_final || is_synchronized || is_native || is_abstract || (major_gte_15 && is_bridge)) { is_illegal = true; } } else { // not initializer if (is_abstract) { if ((is_final || is_native || is_private || is_static || (major_gte_15 && (is_synchronized || is_strict)))) { is_illegal = true; } } if (has_illegal_visibility(flags)) { is_illegal = true; } } } if (is_illegal) { ResourceMark rm(THREAD); Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(), "Method %s in class %s has illegal modifiers: 0x%X", name->as_C_string(), _class_name->as_C_string(), flags); return; } } void ClassFileParser::verify_legal_utf8(const unsigned char* buffer, int length, TRAPS) { assert(_need_verify, "only called when _need_verify is true"); int i = 0; int count = length >> 2; for (int k=0; k<count; k++) { unsigned char b0 = buffer[i]; unsigned char b1 = buffer[i+1]; unsigned char b2 = buffer[i+2]; unsigned char b3 = buffer[i+3]; // For an unsigned char v, // (v | v - 1) is < 128 (highest bit 0) for 0 < v < 128; // (v | v - 1) is >= 128 (highest bit 1) for v == 0 or v >= 128. unsigned char res = b0 | b0 - 1 | b1 | b1 - 1 | b2 | b2 - 1 | b3 | b3 - 1; if (res >= 128) break; i += 4; } for(; i < length; i++) { unsigned short c; // no embedded zeros guarantee_property((buffer[i] != 0), "Illegal UTF8 string in constant pool in class file %s", CHECK); if(buffer[i] < 128) { continue; } if ((i + 5) < length) { // see if it's legal supplementary character if (UTF8::is_supplementary_character(&buffer[i])) { c = UTF8::get_supplementary_character(&buffer[i]); i += 5; continue; } } switch (buffer[i] >> 4) { default: break; case 0x8: case 0x9: case 0xA: case 0xB: case 0xF: classfile_parse_error("Illegal UTF8 string in constant pool in class file %s", CHECK); case 0xC: case 0xD: // 110xxxxx 10xxxxxx c = (buffer[i] & 0x1F) << 6; i++; if ((i < length) && ((buffer[i] & 0xC0) == 0x80)) { c += buffer[i] & 0x3F; if (_major_version <= 47 || c == 0 || c >= 0x80) { // for classes with major > 47, c must a null or a character in its shortest form break; } } classfile_parse_error("Illegal UTF8 string in constant pool in class file %s", CHECK); case 0xE: // 1110xxxx 10xxxxxx 10xxxxxx c = (buffer[i] & 0xF) << 12; i += 2; if ((i < length) && ((buffer[i-1] & 0xC0) == 0x80) && ((buffer[i] & 0xC0) == 0x80)) { c += ((buffer[i-1] & 0x3F) << 6) + (buffer[i] & 0x3F); if (_major_version <= 47 || c >= 0x800) { // for classes with major > 47, c must be in its shortest form break; } } classfile_parse_error("Illegal UTF8 string in constant pool in class file %s", CHECK); } // end of switch } // end of for } // Checks if name is a legal class name. void ClassFileParser::verify_legal_class_name(Symbol* name, TRAPS) { if (!_need_verify || _relax_verify) { return; } char buf[fixed_buffer_size]; char* bytes = name->as_utf8_flexible_buffer(THREAD, buf, fixed_buffer_size); unsigned int length = name->utf8_length(); bool legal = false; if (length > 0) { char* p; if (bytes[0] == JVM_SIGNATURE_ARRAY) { p = skip_over_field_signature(bytes, false, length, CHECK); legal = (p != NULL) && ((p - bytes) == (int)length); } else if (_major_version < JAVA_1_5_VERSION) { if (bytes[0] != '<') { p = skip_over_field_name(bytes, true, length); legal = (p != NULL) && ((p - bytes) == (int)length); } } else { // 4900761: relax the constraints based on JSR202 spec // Class names may be drawn from the entire Unicode character set. // Identifiers between '/' must be unqualified names. // The utf8 string has been verified when parsing cpool entries. legal = verify_unqualified_name(bytes, length, LegalClass); } } if (!legal) { ResourceMark rm(THREAD); Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(), "Illegal class name \"%s\" in class file %s", bytes, _class_name->as_C_string() ); return; } } // Checks if name is a legal field name. void ClassFileParser::verify_legal_field_name(Symbol* name, TRAPS) { if (!_need_verify || _relax_verify) { return; } char buf[fixed_buffer_size]; char* bytes = name->as_utf8_flexible_buffer(THREAD, buf, fixed_buffer_size); unsigned int length = name->utf8_length(); bool legal = false; if (length > 0) { if (_major_version < JAVA_1_5_VERSION) { if (bytes[0] != '<') { char* p = skip_over_field_name(bytes, false, length); legal = (p != NULL) && ((p - bytes) == (int)length); } } else { // 4881221: relax the constraints based on JSR202 spec legal = verify_unqualified_name(bytes, length, LegalField); } } if (!legal) { ResourceMark rm(THREAD); Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(), "Illegal field name \"%s\" in class %s", bytes, _class_name->as_C_string() ); return; } } // Checks if name is a legal method name. void ClassFileParser::verify_legal_method_name(Symbol* name, TRAPS) { if (!_need_verify || _relax_verify) { return; } assert(name != NULL, "method name is null"); char buf[fixed_buffer_size]; char* bytes = name->as_utf8_flexible_buffer(THREAD, buf, fixed_buffer_size); unsigned int length = name->utf8_length(); bool legal = false; if (length > 0) { if (bytes[0] == '<') { if (name == vmSymbols::object_initializer_name() || name == vmSymbols::class_initializer_name()) { legal = true; } } else if (_major_version < JAVA_1_5_VERSION) { char* p; p = skip_over_field_name(bytes, false, length); legal = (p != NULL) && ((p - bytes) == (int)length); } else { // 4881221: relax the constraints based on JSR202 spec legal = verify_unqualified_name(bytes, length, LegalMethod); } } if (!legal) { ResourceMark rm(THREAD); Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(), "Illegal method name \"%s\" in class %s", bytes, _class_name->as_C_string() ); return; } } // Checks if signature is a legal field signature. void ClassFileParser::verify_legal_field_signature(Symbol* name, Symbol* signature, TRAPS) { if (!_need_verify) { return; } char buf[fixed_buffer_size]; char* bytes = signature->as_utf8_flexible_buffer(THREAD, buf, fixed_buffer_size); unsigned int length = signature->utf8_length(); char* p = skip_over_field_signature(bytes, false, length, CHECK); if (p == NULL || (p - bytes) != (int)length) { throwIllegalSignature("Field", name, signature, CHECK); } } // Checks if signature is a legal method signature. // Returns number of parameters int ClassFileParser::verify_legal_method_signature(Symbol* name, Symbol* signature, TRAPS) { if (!_need_verify) { // make sure caller's args_size will be less than 0 even for non-static // method so it will be recomputed in compute_size_of_parameters(). return -2; } unsigned int args_size = 0; char buf[fixed_buffer_size]; char* p = signature->as_utf8_flexible_buffer(THREAD, buf, fixed_buffer_size); unsigned int length = signature->utf8_length(); char* nextp; // The first character must be a '(' if ((length > 0) && (*p++ == JVM_SIGNATURE_FUNC)) { length--; // Skip over legal field signatures nextp = skip_over_field_signature(p, false, length, CHECK_0); while ((length > 0) && (nextp != NULL)) { args_size++; if (p[0] == 'J' || p[0] == 'D') { args_size++; } length -= nextp - p; p = nextp; nextp = skip_over_field_signature(p, false, length, CHECK_0); } // The first non-signature thing better be a ')' if ((length > 0) && (*p++ == JVM_SIGNATURE_ENDFUNC)) { length--; if (name->utf8_length() > 0 && name->byte_at(0) == '<') { // All internal methods must return void if ((length == 1) && (p[0] == JVM_SIGNATURE_VOID)) { return args_size; } } else { // Now we better just have a return value nextp = skip_over_field_signature(p, true, length, CHECK_0); if (nextp && ((int)length == (nextp - p))) { return args_size; } } } } // Report error throwIllegalSignature("Method", name, signature, CHECK_0); return 0; } // Unqualified names may not contain the characters '.', ';', '[', or '/'. // Method names also may not contain the characters '<' or '>', unless <init> // or <clinit>. Note that method names may not be <init> or <clinit> in this // method. Because these names have been checked as special cases before // calling this method in verify_legal_method_name. bool ClassFileParser::verify_unqualified_name( char* name, unsigned int length, int type) { jchar ch; for (char* p = name; p != name + length; ) { ch = *p; if (ch < 128) { p++; if (ch == '.' || ch == ';' || ch == '[' ) { return false; // do not permit '.', ';', or '[' } if (type != LegalClass && ch == '/') { return false; // do not permit '/' unless it's class name } if (type == LegalMethod && (ch == '<' || ch == '>')) { return false; // do not permit '<' or '>' in method names } } else { char* tmp_p = UTF8::next(p, &ch); p = tmp_p; } } return true; } // Take pointer to a string. Skip over the longest part of the string that could // be taken as a fieldname. Allow '/' if slash_ok is true. // Return a pointer to just past the fieldname. // Return NULL if no fieldname at all was found, or in the case of slash_ok // being true, we saw consecutive slashes (meaning we were looking for a // qualified path but found something that was badly-formed). char* ClassFileParser::skip_over_field_name(char* name, bool slash_ok, unsigned int length) { char* p; jchar ch; jboolean last_is_slash = false; jboolean not_first_ch = false; for (p = name; p != name + length; not_first_ch = true) { char* old_p = p; ch = *p; if (ch < 128) { p++; // quick check for ascii if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_' || ch == '$') || (not_first_ch && ch >= '0' && ch <= '9')) { last_is_slash = false; continue; } if (slash_ok && ch == '/') { if (last_is_slash) { return NULL; // Don't permit consecutive slashes } last_is_slash = true; continue; } } else { jint unicode_ch; char* tmp_p = UTF8::next_character(p, &unicode_ch); p = tmp_p; last_is_slash = false; // Check if ch is Java identifier start or is Java identifier part // 4672820: call java.lang.Character methods directly without generating separate tables. EXCEPTION_MARK; instanceKlassHandle klass (THREAD, SystemDictionary::Character_klass()); // return value JavaValue result(T_BOOLEAN); // Set up the arguments to isJavaIdentifierStart and isJavaIdentifierPart JavaCallArguments args; args.push_int(unicode_ch); // public static boolean isJavaIdentifierStart(char ch); JavaCalls::call_static(&result, klass, vmSymbols::isJavaIdentifierStart_name(), vmSymbols::int_bool_signature(), &args, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return 0; } if (result.get_jboolean()) { continue; } if (not_first_ch) { // public static boolean isJavaIdentifierPart(char ch); JavaCalls::call_static(&result, klass, vmSymbols::isJavaIdentifierPart_name(), vmSymbols::int_bool_signature(), &args, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return 0; } if (result.get_jboolean()) { continue; } } } return (not_first_ch) ? old_p : NULL; } return (not_first_ch) ? p : NULL; } // Take pointer to a string. Skip over the longest part of the string that could // be taken as a field signature. Allow "void" if void_ok. // Return a pointer to just past the signature. // Return NULL if no legal signature is found. char* ClassFileParser::skip_over_field_signature(char* signature, bool void_ok, unsigned int length, TRAPS) { unsigned int array_dim = 0; while (length > 0) { switch (signature[0]) { case JVM_SIGNATURE_VOID: if (!void_ok) { return NULL; } case JVM_SIGNATURE_BOOLEAN: case JVM_SIGNATURE_BYTE: case JVM_SIGNATURE_CHAR: case JVM_SIGNATURE_SHORT: case JVM_SIGNATURE_INT: case JVM_SIGNATURE_FLOAT: case JVM_SIGNATURE_LONG: case JVM_SIGNATURE_DOUBLE: return signature + 1; case JVM_SIGNATURE_CLASS: { if (_major_version < JAVA_1_5_VERSION) { // Skip over the class name if one is there char* p = skip_over_field_name(signature + 1, true, --length); // The next character better be a semicolon if (p && (p - signature) > 1 && p[0] == ';') { return p + 1; } } else { // 4900761: For class version > 48, any unicode is allowed in class name. length--; signature++; while (length > 0 && signature[0] != ';') { if (signature[0] == '.') { classfile_parse_error("Class name contains illegal character '.' in descriptor in class file %s", CHECK_0); } length--; signature++; } if (signature[0] == ';') { return signature + 1; } } return NULL; } case JVM_SIGNATURE_ARRAY: array_dim++; if (array_dim > 255) { // 4277370: array descriptor is valid only if it represents 255 or fewer dimensions. classfile_parse_error("Array type descriptor has more than 255 dimensions in class file %s", CHECK_0); } // The rest of what's there better be a legal signature signature++; length--; void_ok = false; break; default: return NULL; } } return NULL; }