diff a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -510,10 +510,21 @@ Symbol* const name = cp->symbol_at(class_index); const unsigned int name_len = name->utf8_length(); if (name->is_Q_signature()) { cp->unresolved_qdescriptor_at_put(index, class_index, num_klasses++); } else { + if (name->is_L_signature()) { + check_property(_lenvelope_mode == lenvelope_unknown_mode || AllowLEnvelopesInCCI, + "[L-envelope forbidden mode] Illegal use of L-envelope in CONSTANT_Class_info index %u in class file %s", + class_index, CHECK); + _lenvelope_mode = lenvelope_required_mode; + } else { + check_property(_lenvelope_mode == lenvelope_unknown_mode || _lenvelope_mode == lenvelope_forbidden_mode, + "[L-envelope required mode] Missing L-envelope in CONSTANT_Class_info index %u in class file %s", + class_index, CHECK); + _lenvelope_mode = lenvelope_forbidden_mode; + } cp->unresolved_klass_at_put(index, class_index, num_klasses++); } break; } case JVM_CONSTANT_StringIndex: { @@ -6339,15 +6350,20 @@ void ClassFileParser::update_class_name(Symbol* new_class_name) { // Decrement the refcount in the old name, since we're clobbering it. _class_name->decrement_refcount(); - _class_name = new_class_name; - // Increment the refcount of the new name. - // Now the ClassFileParser owns this name and will decrement in - // the destructor. - _class_name->increment_refcount(); + if (new_class_name->is_L_signature() || new_class_name->is_Q_signature()) { + new_class_name = new_class_name->fundamental_name(Thread::current()); + _class_name = new_class_name; + } else { + _class_name = new_class_name; + // Increment the refcount of the new name. + // Now the ClassFileParser owns this name and will decrement in + // the destructor. + _class_name->increment_refcount(); + } } // For an unsafe anonymous class that is in the unnamed package, move it to its host class's // package by prepending its host class's package name to its class name and setting @@ -6481,11 +6497,12 @@ _is_naturally_atomic(false), _is_declared_atomic(false), _has_finalizer(false), _has_empty_finalizer(false), _has_vanilla_constructor(false), - _max_bootstrap_specifier_index(-1) { + _max_bootstrap_specifier_index(-1), + _lenvelope_mode(lenvelope_unknown_mode) { _class_name = name != NULL ? name : vmSymbols::unknown_class_name(); _class_name->increment_refcount(); assert(THREAD->is_Java_thread(), "invariant"); diff a/src/hotspot/share/classfile/classFileParser.hpp b/src/hotspot/share/classfile/classFileParser.hpp --- a/src/hotspot/share/classfile/classFileParser.hpp +++ b/src/hotspot/share/classfile/classFileParser.hpp @@ -108,11 +108,11 @@ private: // Potentially unaligned pointer to various 16-bit entries in the class file typedef void unsafe_u2; const ClassFileStream* _stream; // Actual input stream - const Symbol* _requested_name; + Symbol* _requested_name; Symbol* _class_name; mutable ClassLoaderData* _loader_data; const InstanceKlass* _unsafe_anonymous_host; GrowableArray* _cp_patches; // overrides for CP entries int _num_patched_klasses; @@ -207,10 +207,18 @@ bool _has_finalizer; bool _has_empty_finalizer; bool _has_vanilla_constructor; int _max_bootstrap_specifier_index; // detects BSS values + enum { + lenvelope_unknown_mode, // L-envelope mode still undetermined + lenvelope_forbidden_mode, // L-envelopes strictly forbidden in CONSTANT_Class_info + lenvelope_required_mode // L-envelopes mandatory in CONSTANT_Class_info + }; + + int _lenvelope_mode; + void parse_stream(const ClassFileStream* const stream, TRAPS); void post_process_parsed_stream(const ClassFileStream* const stream, ConstantPool* cp, TRAPS); diff a/src/hotspot/share/classfile/stackMapTable.cpp b/src/hotspot/share/classfile/stackMapTable.cpp --- a/src/hotspot/share/classfile/stackMapTable.cpp +++ b/src/hotspot/share/classfile/stackMapTable.cpp @@ -193,10 +193,17 @@ if (fund_name == NULL) { _stream->stackmap_format_error("TBD something bad happened", THREAD); return VerificationType::bogus_type(); } return VerificationType::valuetype_type(fund_name); + } else if (klass_name->is_L_signature()) { + Symbol* fund_name = klass_name->fundamental_name(THREAD); + if (fund_name == NULL) { + _stream->stackmap_format_error("TBD something bad happened", THREAD); + return VerificationType::bogus_type(); + } + return VerificationType::reference_type(fund_name); } else { return VerificationType::reference_type(klass_name); } } if (tag == ITEM_UninitializedThis) { diff a/src/hotspot/share/classfile/verifier.hpp b/src/hotspot/share/classfile/verifier.hpp --- a/src/hotspot/share/classfile/verifier.hpp +++ b/src/hotspot/share/classfile/verifier.hpp @@ -457,12 +457,18 @@ if (name->is_Q_signature()) { // Remove the Q and ; // TBD need error msg if fundamental_name() returns NULL? Symbol* fund_name = name->fundamental_name(CHECK_(VerificationType::bogus_type())); return VerificationType::valuetype_type(fund_name); + } else if (name->is_L_signature()) { + // Remove the L and ; + // TBD need error msg if fundamental_name() returns NULL? + Symbol* fund_name = name->fundamental_name(CHECK_(VerificationType::bogus_type())); + return VerificationType::reference_type(fund_name); + } else { + return VerificationType::reference_type(name); } - return VerificationType::reference_type(name); } // Keep a list of temporary symbols created during verification because // their reference counts need to be decremented when the verifier object // goes out of scope. Since these symbols escape the scope in which they're diff a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp --- a/src/hotspot/share/oops/constantPool.cpp +++ b/src/hotspot/share/oops/constantPool.cpp @@ -494,24 +494,29 @@ } Handle mirror_handle; Symbol* name = this_cp->symbol_at(name_index); bool value_type_signature = false; + bool had_envelope = false; if (name->is_Q_signature()) { name = name->fundamental_name(THREAD); value_type_signature = true; + had_envelope = true; + } else if (name->is_L_signature()) { + name = name->fundamental_name(THREAD); + had_envelope = true; } Handle loader (THREAD, this_cp->pool_holder()->class_loader()); Handle protection_domain (THREAD, this_cp->pool_holder()->protection_domain()); Klass* k; { // Turn off the single stepping while doing class resolution JvmtiHideSingleStepping jhss(javaThread); k = SystemDictionary::resolve_or_fail(name, loader, protection_domain, true, THREAD); } // JvmtiHideSingleStepping jhss(javaThread); - if (value_type_signature) { + if (had_envelope) { name->decrement_refcount(); } if (!HAS_PENDING_EXCEPTION) { // preserve the resolved klass from unloading diff a/src/hotspot/share/oops/symbol.cpp b/src/hotspot/share/oops/symbol.cpp --- a/src/hotspot/share/oops/symbol.cpp +++ b/src/hotspot/share/oops/symbol.cpp @@ -81,10 +81,15 @@ bool Symbol::is_Q_signature() const { int len = utf8_length(); return len > 2 && char_at(0) == JVM_SIGNATURE_VALUETYPE && char_at(len - 1) == JVM_SIGNATURE_ENDCLASS; } +bool Symbol::is_L_signature() const { + int len = utf8_length(); + return len > 2 && char_at(0) == JVM_SIGNATURE_CLASS && char_at(len - 1) == JVM_SIGNATURE_ENDCLASS; +} + bool Symbol::is_Q_array_signature() const { int l = utf8_length(); if (l < 2 || char_at(0) != JVM_SIGNATURE_ARRAY || char_at(l - 1) != JVM_SIGNATURE_ENDCLASS) { return false; } diff a/src/hotspot/share/oops/symbol.hpp b/src/hotspot/share/oops/symbol.hpp --- a/src/hotspot/share/oops/symbol.hpp +++ b/src/hotspot/share/oops/symbol.hpp @@ -234,10 +234,11 @@ bool is_void_method_signature() const { return starts_with('(') && ends_with('V'); } bool is_Q_signature() const; + bool is_L_signature() const; bool is_Q_array_signature() const; bool is_Q_method_signature() const; bool is_Q_singledim_array_signature() const; Symbol* fundamental_name(TRAPS); bool is_same_fundamental_type(Symbol*) const; diff a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -2532,10 +2532,13 @@ "(Deprecated) Use new algorithm to compute field layouts") \ \ product(bool, UseEmptySlotsInSupers, true, \ "Allow allocating fields in empty slots of super-classes") \ \ + product(bool, AllowLEnvelopesInCCI, false, \ + "Use L-envelopes in CONSTANT_Class_info entries") \ + \ // Interface macros #define DECLARE_PRODUCT_FLAG(type, name, value, doc) extern "C" type name;