diff -r 62771002a1cb -r c171aa9e5d3e src/hotspot/share/classfile/classFileParser.cpp --- a/src/hotspot/share/classfile/classFileParser.cpp Tue Jan 22 14:14:52 2019 -0800 +++ b/src/hotspot/share/classfile/classFileParser.cpp Tue Mar 26 10:55:17 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2019, 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 @@ -52,7 +52,7 @@ #include "oops/klass.inline.hpp" #include "oops/klassVtable.hpp" #include "oops/metadata.hpp" -#include "oops/method.hpp" +#include "oops/method.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" #include "prims/jvmtiExport.hpp" @@ -60,6 +60,7 @@ #include "runtime/arguments.hpp" #include "runtime/handles.inline.hpp" #include "runtime/javaCalls.hpp" +#include "runtime/os.hpp" #include "runtime/perfData.hpp" #include "runtime/reflection.hpp" #include "runtime/safepointVerifiers.hpp" @@ -564,7 +565,7 @@ } case JVM_CONSTANT_Dynamic: { const int name_and_type_ref_index = - cp->invoke_dynamic_name_and_type_ref_index_at(index); + cp->bootstrap_name_and_type_ref_index_at(index); check_property(valid_cp_range(name_and_type_ref_index, length) && cp->tag_at(name_and_type_ref_index).is_name_and_type(), @@ -579,7 +580,7 @@ } case JVM_CONSTANT_InvokeDynamic: { const int name_and_type_ref_index = - cp->invoke_dynamic_name_and_type_ref_index_at(index); + cp->bootstrap_name_and_type_ref_index_at(index); check_property(valid_cp_range(name_and_type_ref_index, length) && cp->tag_at(name_and_type_ref_index).is_name_and_type(), @@ -1973,46 +1974,6 @@ return localvariable_table_start; } - -void ClassFileParser::parse_type_array(u2 array_length, - u4 code_length, - u4* const u1_index, - u4* const u2_index, - u1* const u1_array, - u2* const u2_array, - TRAPS) { - const ClassFileStream* const 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++) { - const u1 tag = u1_array[i1++] = cfs->get_u1(CHECK); - index++; - if (tag == ITEM_Long || tag == ITEM_Double) { - index++; - } else if (tag == ITEM_Object) { - const u2 class_index = u2_array[i2++] = cfs->get_u2(CHECK); - guarantee_property(valid_klass_reference_at(class_index), - "Bad class index %u in StackMap in class file %s", - class_index, CHECK); - } else if (tag == ITEM_Uninitialized) { - const 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; -} - static const u1* parse_stackmap_table(const ClassFileStream* const cfs, u4 code_attribute_length, bool need_verify, @@ -2120,12 +2081,7 @@ if (!privileged) break; // only allow in privileged code 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 - if (!privileged) break; // only allow in privileged code - return _method_Hidden; - } - case vmSymbols::VM_SYMBOL_ENUM_NAME(java_security_AccessController_Hidden_signature): { + case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_Hidden_signature): { if (_location != _in_method) break; // only allow for methods if (!privileged) break; // only allow in privileged code return _method_Hidden; @@ -4996,42 +4952,43 @@ bool ClassFileParser::verify_unqualified_name(const char* name, unsigned int length, int type) { - for (const char* p = name; p != name + length;) { - jchar ch = *p; - if (ch < 128) { - if (ch == '.' || ch == ';' || ch == '[' ) { - return false; // do not permit '.', ';', or '[' - } - if (ch == '/') { + for (const char* p = name; p != name + length; p++) { + switch(*p) { + case '.': + case ';': + case '[': + // do not permit '.', ';', or '[' + return false; + case '/': // check for '//' or leading or trailing '/' which are not legal // unqualified name must not be empty if (type == ClassFileParser::LegalClass) { if (p == name || p+1 >= name+length || *(p+1) == '/') { - return false; + return false; } } else { return false; // do not permit '/' unless it's class name } - } - if (type == ClassFileParser::LegalMethod && (ch == '<' || ch == '>')) { - return false; // do not permit '<' or '>' in method names - } - p++; - } else { - char* tmp_p = UTF8::next(p, &ch); - p = tmp_p; + break; + case '<': + case '>': + // do not permit '<' or '>' in method names + if (type == ClassFileParser::LegalMethod) { + return false; + } } } return true; } -// Take pointer to a string. Skip over the longest part of the string that could +// Take pointer to a UTF8 byte string (not NUL-terminated). +// 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). -static const char* skip_over_field_name(const char* name, +static const char* skip_over_field_name(const char* const name, bool slash_ok, unsigned int length) { const char* p; @@ -5067,29 +5024,12 @@ // 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; - // return value JavaValue result(T_BOOLEAN); - // Set up the arguments to isJavaIdentifierStart and isJavaIdentifierPart + // Set up the arguments to isJavaIdentifierStart or isJavaIdentifierPart JavaCallArguments args; args.push_int(unicode_ch); - // public static boolean isJavaIdentifierStart(char ch); - JavaCalls::call_static(&result, - SystemDictionary::Character_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, @@ -5098,15 +5038,21 @@ vmSymbols::int_bool_signature(), &args, THREAD); - - if (HAS_PENDING_EXCEPTION) { - CLEAR_PENDING_EXCEPTION; - return 0; - } - - if (result.get_jboolean()) { - continue; - } + } else { + // public static boolean isJavaIdentifierStart(char ch); + JavaCalls::call_static(&result, + SystemDictionary::Character_klass(), + vmSymbols::isJavaIdentifierStart_name(), + vmSymbols::int_bool_signature(), + &args, + THREAD); + } + if (HAS_PENDING_EXCEPTION) { + CLEAR_PENDING_EXCEPTION; + return NULL; + } + if(result.get_jboolean()) { + continue; } } return (not_first_ch) ? old_p : NULL; @@ -5114,7 +5060,8 @@ return (not_first_ch) ? p : NULL; } -// Take pointer to a string. Skip over the longest part of the string that could +// Take pointer to a UTF8 byte string (not NUL-terminated). +// 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. @@ -5147,18 +5094,12 @@ } else { // Skip leading 'L' and ignore first appearance of ';' - length--; signature++; - char* c = strchr((char*) signature, ';'); + const char* c = (const char*) memchr(signature, ';', length - 1); // Format check signature if (c != NULL) { - ResourceMark rm(THREAD); int newlen = c - (char*) signature; - char* sig = NEW_RESOURCE_ARRAY(char, newlen + 1); - strncpy(sig, signature, newlen); - sig[newlen] = '\0'; - - bool legal = verify_unqualified_name(sig, newlen, LegalClass); + bool legal = verify_unqualified_name(signature, newlen, LegalClass); if (!legal) { classfile_parse_error("Class name contains illegal character " "in descriptor in class file %s", @@ -5192,8 +5133,8 @@ void ClassFileParser::verify_legal_class_name(const Symbol* name, TRAPS) const { if (!_need_verify || _relax_verify) { return; } - char buf[fixed_buffer_size]; - char* bytes = name->as_utf8_flexible_buffer(THREAD, buf, fixed_buffer_size); + assert(name->refcount() > 0, "symbol must be kept alive"); + char* bytes = (char*)name->bytes(); unsigned int length = name->utf8_length(); bool legal = false; @@ -5221,7 +5162,7 @@ Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(), - "Illegal class name \"%s\" in class file %s", bytes, + "Illegal class name \"%.*s\" in class file %s", length, bytes, _class_name->as_C_string() ); return; @@ -5232,8 +5173,7 @@ void ClassFileParser::verify_legal_field_name(const Symbol* name, TRAPS) const { if (!_need_verify || _relax_verify) { return; } - char buf[fixed_buffer_size]; - char* bytes = name->as_utf8_flexible_buffer(THREAD, buf, fixed_buffer_size); + char* bytes = (char*)name->bytes(); unsigned int length = name->utf8_length(); bool legal = false; @@ -5255,7 +5195,7 @@ Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(), - "Illegal field name \"%s\" in class %s", bytes, + "Illegal field name \"%.*s\" in class %s", length, bytes, _class_name->as_C_string() ); return; @@ -5267,8 +5207,7 @@ 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); + char* bytes = (char*)name->bytes(); unsigned int length = name->utf8_length(); bool legal = false; @@ -5293,7 +5232,7 @@ Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(), - "Illegal method name \"%s\" in class %s", bytes, + "Illegal method name \"%.*s\" in class %s", length, bytes, _class_name->as_C_string() ); return; @@ -5307,8 +5246,7 @@ TRAPS) const { if (!_need_verify) { return; } - char buf[fixed_buffer_size]; - const char* const bytes = signature->as_utf8_flexible_buffer(THREAD, buf, fixed_buffer_size); + const char* const bytes = (const char* const)signature->bytes(); const unsigned int length = signature->utf8_length(); const char* const p = skip_over_field_signature(bytes, false, length, CHECK); @@ -5337,8 +5275,7 @@ } unsigned int args_size = 0; - char buf[fixed_buffer_size]; - const char* p = signature->as_utf8_flexible_buffer(THREAD, buf, fixed_buffer_size); + const char* p = (const char*)signature->bytes(); unsigned int length = signature->utf8_length(); const char* nextp; @@ -5744,6 +5681,18 @@ debug_only(ik->verify();) } +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(); +} + + // 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 // its _class_name field. @@ -5755,21 +5704,22 @@ ClassLoader::package_from_name(unsafe_anonymous_host->name()->as_C_string(), NULL); if (host_pkg_name != NULL) { - size_t host_pkg_len = strlen(host_pkg_name); + int host_pkg_len = (int)strlen(host_pkg_name); int class_name_len = _class_name->utf8_length(); - char* new_anon_name = - NEW_RESOURCE_ARRAY(char, host_pkg_len + 1 + class_name_len); - // Copy host package name and trailing /. - strncpy(new_anon_name, host_pkg_name, host_pkg_len); - new_anon_name[host_pkg_len] = '/'; - // Append unsafe anonymous class name. The unsafe anonymous class name can contain odd - // characters. So, do a strncpy instead of using sprintf("%s..."). - strncpy(new_anon_name + host_pkg_len + 1, (char *)_class_name->base(), class_name_len); + int symbol_len = host_pkg_len + 1 + class_name_len; + char* new_anon_name = NEW_RESOURCE_ARRAY(char, symbol_len + 1); + int n = os::snprintf(new_anon_name, symbol_len + 1, "%s/%.*s", + host_pkg_name, class_name_len, _class_name->base()); + assert(n == symbol_len, "Unexpected number of characters in string"); + + // Decrement old _class_name to avoid leaking. + _class_name->decrement_refcount(); // Create a symbol and update the anonymous class name. - _class_name = SymbolTable::new_symbol(new_anon_name, - (int)host_pkg_len + 1 + class_name_len, - CHECK); + // The new class name is created with a refcount of one. When installed into the InstanceKlass, + // it'll be two and when the ClassFileParser destructor runs, it'll go back to one and get deleted + // when the class is unloaded. + _class_name = SymbolTable::new_symbol(new_anon_name, symbol_len, CHECK); } } @@ -5815,6 +5765,7 @@ TRAPS) : _stream(stream), _requested_name(name), + _class_name(NULL), _loader_data(loader_data), _unsafe_anonymous_host(unsafe_anonymous_host), _cp_patches(cp_patches), @@ -5873,6 +5824,7 @@ _max_bootstrap_specifier_index(-1) { _class_name = name != NULL ? name : vmSymbols::unknown_class_name(); + _class_name->increment_refcount(); assert(THREAD->is_Java_thread(), "invariant"); assert(_loader_data != NULL, "invariant"); @@ -5942,6 +5894,8 @@ // Destructor to clean up ClassFileParser::~ClassFileParser() { + _class_name->decrement_refcount(); + if (_cp != NULL) { MetadataFactory::free_metadata(_loader_data, _cp); } @@ -6095,9 +6049,8 @@ Symbol* const class_name_in_cp = cp->klass_name_at(_this_class_index); assert(class_name_in_cp != NULL, "class_name can't be null"); - // Update _class_name which could be null previously - // to reflect the name in the constant pool - _class_name = class_name_in_cp; + // Update _class_name to reflect the name in the constant pool + update_class_name(class_name_in_cp); // Don't need to check whether this class name is legal or not. // It has been checked when constant pool is parsed. @@ -6160,7 +6113,7 @@ // For the boot and platform class loaders, skip classes that are not found in the // java runtime image, such as those found in the --patch-module entries. // These classes can't be loaded from the archive during runtime. - if (!ClassLoader::is_modules_image(stream->source()) && strncmp(stream->source(), "jrt:", 4) != 0) { + if (!stream->from_boot_loader_modules_image() && strncmp(stream->source(), "jrt:", 4) != 0) { skip = true; }