Path: blob/master/src/hotspot/share/cds/lambdaFormInvokers.cpp
41144 views
/*1* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "cds/archiveBuilder.hpp"26#include "cds/lambdaFormInvokers.hpp"27#include "cds/metaspaceShared.hpp"28#include "classfile/classLoadInfo.hpp"29#include "classfile/classFileStream.hpp"30#include "classfile/javaClasses.inline.hpp"31#include "classfile/klassFactory.hpp"32#include "classfile/symbolTable.hpp"33#include "classfile/systemDictionary.hpp"34#include "classfile/systemDictionaryShared.hpp"35#include "classfile/vmClasses.hpp"36#include "classfile/vmSymbols.hpp"37#include "logging/log.hpp"38#include "memory/oopFactory.hpp"39#include "memory/resourceArea.hpp"40#include "oops/instanceKlass.hpp"41#include "oops/klass.hpp"42#include "oops/objArrayKlass.hpp"43#include "oops/objArrayOop.hpp"44#include "oops/oop.inline.hpp"45#include "oops/typeArrayOop.inline.hpp"46#include "runtime/handles.inline.hpp"47#include "runtime/javaCalls.hpp"48#include "runtime/mutexLocker.hpp"4950GrowableArrayCHeap<char*, mtClassShared>* LambdaFormInvokers::_lambdaform_lines = nullptr;51Array<Array<char>*>* LambdaFormInvokers::_static_archive_invokers = nullptr;5253#define NUM_FILTER 454static const char* filter[NUM_FILTER] = {"java.lang.invoke.Invokers$Holder",55"java.lang.invoke.DirectMethodHandle$Holder",56"java.lang.invoke.DelegatingMethodHandle$Holder",57"java.lang.invoke.LambdaForm$Holder"};5859static bool should_be_archived(char* line) {60for (int k = 0; k < NUM_FILTER; k++) {61if (strstr(line, filter[k]) != nullptr) {62return true;63}64}65return false;66}6768void LambdaFormInvokers::append_filtered(char* line) {69if (should_be_archived(line)) {70append(line);71}72}73#undef NUM_FILTER7475void LambdaFormInvokers::append(char* line) {76MutexLocker ml(Thread::current(), LambdaFormInvokers_lock);77if (_lambdaform_lines == NULL) {78_lambdaform_lines = new GrowableArrayCHeap<char*, mtClassShared>(150);79}80_lambdaform_lines->append(line);81}8283// convenient output84class PrintLambdaFormMessage {85public:86PrintLambdaFormMessage() {87log_info(cds)("Regenerate MethodHandle Holder classes...");88}89~PrintLambdaFormMessage() {90log_info(cds)("Regenerate MethodHandle Holder classes...done");91}92};9394void LambdaFormInvokers::regenerate_holder_classes(TRAPS) {95PrintLambdaFormMessage plm;96if (_lambdaform_lines == nullptr || _lambdaform_lines->length() == 0) {97log_info(cds)("Nothing to regenerate for holder classes");98return;99}100101ResourceMark rm(THREAD);102103Symbol* cds_name = vmSymbols::jdk_internal_misc_CDS();104Klass* cds_klass = SystemDictionary::resolve_or_null(cds_name, THREAD);105guarantee(cds_klass != NULL, "jdk/internal/misc/CDS must exist!");106107HandleMark hm(THREAD);108int len = _lambdaform_lines->length();109objArrayHandle list_lines;110{111MutexLocker ml(Thread::current(), LambdaFormInvokers_lock);112list_lines = oopFactory::new_objArray_handle(vmClasses::String_klass(), len, CHECK);113for (int i = 0; i < len; i++) {114Handle h_line = java_lang_String::create_from_str(_lambdaform_lines->at(i), CHECK);115list_lines->obj_at_put(i, h_line());116}117} // Before calling into java, release vm lock.118//119// Object[] CDS.generateLambdaFormHolderClasses(String[] lines)120// the returned Object[] layout:121// name, byte[], name, byte[] ....122Symbol* method = vmSymbols::generateLambdaFormHolderClasses();123Symbol* signrs = vmSymbols::generateLambdaFormHolderClasses_signature();124125JavaValue result(T_OBJECT);126JavaCalls::call_static(&result, cds_klass, method, signrs, list_lines, THREAD);127128if (HAS_PENDING_EXCEPTION) {129if (!PENDING_EXCEPTION->is_a(vmClasses::OutOfMemoryError_klass())) {130log_error(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(),131java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION)));132if (DumpSharedSpaces) {133log_error(cds)("Failed to generate LambdaForm holder classes. Is your classlist out of date?");134} else {135log_error(cds)("Failed to generate LambdaForm holder classes. Was the base archive generated with an outdated classlist?");136}137CLEAR_PENDING_EXCEPTION;138}139return;140}141142objArrayHandle h_array(THREAD, (objArrayOop)result.get_oop());143int sz = h_array->length();144assert(sz % 2 == 0 && sz >= 2, "Must be even size of length");145for (int i = 0; i < sz; i+= 2) {146Handle h_name(THREAD, h_array->obj_at(i));147typeArrayHandle h_bytes(THREAD, (typeArrayOop)h_array->obj_at(i+1));148assert(h_name != NULL, "Class name is NULL");149assert(h_bytes != NULL, "Class bytes is NULL");150151char *class_name = java_lang_String::as_utf8_string(h_name());152int len = h_bytes->length();153// make a copy of class bytes so GC will not affect us.154char *buf = NEW_RESOURCE_ARRAY(char, len);155memcpy(buf, (char*)h_bytes->byte_at_addr(0), len);156ClassFileStream st((u1*)buf, len, NULL, ClassFileStream::verify);157reload_class(class_name, st, CHECK);158}159}160161// class_handle - the class name, bytes_handle - the class bytes162void LambdaFormInvokers::reload_class(char* name, ClassFileStream& st, TRAPS) {163Symbol* class_name = SymbolTable::new_symbol((const char*)name);164// the class must exist165Klass* klass = SystemDictionary::resolve_or_null(class_name, THREAD);166if (klass == NULL) {167log_info(cds)("Class %s not present, skip", name);168return;169}170assert(klass->is_instance_klass(), "Should be");171172ClassLoaderData* cld = ClassLoaderData::the_null_class_loader_data();173Handle protection_domain;174ClassLoadInfo cl_info(protection_domain);175176InstanceKlass* result = KlassFactory::create_from_stream(&st,177class_name,178cld,179cl_info,180CHECK);181182{183MutexLocker mu_r(THREAD, Compile_lock); // add_to_hierarchy asserts this.184SystemDictionary::add_to_hierarchy(result);185}186// new class not linked yet.187MetaspaceShared::try_link_class(THREAD, result);188assert(!HAS_PENDING_EXCEPTION, "Invariant");189190// exclude the existing class from dump191SystemDictionaryShared::set_excluded(InstanceKlass::cast(klass));192SystemDictionaryShared::init_dumptime_info(result);193log_info(cds, lambda)("Replaced class %s, old: " INTPTR_FORMAT " new: " INTPTR_FORMAT,194name, p2i(klass), p2i(result));195}196197void LambdaFormInvokers::dump_static_archive_invokers() {198if (_lambdaform_lines != nullptr && _lambdaform_lines->length() > 0) {199int count = 0;200int len = _lambdaform_lines->length();201for (int i = 0; i < len; i++) {202char* str = _lambdaform_lines->at(i);203if (should_be_archived(str)) {204count++;205}206}207if (count > 0) {208_static_archive_invokers = ArchiveBuilder::new_ro_array<Array<char>*>(count);209int index = 0;210for (int i = 0; i < len; i++) {211char* str = _lambdaform_lines->at(i);212if (should_be_archived(str)) {213size_t str_len = strlen(str) + 1; // including terminating zero214Array<char>* line = ArchiveBuilder::new_ro_array<char>((int)str_len);215strncpy(line->adr_at(0), str, str_len);216217_static_archive_invokers->at_put(index, line);218ArchivePtrMarker::mark_pointer(_static_archive_invokers->adr_at(index));219index++;220}221}222assert(index == count, "Should match");223}224log_debug(cds)("Total LF lines stored into static archive: %d", count);225}226}227228void LambdaFormInvokers::read_static_archive_invokers() {229if (_static_archive_invokers != nullptr) {230for (int i = 0; i < _static_archive_invokers->length(); i++) {231Array<char>* line = _static_archive_invokers->at(i);232char* str = line->adr_at(0);233append(str);234}235log_debug(cds)("Total LF lines read from static archive: %d", _static_archive_invokers->length());236}237}238239void LambdaFormInvokers::serialize(SerializeClosure* soc) {240soc->do_ptr((void**)&_static_archive_invokers);241}242243244