--- old/src/hotspot/share/classfile/classFileParser.cpp 2019-03-22 10:11:22.006279174 -0400 +++ new/src/hotspot/share/classfile/classFileParser.cpp 2019-03-22 10:11:21.237804142 -0400 @@ -662,6 +662,7 @@ // Format check method name and signature verify_legal_method_name(name, CHECK); verify_legal_method_signature(name, sig, CHECK); + _method_sig_count++; } else { // Format check field name and signature verify_legal_field_name(name, CHECK); @@ -5668,6 +5669,8 @@ } } + ik->set_method_sig_count(_method_sig_count); + JFR_ONLY(INIT_ID(ik);) // If we reach here, all is well. @@ -5797,6 +5800,7 @@ _vtable_size(0), _itable_size(0), _num_miranda_methods(0), + _method_sig_count(0), _rt(REF_NONE), _protection_domain(protection_domain), _access_flags(), --- old/src/hotspot/share/classfile/classFileParser.hpp 2019-03-22 10:11:23.695293794 -0400 +++ new/src/hotspot/share/classfile/classFileParser.hpp 2019-03-22 10:11:22.946163091 -0400 @@ -123,6 +123,8 @@ int _num_miranda_methods; + int _method_sig_count; + ReferenceType _rt; Handle _protection_domain; AccessFlags _access_flags; --- old/src/hotspot/share/classfile/verifier.cpp 2019-03-22 10:11:25.739945711 -0400 +++ new/src/hotspot/share/classfile/verifier.cpp 2019-03-22 10:11:24.994080129 -0400 @@ -574,7 +574,7 @@ ClassVerifier::ClassVerifier( InstanceKlass* klass, TRAPS) : _thread(THREAD), _previous_symbol(NULL), _symbols(NULL), _exception_type(NULL), - _message(NULL), _klass(klass) { + _message(NULL), _method_signatures_table(NULL), _klass(klass) { _this_type = VerificationType::reference_type(klass->name()); } @@ -601,6 +601,14 @@ void ClassVerifier::verify_class(TRAPS) { log_info(verification)("Verifying class %s with new format", _klass->external_name()); + // Either verifying both local and remote classes or just remote classes. + assert(BytecodeVerificationRemote, "Should not be here"); + + // Create and initialize hash table containing method signatures. + method_signatures_table_type method_signatures_table; + init_method_sigs_table(&method_signatures_table, CHECK_VERIFY(this)); + set_method_signatures_table(&method_signatures_table); + Array* methods = _klass->methods(); int num_methods = methods->length(); @@ -625,6 +633,81 @@ } } +// Translate the signature entries into verification types and save them in +// the growable array. Also, save the count of arguments. +void ClassVerifier::translate_signature(Symbol* const method_sig, + sig_as_verification_types* sig_verif_types, + TRAPS) { + SignatureStream sig_stream(method_sig); + VerificationType sig_type[2]; + int sig_i = 0; + GrowableArray* verif_types = sig_verif_types->sig_verif_types(); + + // Translate the signature arguments into verification types. + while (!sig_stream.at_return_type()) { + int n = change_sig_to_verificationType(&sig_stream, sig_type, CHECK_VERIFY(this)); + assert(n <= 2, "Unexpected signature type"); + + // Store verification type(s). Longs and Doubles each have two verificationTypes. + for (int x = 0; x < n; x++) { + verif_types->push(sig_type[x]); + } + sig_i += n; + sig_stream.next(); + } + + // Set final arg count, not including the return type. The final arg count will + // be compared with sig_verify_types' length to see if there is a return type. + sig_verif_types->set_num_args(sig_i); + + // Store verification type(s) for the return type, if there is one. + if (sig_stream.type() != T_VOID) { + int n = change_sig_to_verificationType(&sig_stream, sig_type, CHECK_VERIFY(this)); + assert(n <= 2, "Unexpected signature return type"); + for (int y = 0; y < n; y++) { + verif_types->push(sig_type[y]); + } + } +} + + +// Initialize the table with all the unique method signatures. +void ClassVerifier::init_method_sigs_table(method_signatures_table_type* method_sig_table, TRAPS) { + ConstantPool* cp = _klass->constants(); + int len = cp->length(); + GrowableArray* unique_sig_indexes = new GrowableArray(_klass->method_sig_count()); + + // Loop through the constant pool looking for each method signature pointed + // to by a NameAndType entry. Save the method signatures' UTF8 constant + // pool indexes. + for (int index = 1; index < len; index++) { + constantTag tag = cp->tag_at(index); + if (tag.is_name_and_type()) { + const int sig_index = cp->signature_ref_index_at(index); + Symbol* const method_sig = cp->symbol_at(sig_index); + if (method_sig->char_at(0) == JVM_SIGNATURE_FUNC) { + // Multiple constant pool NameAndType entries can point + // to the same UTF8 signature so weed out duplicates. + unique_sig_indexes->append_if_missing(sig_index); + } + } + } + + for (int i = 0; i < unique_sig_indexes->length(); i++) { + const int sig_index = unique_sig_indexes->at(i); + Symbol* const method_sig = cp->symbol_at(sig_index); + + // Translate the signature into a growable array of verification types. + GrowableArray* verif_types = new GrowableArray(10); + sig_as_verification_types* sig_verif_types = new sig_as_verification_types(verif_types); + translate_signature(method_sig, sig_verif_types, CHECK_VERIFY(this)); + + // Add the list of this signature's verification types to the table. + bool is_unique = method_sig_table->put(sig_index, sig_verif_types); + assert(is_unique, "Duplicate entries in method_signature_table"); + } +} + void ClassVerifier::verify_method(const methodHandle& m, TRAPS) { HandleMark hm(THREAD); _method = m; // initialize _method @@ -2740,38 +2823,13 @@ // longs/doubles to be consertive. assert(sizeof(VerificationType) == sizeof(uintptr_t), "buffer type must match VerificationType size"); - uintptr_t on_stack_sig_types_buffer[128]; - // If we make a VerificationType[128] array directly, the compiler calls - // to the c-runtime library to do the allocation instead of just - // stack allocating it. Plus it would run constructors. This shows up - // in performance profiles. - VerificationType* sig_types; - int size = (method_sig->utf8_length() - 3) * 2; - if (size > 128) { - // Long and double occupies two slots here. - ArgumentSizeComputer size_it(method_sig); - size = size_it.size(); - sig_types = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, VerificationType, size); - } else{ - sig_types = (VerificationType*)on_stack_sig_types_buffer; - } - SignatureStream sig_stream(method_sig); - int sig_i = 0; - while (!sig_stream.at_return_type()) { - sig_i += change_sig_to_verificationType( - &sig_stream, &sig_types[sig_i], CHECK_VERIFY(this)); - sig_stream.next(); - } - int nargs = sig_i; + // Get the UTF8 index for this signature. + int sig_index = cp->signature_ref_index_at(cp->name_and_type_ref_index_at(index)); -#ifdef ASSERT - { - ArgumentSizeComputer size_it(method_sig); - assert(nargs == size_it.size(), "Argument sizes do not match"); - assert(nargs <= (method_sig->utf8_length() - 3) * 2, "estimate of max size isn't conservative enough"); - } -#endif + // Get the number of arguments for this signature. + sig_as_verification_types* mth_sig_verif_types = *(method_signatures_table()->get(sig_index)); + int nargs = mth_sig_verif_types->num_args(); // Check instruction operands u2 bci = bcs->bci(); @@ -2844,10 +2902,16 @@ } } + + // Get the verification types for the method's arguments. + GrowableArray* sig_verif_types = mth_sig_verif_types->sig_verif_types(); + assert(sig_verif_types != NULL, "Missing signature's array of verification types"); // Match method descriptor with operand stack - for (int i = nargs - 1; i >= 0; i--) { // Run backwards - current_frame->pop_stack(sig_types[i], CHECK_VERIFY(this)); + // The arguments are on the stack in descending order. + for (int i = nargs - 1; i >= 0; i--) { // Run backwards + current_frame->pop_stack(sig_verif_types->at(i), CHECK_VERIFY(this)); } + // Check objectref on operand stack if (opcode != Bytecodes::_invokestatic && opcode != Bytecodes::_invokedynamic) { @@ -2919,7 +2983,8 @@ } } // Push the result type. - if (sig_stream.type() != T_VOID) { + int sig_verif_types_len = sig_verif_types->length(); + if (sig_verif_types_len > nargs) { // There's a return type if (method_name == vmSymbols::object_initializer_name()) { // method must have a void return type /* Unreachable? Class file parser verifies that methods with '<' have @@ -2928,11 +2993,11 @@ "Return type must be void in method"); return; } - VerificationType return_type[2]; - int n = change_sig_to_verificationType( - &sig_stream, return_type, CHECK_VERIFY(this)); - for (int i = 0; i < n; i++) { - current_frame->push_stack(return_type[i], CHECK_VERIFY(this)); // push types backwards + + assert(sig_verif_types_len <= nargs + 2, + "Signature verification types array return type is bogus"); + for (int i = nargs; i < sig_verif_types_len; i++) { + current_frame->push_stack(sig_verif_types->at(i), CHECK_VERIFY(this)); } } } --- old/src/hotspot/share/classfile/verifier.hpp 2019-03-22 10:11:28.391612367 -0400 +++ new/src/hotspot/share/classfile/verifier.hpp 2019-03-22 10:11:27.654201249 -0400 @@ -31,6 +31,7 @@ #include "runtime/handles.hpp" #include "utilities/exceptions.hpp" #include "utilities/growableArray.hpp" +#include "utilities/resourceHash.hpp" // The verifier class class Verifier : AllStatic { @@ -246,6 +247,31 @@ void stackmap_details(outputStream* ss, const Method* method) const; }; +class sig_as_verification_types : public ResourceObj { + private: + int _num_args; // Number of arguments, not including return type. + GrowableArray* _sig_verif_types; + + public: + + sig_as_verification_types(GrowableArray* sig_verif_types) : + _num_args(0), _sig_verif_types(sig_verif_types) { + } + + int num_args() const { return _num_args; } + void set_num_args(int num_args) { _num_args = num_args; } + + GrowableArray* sig_verif_types() { return _sig_verif_types; } + void set_sig_verif_types(GrowableArray* sig_verif_types) { + _sig_verif_types = sig_verif_types; + } + +}; + +typedef ResourceHashtable, primitive_equals, 71> + method_signatures_table_type; + // A new instance of this class is created for each class being verified class ClassVerifier : public StackObj { private: @@ -257,6 +283,8 @@ Symbol* _exception_type; char* _message; + method_signatures_table_type* _method_signatures_table; + ErrorContext _error_context; // contains information about an error void verify_method(const methodHandle& method, TRAPS); @@ -383,6 +411,14 @@ // the message_buffer will be filled in with the exception message. void verify_class(TRAPS); + // Loops through the constant pool looking for method signatures and stores + // them in the method signatures table. + void init_method_sigs_table(method_signatures_table_type* method_sig_table, TRAPS); + + // Translates signature entries into verificationTypes and saves them in the + // growable array. + void translate_signature(Symbol* const method_sig, sig_as_verification_types* sig_verif_types, TRAPS); + // Return status modes Symbol* result() const { return _exception_type; } bool has_error() const { return result() != NULL; } @@ -400,6 +436,14 @@ Klass* load_class(Symbol* name, TRAPS); + method_signatures_table_type* method_signatures_table() const { + return _method_signatures_table; + } + + void set_method_signatures_table(method_signatures_table_type* method_signatures_table) { + _method_signatures_table = method_signatures_table; + } + int change_sig_to_verificationType( SignatureStream* sig_type, VerificationType* inference_type, TRAPS); --- old/src/hotspot/share/oops/instanceKlass.hpp 2019-03-22 10:11:30.459534105 -0400 +++ new/src/hotspot/share/oops/instanceKlass.hpp 2019-03-22 10:11:29.704409894 -0400 @@ -206,6 +206,9 @@ int _nonstatic_oop_map_size;// size in words of nonstatic oop map blocks int _itable_len; // length of Java itable (in words) + + int _method_sig_count; // number of method signatures in constant pool + // _is_marked_dependent can be set concurrently, thus cannot be part of the // _misc_flags. bool _is_marked_dependent; // used for marking during flushing and deoptimization @@ -391,6 +394,10 @@ int itable_length() const { return _itable_len; } void set_itable_length(int len) { _itable_len = len; } + // Number of constant pool method signatures + int method_sig_count() const { return _method_sig_count; } + void set_method_sig_count(int count) { _method_sig_count = count; } + // array klasses Klass* array_klasses() const { return _array_klasses; } inline Klass* array_klasses_acquire() const; // load with acquire semantics