Path: blob/master/src/hotspot/share/interpreter/bootstrapInfo.cpp
40949 views
/*1* Copyright (c) 2019, 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 "jvm.h"26#include "classfile/javaClasses.inline.hpp"27#include "classfile/resolutionErrors.hpp"28#include "classfile/systemDictionary.hpp"29#include "classfile/vmClasses.hpp"30#include "interpreter/bootstrapInfo.hpp"31#include "interpreter/linkResolver.hpp"32#include "logging/log.hpp"33#include "logging/logStream.hpp"34#include "memory/oopFactory.hpp"35#include "memory/resourceArea.hpp"36#include "oops/cpCache.inline.hpp"37#include "oops/objArrayOop.inline.hpp"38#include "oops/typeArrayOop.inline.hpp"39#include "runtime/handles.inline.hpp"40#include "runtime/thread.inline.hpp"41#include "runtime/vmThread.hpp"4243//------------------------------------------------------------------------------------------------------------------------44// Implementation of BootstrapInfo4546BootstrapInfo::BootstrapInfo(const constantPoolHandle& pool, int bss_index, int indy_index)47: _pool(pool),48_bss_index(bss_index),49_indy_index(indy_index),50// derived and eagerly cached:51_argc( pool->bootstrap_argument_count_at(bss_index) ),52_name( pool->uncached_name_ref_at(bss_index) ),53_signature( pool->uncached_signature_ref_at(bss_index) )54{55_is_resolved = false;56assert(pool->tag_at(bss_index).has_bootstrap(), "");57assert(indy_index == -1 || pool->invokedynamic_bootstrap_ref_index_at(indy_index) == bss_index, "invalid bootstrap specifier index");58}5960// If there is evidence this call site was already linked, set the61// existing linkage data into result, or throw previous exception.62// Return true if either action is taken, else false.63bool BootstrapInfo::resolve_previously_linked_invokedynamic(CallInfo& result, TRAPS) {64assert(_indy_index != -1, "");65ConstantPoolCacheEntry* cpce = invokedynamic_cp_cache_entry();66if (!cpce->is_f1_null()) {67methodHandle method( THREAD, cpce->f1_as_method());68Handle appendix( THREAD, cpce->appendix_if_resolved(_pool));69result.set_handle(method, appendix, THREAD);70Exceptions::wrap_dynamic_exception(/* is_indy */ true, CHECK_false);71return true;72} else if (cpce->indy_resolution_failed()) {73int encoded_index = ResolutionErrorTable::encode_cpcache_index(_indy_index);74ConstantPool::throw_resolution_error(_pool, encoded_index, CHECK_false);75return true;76} else {77return false;78}79}8081// Resolve the bootstrap specifier in 3 steps:82// - unpack the BSM by resolving the MH constant83// - obtain the NameAndType description for the condy/indy84// - prepare the BSM's static arguments85Handle BootstrapInfo::resolve_bsm(TRAPS) {86if (_bsm.not_null()) {87return _bsm;88}8990bool is_indy = is_method_call();91// The tag at the bootstrap method index must be a valid method handle or a method handle in error.92// If it is a MethodHandleInError, a resolution error will be thrown which will be wrapped if necessary93// with a BootstrapMethodError.94assert(_pool->tag_at(bsm_index()).is_method_handle() ||95_pool->tag_at(bsm_index()).is_method_handle_in_error(), "MH not present, classfile structural constraint");96oop bsm_oop = _pool->resolve_possibly_cached_constant_at(bsm_index(), THREAD);97Exceptions::wrap_dynamic_exception(is_indy, CHECK_NH);98guarantee(java_lang_invoke_MethodHandle::is_instance(bsm_oop), "classfile must supply a valid BSM");99_bsm = Handle(THREAD, bsm_oop);100101// Obtain NameAndType information102resolve_bss_name_and_type(THREAD);103Exceptions::wrap_dynamic_exception(is_indy, CHECK_NH);104105// Prepare static arguments106resolve_args(THREAD);107Exceptions::wrap_dynamic_exception(is_indy, CHECK_NH);108109return _bsm;110}111112// Resolve metadata from the JVM_Dynamic_info or JVM_InvokeDynamic_info's name and type information.113void BootstrapInfo::resolve_bss_name_and_type(TRAPS) {114assert(_bsm.not_null(), "resolve_bsm first");115Symbol* name = this->name();116Symbol* type = this->signature();117_name_arg = java_lang_String::create_from_symbol(name, CHECK);118if (type->char_at(0) == '(') {119_type_arg = SystemDictionary::find_method_handle_type(type, caller(), CHECK);120} else {121_type_arg = SystemDictionary::find_java_mirror_for_type(type, caller(), SignatureStream::NCDFError, CHECK);122}123}124125// Resolve the bootstrap method's static arguments and store the result in _arg_values.126void BootstrapInfo::resolve_args(TRAPS) {127assert(_bsm.not_null(), "resolve_bsm first");128129// if there are no static arguments, return leaving _arg_values as null130if (_argc == 0 && UseBootstrapCallInfo < 2) return;131132bool use_BSCI;133switch (UseBootstrapCallInfo) {134default: use_BSCI = true; break; // stress mode135case 0: use_BSCI = false; break; // stress mode136case 1: // normal mode137// If we were to support an alternative mode of BSM invocation,138// we'd convert to pull mode here if the BSM could be a candidate139// for that alternative mode. We can't easily test for things140// like varargs here, but we can get away with approximate testing,141// since the JDK runtime will make up the difference either way.142// For now, exercise the pull-mode path if the BSM is of arity 2,143// or if there is a potential condy loop (see below).144oop mt_oop = java_lang_invoke_MethodHandle::type(_bsm());145use_BSCI = (java_lang_invoke_MethodType::ptype_count(mt_oop) == 2);146break;147}148149// Here's a reason to use BSCI even if it wasn't requested:150// If a condy uses a condy argument, we want to avoid infinite151// recursion (condy loops) in the C code. It's OK in Java,152// because Java has stack overflow checking, so we punt153// potentially cyclic cases from C to Java.154if (!use_BSCI && _pool->tag_at(_bss_index).is_dynamic_constant()) {155bool found_unresolved_condy = false;156for (int i = 0; i < _argc; i++) {157int arg_index = _pool->bootstrap_argument_index_at(_bss_index, i);158if (_pool->tag_at(arg_index).is_dynamic_constant()) {159// potential recursion point condy -> condy160bool found_it = false;161_pool->find_cached_constant_at(arg_index, found_it, CHECK);162if (!found_it) { found_unresolved_condy = true; break; }163}164}165if (found_unresolved_condy)166use_BSCI = true;167}168169const int SMALL_ARITY = 5;170if (use_BSCI && _argc <= SMALL_ARITY && UseBootstrapCallInfo <= 2) {171// If there are only a few arguments, and none of them need linking,172// push them, instead of asking the JDK runtime to turn around and173// pull them, saving a JVM/JDK transition in some simple cases.174bool all_resolved = true;175for (int i = 0; i < _argc; i++) {176bool found_it = false;177int arg_index = _pool->bootstrap_argument_index_at(_bss_index, i);178_pool->find_cached_constant_at(arg_index, found_it, CHECK);179if (!found_it) { all_resolved = false; break; }180}181if (all_resolved)182use_BSCI = false;183}184185if (!use_BSCI) {186// return {arg...}; resolution of arguments is done immediately, before JDK code is called187objArrayOop args_oop = oopFactory::new_objArray(vmClasses::Object_klass(), _argc, CHECK);188objArrayHandle args(THREAD, args_oop);189_pool->copy_bootstrap_arguments_at(_bss_index, 0, _argc, args, 0, true, Handle(), CHECK);190oop arg_oop = ((_argc == 1) ? args->obj_at(0) : (oop)NULL);191// try to discard the singleton array192if (arg_oop != NULL && !arg_oop->is_array()) {193// JVM treats arrays and nulls specially in this position,194// but other things are just single arguments195_arg_values = Handle(THREAD, arg_oop);196} else {197_arg_values = args;198}199} else {200// return {arg_count, pool_index}; JDK code must pull the arguments as needed201typeArrayOop ints_oop = oopFactory::new_typeArray(T_INT, 2, CHECK);202ints_oop->int_at_put(0, _argc);203ints_oop->int_at_put(1, _bss_index);204_arg_values = Handle(THREAD, ints_oop);205}206}207208// there must be a LinkageError pending; try to save it and then throw209bool BootstrapInfo::save_and_throw_indy_exc(TRAPS) {210assert(HAS_PENDING_EXCEPTION, "");211assert(_indy_index != -1, "");212ConstantPoolCacheEntry* cpce = invokedynamic_cp_cache_entry();213int encoded_index = ResolutionErrorTable::encode_cpcache_index(_indy_index);214bool recorded_res_status = cpce->save_and_throw_indy_exc(_pool, _bss_index,215encoded_index,216pool()->tag_at(_bss_index),217CHECK_false);218return recorded_res_status;219}220221void BootstrapInfo::resolve_newly_linked_invokedynamic(CallInfo& result, TRAPS) {222assert(is_resolved(), "");223result.set_handle(resolved_method(), resolved_appendix(), CHECK);224}225226void BootstrapInfo::print_msg_on(outputStream* st, const char* msg) {227ResourceMark rm;228char what[20];229st = st ? st : tty;230231if (_indy_index != -1)232sprintf(what, "indy#%d", decode_indy_index());233else234sprintf(what, "condy");235bool have_msg = (msg != NULL && strlen(msg) > 0);236st->print_cr("%s%sBootstrap in %s %s@CP[%d] %s:%s%s BSMS[%d] BSM@CP[%d]%s argc=%d%s",237(have_msg ? msg : ""), (have_msg ? " " : ""),238caller()->name()->as_C_string(),239what, // "indy#42" or "condy"240_bss_index,241_name->as_C_string(),242_signature->as_C_string(),243(_type_arg.is_null() ? "" : "(resolved)"),244bsms_attr_index(),245bsm_index(), (_bsm.is_null() ? "" : "(resolved)"),246_argc, (_arg_values.is_null() ? "" : "(resolved)"));247if (_argc > 0) {248char argbuf[80];249argbuf[0] = 0;250for (int i = 0; i < _argc; i++) {251int pos = (int) strlen(argbuf);252if (pos + 20 > (int)sizeof(argbuf)) {253sprintf(argbuf + pos, "...");254break;255}256if (i > 0) argbuf[pos++] = ',';257sprintf(argbuf+pos, "%d", arg_index(i));258}259st->print_cr(" argument indexes: {%s}", argbuf);260}261if (_bsm.not_null()) {262st->print(" resolved BSM: "); _bsm->print_on(st);263}264265// How the array of resolved arguments is printed depends highly266// on how BootstrapInfo::resolve_args structures the array based on267// the use_BSCI setting.268if (_arg_values.not_null()) {269// Find the static arguments within the first element of _arg_values.270objArrayOop static_args = (objArrayOop)_arg_values();271if (!static_args->is_array()) {272assert(_argc == 1, "Invalid BSM _arg_values for non-array");273st->print(" resolved arg[0]: "); static_args->print_on(st);274} else if (static_args->is_objArray()) {275int lines = 0;276for (int i = 0; i < _argc; i++) {277oop x = static_args->obj_at(i);278if (x != NULL) {279if (++lines > 6) {280st->print_cr(" resolved arg[%d]: ...", i);281break;282}283st->print(" resolved arg[%d]: ", i); x->print_on(st);284}285}286} else if (static_args->is_typeArray()) {287typeArrayOop tmp_array = (typeArrayOop) static_args;288assert(tmp_array->length() == 2, "Invalid BSM _arg_values type array");289st->print_cr(" resolved arg[0]: %d", tmp_array->int_at(0));290st->print_cr(" resolved arg[1]: %d", tmp_array->int_at(1));291}292}293}294295296