8218994: Consolidate indy and condy JVM information within a BootstrapInfo data structure
Introduce BootstrapInfo data structure and merge invocation of a bootstrap method for condy and indy into invoke_bootstrap_method. Co-authored-by: John Rose <john.r.rose@oracle.com> Reviewed-by: acorn, coleenp
This commit is contained in:
parent
fd3378a73e
commit
57aaf7a8cd
@ -2750,106 +2750,61 @@ Handle SystemDictionary::link_method_handle_constant(Klass* caller,
|
||||
return Handle(THREAD, (oop) result.get_jobject());
|
||||
}
|
||||
|
||||
// Ask Java to compute a constant by invoking a BSM given a Dynamic_info CP entry
|
||||
Handle SystemDictionary::link_dynamic_constant(Klass* caller,
|
||||
int condy_index,
|
||||
Handle bootstrap_specifier,
|
||||
Symbol* name,
|
||||
Symbol* type,
|
||||
TRAPS) {
|
||||
Handle empty;
|
||||
Handle bsm, info;
|
||||
if (java_lang_invoke_MethodHandle::is_instance(bootstrap_specifier())) {
|
||||
bsm = bootstrap_specifier;
|
||||
} else {
|
||||
assert(bootstrap_specifier->is_objArray(), "");
|
||||
objArrayOop args = (objArrayOop) bootstrap_specifier();
|
||||
assert(args->length() == 2, "");
|
||||
bsm = Handle(THREAD, args->obj_at(0));
|
||||
info = Handle(THREAD, args->obj_at(1));
|
||||
}
|
||||
guarantee(java_lang_invoke_MethodHandle::is_instance(bsm()),
|
||||
"caller must supply a valid BSM");
|
||||
// Ask Java to run a bootstrap method, in order to create a dynamic call site
|
||||
// while linking an invokedynamic op, or compute a constant for Dynamic_info CP entry
|
||||
// with linkage results being stored back into the bootstrap specifier.
|
||||
void SystemDictionary::invoke_bootstrap_method(BootstrapInfo& bootstrap_specifier, TRAPS) {
|
||||
// Resolve the bootstrap specifier, its name, type, and static arguments
|
||||
bootstrap_specifier.resolve_bsm(CHECK);
|
||||
|
||||
// This should not happen. JDK code should take care of that.
|
||||
if (caller == NULL) {
|
||||
THROW_MSG_(vmSymbols::java_lang_InternalError(), "bad dynamic constant", empty);
|
||||
if (bootstrap_specifier.caller() == NULL || bootstrap_specifier.type_arg().is_null()) {
|
||||
THROW_MSG(vmSymbols::java_lang_InternalError(), "Invalid bootstrap method invocation with no caller or type argument");
|
||||
}
|
||||
|
||||
Handle constant_name = java_lang_String::create_from_symbol(name, CHECK_(empty));
|
||||
bool is_indy = bootstrap_specifier.is_method_call();
|
||||
objArrayHandle appendix_box;
|
||||
if (is_indy) {
|
||||
// Some method calls may require an appendix argument. Arrange to receive it.
|
||||
appendix_box = oopFactory::new_objArray_handle(SystemDictionary::Object_klass(), 1, CHECK);
|
||||
assert(appendix_box->obj_at(0) == NULL, "");
|
||||
}
|
||||
|
||||
// Resolve the constant type in the context of the caller class
|
||||
Handle type_mirror = find_java_mirror_for_type(type, caller, SignatureStream::NCDFError,
|
||||
CHECK_(empty));
|
||||
|
||||
// call java.lang.invoke.MethodHandleNatives::linkConstantDyanmic(caller, condy_index, bsm, type, info)
|
||||
// call condy: java.lang.invoke.MethodHandleNatives::linkDynamicConstant(caller, condy_index, bsm, type, info)
|
||||
// indy: java.lang.invoke.MethodHandleNatives::linkCallSite(caller, indy_index, bsm, name, mtype, info, &appendix)
|
||||
JavaCallArguments args;
|
||||
args.push_oop(Handle(THREAD, caller->java_mirror()));
|
||||
args.push_int(condy_index);
|
||||
args.push_oop(bsm);
|
||||
args.push_oop(constant_name);
|
||||
args.push_oop(type_mirror);
|
||||
args.push_oop(info);
|
||||
args.push_oop(Handle(THREAD, bootstrap_specifier.caller_mirror()));
|
||||
args.push_int(bootstrap_specifier.bss_index());
|
||||
args.push_oop(bootstrap_specifier.bsm());
|
||||
args.push_oop(bootstrap_specifier.name_arg());
|
||||
args.push_oop(bootstrap_specifier.type_arg());
|
||||
args.push_oop(bootstrap_specifier.arg_values());
|
||||
if (is_indy) {
|
||||
args.push_oop(appendix_box);
|
||||
}
|
||||
JavaValue result(T_OBJECT);
|
||||
JavaCalls::call_static(&result,
|
||||
SystemDictionary::MethodHandleNatives_klass(),
|
||||
vmSymbols::linkDynamicConstant_name(),
|
||||
vmSymbols::linkDynamicConstant_signature(),
|
||||
&args, CHECK_(empty));
|
||||
is_indy ? vmSymbols::linkCallSite_name() : vmSymbols::linkDynamicConstant_name(),
|
||||
is_indy ? vmSymbols::linkCallSite_signature() : vmSymbols::linkDynamicConstant_signature(),
|
||||
&args, CHECK);
|
||||
|
||||
return Handle(THREAD, (oop) result.get_jobject());
|
||||
}
|
||||
|
||||
// Ask Java code to find or construct a java.lang.invoke.CallSite for the given
|
||||
// name and signature, as interpreted relative to the given class loader.
|
||||
methodHandle SystemDictionary::find_dynamic_call_site_invoker(Klass* caller,
|
||||
int indy_index,
|
||||
Handle bootstrap_specifier,
|
||||
Symbol* name,
|
||||
Symbol* type,
|
||||
Handle *appendix_result,
|
||||
TRAPS) {
|
||||
methodHandle empty;
|
||||
Handle bsm, info;
|
||||
if (java_lang_invoke_MethodHandle::is_instance(bootstrap_specifier())) {
|
||||
bsm = bootstrap_specifier;
|
||||
Handle value(THREAD, (oop) result.get_jobject());
|
||||
if (is_indy) {
|
||||
Handle appendix;
|
||||
methodHandle method = unpack_method_and_appendix(value,
|
||||
bootstrap_specifier.caller(),
|
||||
appendix_box,
|
||||
&appendix, CHECK);
|
||||
bootstrap_specifier.set_resolved_method(method, appendix);
|
||||
} else {
|
||||
objArrayOop args = (objArrayOop) bootstrap_specifier();
|
||||
assert(args->length() == 2, "");
|
||||
bsm = Handle(THREAD, args->obj_at(0));
|
||||
info = Handle(THREAD, args->obj_at(1));
|
||||
}
|
||||
guarantee(java_lang_invoke_MethodHandle::is_instance(bsm()),
|
||||
"caller must supply a valid BSM");
|
||||
|
||||
Handle method_name = java_lang_String::create_from_symbol(name, CHECK_(empty));
|
||||
Handle method_type = find_method_handle_type(type, caller, CHECK_(empty));
|
||||
|
||||
// This should not happen. JDK code should take care of that.
|
||||
if (caller == NULL || method_type.is_null()) {
|
||||
THROW_MSG_(vmSymbols::java_lang_InternalError(), "bad invokedynamic", empty);
|
||||
bootstrap_specifier.set_resolved_value(value);
|
||||
}
|
||||
|
||||
objArrayHandle appendix_box = oopFactory::new_objArray_handle(SystemDictionary::Object_klass(), 1, CHECK_(empty));
|
||||
assert(appendix_box->obj_at(0) == NULL, "");
|
||||
|
||||
// call java.lang.invoke.MethodHandleNatives::linkCallSite(caller, indy_index, bsm, name, mtype, info, &appendix)
|
||||
JavaCallArguments args;
|
||||
args.push_oop(Handle(THREAD, caller->java_mirror()));
|
||||
args.push_int(indy_index);
|
||||
args.push_oop(bsm);
|
||||
args.push_oop(method_name);
|
||||
args.push_oop(method_type);
|
||||
args.push_oop(info);
|
||||
args.push_oop(appendix_box);
|
||||
JavaValue result(T_OBJECT);
|
||||
JavaCalls::call_static(&result,
|
||||
SystemDictionary::MethodHandleNatives_klass(),
|
||||
vmSymbols::linkCallSite_name(),
|
||||
vmSymbols::linkCallSite_signature(),
|
||||
&args, CHECK_(empty));
|
||||
Handle mname(THREAD, (oop) result.get_jobject());
|
||||
return unpack_method_and_appendix(mname, caller, appendix_box, appendix_result, THREAD);
|
||||
// sanity check
|
||||
assert(bootstrap_specifier.is_resolved() ||
|
||||
(bootstrap_specifier.is_method_call() &&
|
||||
bootstrap_specifier.resolved_method().not_null()), "bootstrap method call failed");
|
||||
}
|
||||
|
||||
// Protection domain cache table handling
|
||||
|
@ -74,6 +74,7 @@
|
||||
// of placeholders must hold the SystemDictionary_lock.
|
||||
//
|
||||
|
||||
class BootstrapInfo;
|
||||
class ClassFileStream;
|
||||
class Dictionary;
|
||||
class PlaceholderTable;
|
||||
@ -221,6 +222,7 @@ class OopStorage;
|
||||
|
||||
|
||||
class SystemDictionary : AllStatic {
|
||||
friend class BootstrapInfo;
|
||||
friend class VMStructs;
|
||||
friend class SystemDictionaryHandles;
|
||||
|
||||
@ -531,21 +533,7 @@ public:
|
||||
TRAPS);
|
||||
|
||||
// ask Java to compute a constant by invoking a BSM given a Dynamic_info CP entry
|
||||
static Handle link_dynamic_constant(Klass* caller,
|
||||
int condy_index,
|
||||
Handle bootstrap_specifier,
|
||||
Symbol* name,
|
||||
Symbol* type,
|
||||
TRAPS);
|
||||
|
||||
// ask Java to create a dynamic call site, while linking an invokedynamic op
|
||||
static methodHandle find_dynamic_call_site_invoker(Klass* caller,
|
||||
int indy_index,
|
||||
Handle bootstrap_method,
|
||||
Symbol* name,
|
||||
Symbol* type,
|
||||
Handle *appendix_result,
|
||||
TRAPS);
|
||||
static void invoke_bootstrap_method(BootstrapInfo& bootstrap_specifier, TRAPS);
|
||||
|
||||
// Record the error when the first attempt to resolve a reference from a constant
|
||||
// pool entry to a class fails.
|
||||
|
287
src/hotspot/share/interpreter/bootstrapInfo.cpp
Normal file
287
src/hotspot/share/interpreter/bootstrapInfo.cpp
Normal file
@ -0,0 +1,287 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "jvm.h"
|
||||
#include "classfile/javaClasses.inline.hpp"
|
||||
#include "classfile/resolutionErrors.hpp"
|
||||
#include "interpreter/bootstrapInfo.hpp"
|
||||
#include "interpreter/linkResolver.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
#include "memory/oopFactory.hpp"
|
||||
#include "oops/cpCache.inline.hpp"
|
||||
#include "oops/objArrayOop.inline.hpp"
|
||||
#include "oops/typeArrayOop.inline.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
// Implementation of BootstrapInfo
|
||||
|
||||
BootstrapInfo::BootstrapInfo(const constantPoolHandle& pool, int bss_index, int indy_index)
|
||||
: _pool(pool),
|
||||
_bss_index(bss_index),
|
||||
_indy_index(indy_index),
|
||||
// derived and eagerly cached:
|
||||
_argc( pool->bootstrap_argument_count_at(bss_index) ),
|
||||
_name( pool->uncached_name_ref_at(bss_index) ),
|
||||
_signature( pool->uncached_signature_ref_at(bss_index) )
|
||||
{
|
||||
_is_resolved = false;
|
||||
assert(pool->tag_at(bss_index).has_bootstrap(), "");
|
||||
assert(indy_index == -1 || pool->invokedynamic_bootstrap_ref_index_at(indy_index) == bss_index, "invalid bootstrap specifier index");
|
||||
}
|
||||
|
||||
// If there is evidence this call site was already linked, set the
|
||||
// existing linkage data into result, or throw previous exception.
|
||||
// Return true if either action is taken, else false.
|
||||
bool BootstrapInfo::resolve_previously_linked_invokedynamic(CallInfo& result, TRAPS) {
|
||||
assert(_indy_index != -1, "");
|
||||
ConstantPoolCacheEntry* cpce = invokedynamic_cp_cache_entry();
|
||||
if (!cpce->is_f1_null()) {
|
||||
methodHandle method( THREAD, cpce->f1_as_method());
|
||||
Handle appendix( THREAD, cpce->appendix_if_resolved(_pool));
|
||||
result.set_handle(method, appendix, THREAD);
|
||||
Exceptions::wrap_dynamic_exception(CHECK_false);
|
||||
return true;
|
||||
} else if (cpce->indy_resolution_failed()) {
|
||||
int encoded_index = ResolutionErrorTable::encode_cpcache_index(_indy_index);
|
||||
ConstantPool::throw_resolution_error(_pool, encoded_index, CHECK_false);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve the bootstrap specifier in 3 steps:
|
||||
// - unpack the BSM by resolving the MH constant
|
||||
// - obtain the NameAndType description for the condy/indy
|
||||
// - prepare the BSM's static arguments
|
||||
Handle BootstrapInfo::resolve_bsm(TRAPS) {
|
||||
if (_bsm.not_null()) return _bsm;
|
||||
// The tag at the bootstrap method index must be a valid method handle or a method handle in error.
|
||||
// If it is a MethodHandleInError, a resolution error will be thrown which will be wrapped if necessary
|
||||
// with a BootstrapMethodError.
|
||||
assert(_pool->tag_at(bsm_index()).is_method_handle() ||
|
||||
_pool->tag_at(bsm_index()).is_method_handle_in_error(), "MH not present, classfile structural constraint");
|
||||
oop bsm_oop = _pool->resolve_possibly_cached_constant_at(bsm_index(), THREAD);
|
||||
Exceptions::wrap_dynamic_exception(CHECK_NH);
|
||||
guarantee(java_lang_invoke_MethodHandle::is_instance(bsm_oop), "classfile must supply a valid BSM");
|
||||
_bsm = Handle(THREAD, bsm_oop);
|
||||
|
||||
// Obtain NameAndType information
|
||||
resolve_bss_name_and_type(THREAD);
|
||||
Exceptions::wrap_dynamic_exception(CHECK_NH);
|
||||
|
||||
// Prepare static arguments
|
||||
resolve_args(THREAD);
|
||||
Exceptions::wrap_dynamic_exception(CHECK_NH);
|
||||
|
||||
return _bsm;
|
||||
}
|
||||
|
||||
// Resolve metadata from the JVM_Dynamic_info or JVM_InvokeDynamic_info's name and type information.
|
||||
void BootstrapInfo::resolve_bss_name_and_type(TRAPS) {
|
||||
assert(_bsm.not_null(), "resolve_bsm first");
|
||||
Symbol* name = this->name();
|
||||
Symbol* type = this->signature();
|
||||
_name_arg = java_lang_String::create_from_symbol(name, CHECK);
|
||||
if (type->char_at(0) == '(') {
|
||||
_type_arg = SystemDictionary::find_method_handle_type(type, caller(), CHECK);
|
||||
} else {
|
||||
_type_arg = SystemDictionary::find_java_mirror_for_type(type, caller(), SignatureStream::NCDFError, CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve the bootstrap method's static arguments and store the result in _arg_values.
|
||||
void BootstrapInfo::resolve_args(TRAPS) {
|
||||
assert(_bsm.not_null(), "resolve_bsm first");
|
||||
|
||||
// if there are no static arguments, return leaving _arg_values as null
|
||||
if (_argc == 0 && UseBootstrapCallInfo < 2) return;
|
||||
|
||||
bool use_BSCI;
|
||||
switch (UseBootstrapCallInfo) {
|
||||
default: use_BSCI = true; break; // stress mode
|
||||
case 0: use_BSCI = false; break; // stress mode
|
||||
case 1: // normal mode
|
||||
// If we were to support an alternative mode of BSM invocation,
|
||||
// we'd convert to pull mode here if the BSM could be a candidate
|
||||
// for that alternative mode. We can't easily test for things
|
||||
// like varargs here, but we can get away with approximate testing,
|
||||
// since the JDK runtime will make up the difference either way.
|
||||
// For now, exercise the pull-mode path if the BSM is of arity 2,
|
||||
// or if there is a potential condy loop (see below).
|
||||
oop mt_oop = java_lang_invoke_MethodHandle::type(_bsm());
|
||||
use_BSCI = (java_lang_invoke_MethodType::ptype_count(mt_oop) == 2);
|
||||
break;
|
||||
}
|
||||
|
||||
// Here's a reason to use BSCI even if it wasn't requested:
|
||||
// If a condy uses a condy argument, we want to avoid infinite
|
||||
// recursion (condy loops) in the C code. It's OK in Java,
|
||||
// because Java has stack overflow checking, so we punt
|
||||
// potentially cyclic cases from C to Java.
|
||||
if (!use_BSCI && _pool->tag_at(_bss_index).is_dynamic_constant()) {
|
||||
bool found_unresolved_condy = false;
|
||||
for (int i = 0; i < _argc; i++) {
|
||||
int arg_index = _pool->bootstrap_argument_index_at(_bss_index, i);
|
||||
if (_pool->tag_at(arg_index).is_dynamic_constant()) {
|
||||
// potential recursion point condy -> condy
|
||||
bool found_it = false;
|
||||
_pool->find_cached_constant_at(arg_index, found_it, CHECK);
|
||||
if (!found_it) { found_unresolved_condy = true; break; }
|
||||
}
|
||||
}
|
||||
if (found_unresolved_condy)
|
||||
use_BSCI = true;
|
||||
}
|
||||
|
||||
const int SMALL_ARITY = 5;
|
||||
if (use_BSCI && _argc <= SMALL_ARITY && UseBootstrapCallInfo <= 2) {
|
||||
// If there are only a few arguments, and none of them need linking,
|
||||
// push them, instead of asking the JDK runtime to turn around and
|
||||
// pull them, saving a JVM/JDK transition in some simple cases.
|
||||
bool all_resolved = true;
|
||||
for (int i = 0; i < _argc; i++) {
|
||||
bool found_it = false;
|
||||
int arg_index = _pool->bootstrap_argument_index_at(_bss_index, i);
|
||||
_pool->find_cached_constant_at(arg_index, found_it, CHECK);
|
||||
if (!found_it) { all_resolved = false; break; }
|
||||
}
|
||||
if (all_resolved)
|
||||
use_BSCI = false;
|
||||
}
|
||||
|
||||
if (!use_BSCI) {
|
||||
// return {arg...}; resolution of arguments is done immediately, before JDK code is called
|
||||
objArrayOop args_oop = oopFactory::new_objArray(SystemDictionary::Object_klass(), _argc, CHECK);
|
||||
objArrayHandle args(THREAD, args_oop);
|
||||
_pool->copy_bootstrap_arguments_at(_bss_index, 0, _argc, args, 0, true, Handle(), CHECK);
|
||||
oop arg_oop = ((_argc == 1) ? args->obj_at(0) : (oop)NULL);
|
||||
// try to discard the singleton array
|
||||
if (arg_oop != NULL && !arg_oop->is_array()) {
|
||||
// JVM treats arrays and nulls specially in this position,
|
||||
// but other things are just single arguments
|
||||
_arg_values = Handle(THREAD, arg_oop);
|
||||
} else {
|
||||
_arg_values = args;
|
||||
}
|
||||
} else {
|
||||
// return {arg_count, pool_index}; JDK code must pull the arguments as needed
|
||||
typeArrayOop ints_oop = oopFactory::new_typeArray(T_INT, 2, CHECK);
|
||||
ints_oop->int_at_put(0, _argc);
|
||||
ints_oop->int_at_put(1, _bss_index);
|
||||
_arg_values = Handle(THREAD, ints_oop);
|
||||
}
|
||||
}
|
||||
|
||||
// there must be a LinkageError pending; try to save it and then throw
|
||||
bool BootstrapInfo::save_and_throw_indy_exc(TRAPS) {
|
||||
assert(HAS_PENDING_EXCEPTION, "");
|
||||
assert(_indy_index != -1, "");
|
||||
ConstantPoolCacheEntry* cpce = invokedynamic_cp_cache_entry();
|
||||
int encoded_index = ResolutionErrorTable::encode_cpcache_index(_indy_index);
|
||||
bool recorded_res_status = cpce->save_and_throw_indy_exc(_pool, _bss_index,
|
||||
encoded_index,
|
||||
pool()->tag_at(_bss_index),
|
||||
CHECK_false);
|
||||
return recorded_res_status;
|
||||
}
|
||||
|
||||
void BootstrapInfo::resolve_newly_linked_invokedynamic(CallInfo& result, TRAPS) {
|
||||
assert(is_resolved(), "");
|
||||
result.set_handle(resolved_method(), resolved_appendix(), CHECK);
|
||||
}
|
||||
|
||||
void BootstrapInfo::print_msg_on(outputStream* st, const char* msg) {
|
||||
ResourceMark rm;
|
||||
char what[20];
|
||||
st = st ? st : tty;
|
||||
|
||||
if (_indy_index != -1)
|
||||
sprintf(what, "indy#%d", decode_indy_index());
|
||||
else
|
||||
sprintf(what, "condy");
|
||||
bool have_msg = (msg != NULL && strlen(msg) > 0);
|
||||
st->print_cr("%s%sBootstrap in %s %s@CP[%d] %s:%s%s BSMS[%d] BSM@CP[%d]%s argc=%d%s",
|
||||
(have_msg ? msg : ""), (have_msg ? " " : ""),
|
||||
caller()->name()->as_C_string(),
|
||||
what, // "indy#42" or "condy"
|
||||
_bss_index,
|
||||
_name->as_C_string(),
|
||||
_signature->as_C_string(),
|
||||
(_type_arg.is_null() ? "" : "(resolved)"),
|
||||
bsms_attr_index(),
|
||||
bsm_index(), (_bsm.is_null() ? "" : "(resolved)"),
|
||||
_argc, (_arg_values.is_null() ? "" : "(resolved)"));
|
||||
if (_argc > 0) {
|
||||
char argbuf[80];
|
||||
argbuf[0] = 0;
|
||||
for (int i = 0; i < _argc; i++) {
|
||||
int pos = (int) strlen(argbuf);
|
||||
if (pos + 20 > (int)sizeof(argbuf)) {
|
||||
sprintf(argbuf + pos, "...");
|
||||
break;
|
||||
}
|
||||
if (i > 0) argbuf[pos++] = ',';
|
||||
sprintf(argbuf+pos, "%d", arg_index(i));
|
||||
}
|
||||
st->print_cr(" argument indexes: {%s}", argbuf);
|
||||
}
|
||||
if (_bsm.not_null()) {
|
||||
st->print(" resolved BSM: "); _bsm->print();
|
||||
}
|
||||
|
||||
// How the array of resolved arguments is printed depends highly
|
||||
// on how BootstrapInfo::resolve_args structures the array based on
|
||||
// the use_BSCI setting.
|
||||
if (_arg_values.not_null()) {
|
||||
// Find the static arguments within the first element of _arg_values.
|
||||
objArrayOop static_args = (objArrayOop)_arg_values();
|
||||
if (!static_args->is_array()) {
|
||||
assert(_argc == 1, "Invalid BSM _arg_values for non-array");
|
||||
st->print(" resolved arg[0]: "); static_args->print();
|
||||
} else if (static_args->is_objArray()) {
|
||||
int lines = 0;
|
||||
for (int i = 0; i < _argc; i++) {
|
||||
oop x = static_args->obj_at(i);
|
||||
if (x != NULL) {
|
||||
if (++lines > 6) {
|
||||
st->print_cr(" resolved arg[%d]: ...", i);
|
||||
break;
|
||||
}
|
||||
st->print(" resolved arg[%d]: ", i); x->print();
|
||||
}
|
||||
}
|
||||
} else if (static_args->is_typeArray()) {
|
||||
typeArrayOop tmp_array = (typeArrayOop) static_args;
|
||||
assert(tmp_array->length() == 2, "Invalid BSM _arg_values type array");
|
||||
st->print_cr(" resolved arg[0]: %d", tmp_array->int_at(0));
|
||||
st->print_cr(" resolved arg[1]: %d", tmp_array->int_at(1));
|
||||
}
|
||||
}
|
||||
}
|
120
src/hotspot/share/interpreter/bootstrapInfo.hpp
Normal file
120
src/hotspot/share/interpreter/bootstrapInfo.hpp
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_INTERPRETER_BOOTSTRAPINFO_HPP
|
||||
#define SHARE_INTERPRETER_BOOTSTRAPINFO_HPP
|
||||
|
||||
#include "oops/constantPool.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
|
||||
// BootstrapInfo provides condensed information from the constant pool
|
||||
// necessary to invoke a bootstrap method.
|
||||
class BootstrapInfo : public StackObj {
|
||||
constantPoolHandle _pool; // constant pool containing the bootstrap specifier
|
||||
const int _bss_index; // index of bootstrap specifier in CP (condy or indy)
|
||||
const int _indy_index; // internal index of indy call site, or -1 if a condy call
|
||||
const int _argc; // number of static arguments
|
||||
Symbol* _name; // extracted from JVM_CONSTANT_NameAndType
|
||||
Symbol* _signature;
|
||||
|
||||
// pre-bootstrap resolution state:
|
||||
Handle _bsm; // resolved bootstrap method
|
||||
Handle _name_arg; // resolved String
|
||||
Handle _type_arg; // resolved Class or MethodType
|
||||
Handle _arg_values; // array of static arguments; null implies either
|
||||
// uresolved or zero static arguments are specified
|
||||
|
||||
// post-bootstrap resolution state:
|
||||
bool _is_resolved; // set true when any of the next fields are set
|
||||
Handle _resolved_value; // bind this as condy constant
|
||||
methodHandle _resolved_method; // bind this as indy behavior
|
||||
Handle _resolved_appendix; // extra opaque static argument for _resolved_method
|
||||
|
||||
public:
|
||||
BootstrapInfo(const constantPoolHandle& pool, int bss_index, int indy_index = -1);
|
||||
|
||||
// accessors
|
||||
const constantPoolHandle& pool() const{ return _pool; }
|
||||
int bss_index() const { return _bss_index; }
|
||||
int indy_index() const { return _indy_index; }
|
||||
int argc() const { return _argc; }
|
||||
bool is_method_call() const { return (_indy_index != -1); }
|
||||
Symbol* name() const { return _name; }
|
||||
Symbol* signature() const { return _signature; }
|
||||
|
||||
// accessors to lazy state
|
||||
Handle bsm() const { return _bsm; }
|
||||
Handle name_arg() const { return _name_arg; }
|
||||
Handle type_arg() const { return _type_arg; }
|
||||
Handle arg_values() const { return _arg_values; }
|
||||
bool is_resolved() const { return _is_resolved; }
|
||||
Handle resolved_value() const { assert(!is_method_call(), ""); return _resolved_value; }
|
||||
methodHandle resolved_method() const { assert(is_method_call(), ""); return _resolved_method; }
|
||||
Handle resolved_appendix() const { assert(is_method_call(), ""); return _resolved_appendix; }
|
||||
|
||||
// derived accessors
|
||||
InstanceKlass* caller() const { return _pool->pool_holder(); }
|
||||
oop caller_mirror() const { return caller()->java_mirror(); }
|
||||
int decode_indy_index() const { return ConstantPool::decode_invokedynamic_index(_indy_index); }
|
||||
int bsms_attr_index() const { return _pool->bootstrap_methods_attribute_index(_bss_index); }
|
||||
int bsm_index() const { return _pool->bootstrap_method_ref_index_at(_bss_index); }
|
||||
//int argc() is eagerly cached in _argc
|
||||
int arg_index(int i) const { return _pool->bootstrap_argument_index_at(_bss_index, i); }
|
||||
|
||||
// CP cache entry for call site (indy only)
|
||||
ConstantPoolCacheEntry* invokedynamic_cp_cache_entry() const {
|
||||
assert(is_method_call(), "");
|
||||
return _pool->invokedynamic_cp_cache_entry_at(_indy_index);
|
||||
}
|
||||
|
||||
// If there is evidence this call site was already linked, set the
|
||||
// existing linkage data into result, or throw previous exception.
|
||||
// Return true if either action is taken, else false.
|
||||
bool resolve_previously_linked_invokedynamic(CallInfo& result, TRAPS);
|
||||
bool save_and_throw_indy_exc(TRAPS);
|
||||
void resolve_newly_linked_invokedynamic(CallInfo& result, TRAPS);
|
||||
|
||||
// pre-bootstrap resolution actions:
|
||||
Handle resolve_bsm(TRAPS); // lazily compute _bsm and return it
|
||||
void resolve_bss_name_and_type(TRAPS); // lazily compute _name/_type
|
||||
void resolve_args(TRAPS); // compute arguments
|
||||
|
||||
// setters for post-bootstrap results:
|
||||
void set_resolved_value(Handle value) {
|
||||
assert(!is_resolved() && !is_method_call(), "");
|
||||
_is_resolved = true;
|
||||
_resolved_value = value;
|
||||
}
|
||||
void set_resolved_method(methodHandle method, Handle appendix) {
|
||||
assert(!is_resolved() && is_method_call(), "");
|
||||
_is_resolved = true;
|
||||
_resolved_method = method;
|
||||
_resolved_appendix = appendix;
|
||||
}
|
||||
|
||||
void print() { print_msg_on(tty); }
|
||||
void print_msg_on(outputStream* st, const char* msg = NULL);
|
||||
};
|
||||
|
||||
#endif // SHARE_INTERPRETER_BOOTSTRAPINFO_HPP
|
@ -32,6 +32,7 @@
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "compiler/compileBroker.hpp"
|
||||
#include "gc/shared/collectedHeap.inline.hpp"
|
||||
#include "interpreter/bootstrapInfo.hpp"
|
||||
#include "interpreter/bytecode.hpp"
|
||||
#include "interpreter/interpreterRuntime.hpp"
|
||||
#include "interpreter/linkResolver.hpp"
|
||||
@ -1694,99 +1695,80 @@ void LinkResolver::resolve_handle_call(CallInfo& result,
|
||||
result.set_handle(resolved_klass, resolved_method, resolved_appendix, CHECK);
|
||||
}
|
||||
|
||||
void LinkResolver::resolve_invokedynamic(CallInfo& result, const constantPoolHandle& pool, int index, TRAPS) {
|
||||
Symbol* method_name = pool->name_ref_at(index);
|
||||
Symbol* method_signature = pool->signature_ref_at(index);
|
||||
Klass* current_klass = pool->pool_holder();
|
||||
|
||||
// Resolve the bootstrap specifier (BSM + optional arguments).
|
||||
Handle bootstrap_specifier;
|
||||
// Check if CallSite has been bound already:
|
||||
ConstantPoolCacheEntry* cpce = pool->invokedynamic_cp_cache_entry_at(index);
|
||||
void LinkResolver::resolve_invokedynamic(CallInfo& result, const constantPoolHandle& pool, int indy_index, TRAPS) {
|
||||
ConstantPoolCacheEntry* cpce = pool->invokedynamic_cp_cache_entry_at(indy_index);
|
||||
int pool_index = cpce->constant_pool_index();
|
||||
|
||||
if (cpce->is_f1_null()) {
|
||||
if (cpce->indy_resolution_failed()) {
|
||||
ConstantPool::throw_resolution_error(pool,
|
||||
ResolutionErrorTable::encode_cpcache_index(index),
|
||||
CHECK);
|
||||
}
|
||||
// Resolve the bootstrap specifier (BSM + optional arguments).
|
||||
BootstrapInfo bootstrap_specifier(pool, pool_index, indy_index);
|
||||
|
||||
// The initial step in Call Site Specifier Resolution is to resolve the symbolic
|
||||
// reference to a method handle which will be the bootstrap method for a dynamic
|
||||
// call site. If resolution for the java.lang.invoke.MethodHandle for the bootstrap
|
||||
// method fails, then a MethodHandleInError is stored at the corresponding bootstrap
|
||||
// method's CP index for the CONSTANT_MethodHandle_info. So, there is no need to
|
||||
// set the indy_rf flag since any subsequent invokedynamic instruction which shares
|
||||
// this bootstrap method will encounter the resolution of MethodHandleInError.
|
||||
oop bsm_info = pool->resolve_bootstrap_specifier_at(pool_index, THREAD);
|
||||
Exceptions::wrap_dynamic_exception(CHECK);
|
||||
assert(bsm_info != NULL, "");
|
||||
// FIXME: Cache this once per BootstrapMethods entry, not once per CONSTANT_InvokeDynamic.
|
||||
bootstrap_specifier = Handle(THREAD, bsm_info);
|
||||
}
|
||||
if (!cpce->is_f1_null()) {
|
||||
methodHandle method( THREAD, cpce->f1_as_method());
|
||||
Handle appendix( THREAD, cpce->appendix_if_resolved(pool));
|
||||
result.set_handle(method, appendix, THREAD);
|
||||
Exceptions::wrap_dynamic_exception(CHECK);
|
||||
return;
|
||||
// Check if CallSite has been bound already or failed already, and short circuit:
|
||||
{
|
||||
bool is_done = bootstrap_specifier.resolve_previously_linked_invokedynamic(result, CHECK);
|
||||
if (is_done) return;
|
||||
}
|
||||
|
||||
// The initial step in Call Site Specifier Resolution is to resolve the symbolic
|
||||
// reference to a method handle which will be the bootstrap method for a dynamic
|
||||
// call site. If resolution for the java.lang.invoke.MethodHandle for the bootstrap
|
||||
// method fails, then a MethodHandleInError is stored at the corresponding bootstrap
|
||||
// method's CP index for the CONSTANT_MethodHandle_info. So, there is no need to
|
||||
// set the indy_rf flag since any subsequent invokedynamic instruction which shares
|
||||
// this bootstrap method will encounter the resolution of MethodHandleInError.
|
||||
|
||||
resolve_dynamic_call(result, bootstrap_specifier, CHECK);
|
||||
|
||||
if (TraceMethodHandles) {
|
||||
ResourceMark rm(THREAD);
|
||||
tty->print_cr("resolve_invokedynamic #%d %s %s in %s",
|
||||
ConstantPool::decode_invokedynamic_index(index),
|
||||
method_name->as_C_string(), method_signature->as_C_string(),
|
||||
current_klass->name()->as_C_string());
|
||||
tty->print(" BSM info: "); bootstrap_specifier->print();
|
||||
bootstrap_specifier.print_msg_on(tty, "resolve_invokedynamic");
|
||||
}
|
||||
|
||||
resolve_dynamic_call(result, pool_index, bootstrap_specifier, method_name,
|
||||
method_signature, current_klass, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION && PENDING_EXCEPTION->is_a(SystemDictionary::LinkageError_klass())) {
|
||||
int encoded_index = ResolutionErrorTable::encode_cpcache_index(index);
|
||||
bool recorded_res_status = cpce->save_and_throw_indy_exc(pool, pool_index,
|
||||
encoded_index,
|
||||
pool()->tag_at(pool_index),
|
||||
CHECK);
|
||||
if (!recorded_res_status) {
|
||||
// Another thread got here just before we did. So, either use the method
|
||||
// that it resolved or throw the LinkageError exception that it threw.
|
||||
if (!cpce->is_f1_null()) {
|
||||
methodHandle method( THREAD, cpce->f1_as_method());
|
||||
Handle appendix( THREAD, cpce->appendix_if_resolved(pool));
|
||||
result.set_handle(method, appendix, THREAD);
|
||||
Exceptions::wrap_dynamic_exception(CHECK);
|
||||
} else {
|
||||
assert(cpce->indy_resolution_failed(), "Resolution failure flag not set");
|
||||
ConstantPool::throw_resolution_error(pool, encoded_index, CHECK);
|
||||
}
|
||||
return;
|
||||
}
|
||||
assert(cpce->indy_resolution_failed(), "Resolution failure flag wasn't set");
|
||||
}
|
||||
// The returned linkage result is provisional up to the moment
|
||||
// the interpreter or runtime performs a serialized check of
|
||||
// the relevant CPCE::f1 field. This is done by the caller
|
||||
// of this method, via CPCE::set_dynamic_call, which uses
|
||||
// an ObjectLocker to do the final serialization of updates
|
||||
// to CPCE state, including f1.
|
||||
}
|
||||
|
||||
void LinkResolver::resolve_dynamic_call(CallInfo& result,
|
||||
int pool_index,
|
||||
Handle bootstrap_specifier,
|
||||
Symbol* method_name, Symbol* method_signature,
|
||||
Klass* current_klass,
|
||||
BootstrapInfo& bootstrap_specifier,
|
||||
TRAPS) {
|
||||
// JSR 292: this must resolve to an implicitly generated method MH.linkToCallSite(*...)
|
||||
// JSR 292: this must resolve to an implicitly generated method
|
||||
// such as MH.linkToCallSite(*...) or some other call-site shape.
|
||||
// The appendix argument is likely to be a freshly-created CallSite.
|
||||
Handle resolved_appendix;
|
||||
methodHandle resolved_method =
|
||||
SystemDictionary::find_dynamic_call_site_invoker(current_klass,
|
||||
pool_index,
|
||||
bootstrap_specifier,
|
||||
method_name, method_signature,
|
||||
&resolved_appendix,
|
||||
THREAD);
|
||||
Exceptions::wrap_dynamic_exception(CHECK);
|
||||
result.set_handle(resolved_method, resolved_appendix, THREAD);
|
||||
Exceptions::wrap_dynamic_exception(CHECK);
|
||||
// It may also be a MethodHandle from an unwrapped ConstantCallSite,
|
||||
// or any other reference. The resolved_method as well as the appendix
|
||||
// are both recorded together via CallInfo::set_handle.
|
||||
SystemDictionary::invoke_bootstrap_method(bootstrap_specifier, THREAD);
|
||||
Exceptions::wrap_dynamic_exception(THREAD);
|
||||
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
if (!PENDING_EXCEPTION->is_a(SystemDictionary::LinkageError_klass())) {
|
||||
// Let any random low-level IE or SOE or OOME just bleed through.
|
||||
// Basically we pretend that the bootstrap method was never called,
|
||||
// if it fails this way: We neither record a successful linkage,
|
||||
// nor do we memorize a LE for posterity.
|
||||
return;
|
||||
}
|
||||
// JVMS 5.4.3 says: If an attempt by the Java Virtual Machine to resolve
|
||||
// a symbolic reference fails because an error is thrown that is an
|
||||
// instance of LinkageError (or a subclass), then subsequent attempts to
|
||||
// resolve the reference always fail with the same error that was thrown
|
||||
// as a result of the initial resolution attempt.
|
||||
bool recorded_res_status = bootstrap_specifier.save_and_throw_indy_exc(CHECK);
|
||||
if (!recorded_res_status) {
|
||||
// Another thread got here just before we did. So, either use the method
|
||||
// that it resolved or throw the LinkageError exception that it threw.
|
||||
bool is_done = bootstrap_specifier.resolve_previously_linked_invokedynamic(result, CHECK);
|
||||
if (is_done) return;
|
||||
}
|
||||
assert(bootstrap_specifier.invokedynamic_cp_cache_entry()->indy_resolution_failed(),
|
||||
"Resolution failure flag wasn't set");
|
||||
}
|
||||
|
||||
bootstrap_specifier.resolve_newly_linked_invokedynamic(result, CHECK);
|
||||
// Exceptions::wrap_dynamic_exception not used because
|
||||
// set_handle doesn't throw linkage errors
|
||||
}
|
||||
|
||||
// Selected method is abstract.
|
||||
|
@ -25,6 +25,7 @@
|
||||
#ifndef SHARE_INTERPRETER_LINKRESOLVER_HPP
|
||||
#define SHARE_INTERPRETER_LINKRESOLVER_HPP
|
||||
|
||||
#include "interpreter/bootstrapInfo.hpp"
|
||||
#include "oops/method.hpp"
|
||||
|
||||
// All the necessary definitions for run-time link resolution.
|
||||
@ -77,6 +78,7 @@ class CallInfo : public StackObj {
|
||||
CallKind kind,
|
||||
int index, TRAPS);
|
||||
|
||||
friend class BootstrapInfo;
|
||||
friend class LinkResolver;
|
||||
|
||||
public:
|
||||
@ -311,9 +313,8 @@ class LinkResolver: AllStatic {
|
||||
bool check_null_and_abstract, TRAPS);
|
||||
static void resolve_handle_call (CallInfo& result,
|
||||
const LinkInfo& link_info, TRAPS);
|
||||
static void resolve_dynamic_call (CallInfo& result, int pool_index, Handle bootstrap_specifier,
|
||||
Symbol* method_name, Symbol* method_signature,
|
||||
Klass* current_klass, TRAPS);
|
||||
static void resolve_dynamic_call (CallInfo& result,
|
||||
BootstrapInfo& bootstrap_specifier, TRAPS);
|
||||
|
||||
// same as above for compile-time resolution; but returns null handle instead of throwing
|
||||
// an exception on error also, does not initialize klass (i.e., no side effects)
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "classfile/stringTable.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "interpreter/bootstrapInfo.hpp"
|
||||
#include "interpreter/linkResolver.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/heapInspection.hpp"
|
||||
@ -909,9 +910,8 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp,
|
||||
|
||||
case JVM_CONSTANT_Dynamic:
|
||||
{
|
||||
Klass* current_klass = this_cp->pool_holder();
|
||||
Symbol* constant_name = this_cp->uncached_name_ref_at(index);
|
||||
Symbol* constant_type = this_cp->uncached_signature_ref_at(index);
|
||||
// Resolve the Dynamically-Computed constant to invoke the BSM in order to obtain the resulting oop.
|
||||
BootstrapInfo bootstrap_specifier(this_cp, index);
|
||||
|
||||
// The initial step in resolving an unresolved symbolic reference to a
|
||||
// dynamically-computed constant is to resolve the symbolic reference to a
|
||||
@ -921,27 +921,18 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp,
|
||||
// bootstrap method's CP index for the CONSTANT_MethodHandle_info. No need to
|
||||
// set a DynamicConstantInError here since any subsequent use of this
|
||||
// bootstrap method will encounter the resolution of MethodHandleInError.
|
||||
oop bsm_info = this_cp->resolve_bootstrap_specifier_at(index, THREAD);
|
||||
Exceptions::wrap_dynamic_exception(CHECK_NULL);
|
||||
assert(bsm_info != NULL, "");
|
||||
// FIXME: Cache this once per BootstrapMethods entry, not once per CONSTANT_Dynamic.
|
||||
Handle bootstrap_specifier = Handle(THREAD, bsm_info);
|
||||
|
||||
// Resolve the Dynamically-Computed constant to invoke the BSM in order to obtain the resulting oop.
|
||||
Handle value = SystemDictionary::link_dynamic_constant(current_klass,
|
||||
index,
|
||||
bootstrap_specifier,
|
||||
constant_name,
|
||||
constant_type,
|
||||
THREAD);
|
||||
result_oop = value();
|
||||
// Both the first, (resolution of the BSM and its static arguments), and the second tasks,
|
||||
// (invocation of the BSM), of JVMS Section 5.4.3.6 occur within invoke_bootstrap_method()
|
||||
// for the bootstrap_specifier created above.
|
||||
SystemDictionary::invoke_bootstrap_method(bootstrap_specifier, THREAD);
|
||||
Exceptions::wrap_dynamic_exception(THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
// Resolution failure of the dynamically-computed constant, save_and_throw_exception
|
||||
// will check for a LinkageError and store a DynamicConstantInError.
|
||||
save_and_throw_exception(this_cp, index, tag, CHECK_NULL);
|
||||
}
|
||||
BasicType type = FieldType::basic_type(constant_type);
|
||||
result_oop = bootstrap_specifier.resolved_value()();
|
||||
BasicType type = FieldType::basic_type(bootstrap_specifier.signature());
|
||||
if (!is_reference_type(type)) {
|
||||
// Make sure the primitive value is properly boxed.
|
||||
// This is a JDK responsibility.
|
||||
@ -961,6 +952,10 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp,
|
||||
THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), fail);
|
||||
}
|
||||
}
|
||||
|
||||
if (TraceMethodHandles) {
|
||||
bootstrap_specifier.print_msg_on(tty, "resolve_constant_at_impl");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1102,119 +1097,6 @@ oop ConstantPool::uncached_string_at(int which, TRAPS) {
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
oop ConstantPool::resolve_bootstrap_specifier_at_impl(const constantPoolHandle& this_cp, int index, TRAPS) {
|
||||
assert((this_cp->tag_at(index).is_invoke_dynamic() ||
|
||||
this_cp->tag_at(index).is_dynamic_constant()), "Corrupted constant pool");
|
||||
Handle bsm;
|
||||
int argc;
|
||||
{
|
||||
// JVM_CONSTANT_InvokeDynamic is an ordered pair of [bootm, name&mtype], plus optional arguments
|
||||
// JVM_CONSTANT_Dynamic is an ordered pair of [bootm, name&ftype], plus optional arguments
|
||||
// In both cases, the bootm, being a JVM_CONSTANT_MethodHandle, has its own cache entry.
|
||||
// It is accompanied by the optional arguments.
|
||||
int bsm_index = this_cp->bootstrap_method_ref_index_at(index);
|
||||
oop bsm_oop = this_cp->resolve_possibly_cached_constant_at(bsm_index, CHECK_NULL);
|
||||
if (!java_lang_invoke_MethodHandle::is_instance(bsm_oop)) {
|
||||
THROW_MSG_NULL(vmSymbols::java_lang_LinkageError(), "BSM not an MethodHandle");
|
||||
}
|
||||
|
||||
// Extract the optional static arguments.
|
||||
argc = this_cp->bootstrap_argument_count_at(index);
|
||||
|
||||
// if there are no static arguments, return the bsm by itself:
|
||||
if (argc == 0 && UseBootstrapCallInfo < 2) return bsm_oop;
|
||||
|
||||
bsm = Handle(THREAD, bsm_oop);
|
||||
}
|
||||
|
||||
// We are going to return an ordered pair of {bsm, info}, using a 2-array.
|
||||
objArrayHandle info;
|
||||
{
|
||||
objArrayOop info_oop = oopFactory::new_objArray(SystemDictionary::Object_klass(), 2, CHECK_NULL);
|
||||
info = objArrayHandle(THREAD, info_oop);
|
||||
}
|
||||
|
||||
info->obj_at_put(0, bsm());
|
||||
|
||||
bool use_BSCI;
|
||||
switch (UseBootstrapCallInfo) {
|
||||
default: use_BSCI = true; break; // stress mode
|
||||
case 0: use_BSCI = false; break; // stress mode
|
||||
case 1: // normal mode
|
||||
// If we were to support an alternative mode of BSM invocation,
|
||||
// we'd convert to pull mode here if the BSM could be a candidate
|
||||
// for that alternative mode. We can't easily test for things
|
||||
// like varargs here, but we can get away with approximate testing,
|
||||
// since the JDK runtime will make up the difference either way.
|
||||
// For now, exercise the pull-mode path if the BSM is of arity 2,
|
||||
// or if there is a potential condy loop (see below).
|
||||
oop mt_oop = java_lang_invoke_MethodHandle::type(bsm());
|
||||
use_BSCI = (java_lang_invoke_MethodType::ptype_count(mt_oop) == 2);
|
||||
break;
|
||||
}
|
||||
|
||||
// Here's a reason to use BSCI even if it wasn't requested:
|
||||
// If a condy uses a condy argument, we want to avoid infinite
|
||||
// recursion (condy loops) in the C code. It's OK in Java,
|
||||
// because Java has stack overflow checking, so we punt
|
||||
// potentially cyclic cases from C to Java.
|
||||
if (!use_BSCI && this_cp->tag_at(index).is_dynamic_constant()) {
|
||||
bool found_unresolved_condy = false;
|
||||
for (int i = 0; i < argc; i++) {
|
||||
int arg_index = this_cp->bootstrap_argument_index_at(index, i);
|
||||
if (this_cp->tag_at(arg_index).is_dynamic_constant()) {
|
||||
// potential recursion point condy -> condy
|
||||
bool found_it = false;
|
||||
this_cp->find_cached_constant_at(arg_index, found_it, CHECK_NULL);
|
||||
if (!found_it) { found_unresolved_condy = true; break; }
|
||||
}
|
||||
}
|
||||
if (found_unresolved_condy)
|
||||
use_BSCI = true;
|
||||
}
|
||||
|
||||
const int SMALL_ARITY = 5;
|
||||
if (use_BSCI && argc <= SMALL_ARITY && UseBootstrapCallInfo <= 2) {
|
||||
// If there are only a few arguments, and none of them need linking,
|
||||
// push them, instead of asking the JDK runtime to turn around and
|
||||
// pull them, saving a JVM/JDK transition in some simple cases.
|
||||
bool all_resolved = true;
|
||||
for (int i = 0; i < argc; i++) {
|
||||
bool found_it = false;
|
||||
int arg_index = this_cp->bootstrap_argument_index_at(index, i);
|
||||
this_cp->find_cached_constant_at(arg_index, found_it, CHECK_NULL);
|
||||
if (!found_it) { all_resolved = false; break; }
|
||||
}
|
||||
if (all_resolved)
|
||||
use_BSCI = false;
|
||||
}
|
||||
|
||||
if (!use_BSCI) {
|
||||
// return {bsm, {arg...}}; resolution of arguments is done immediately, before JDK code is called
|
||||
objArrayOop args_oop = oopFactory::new_objArray(SystemDictionary::Object_klass(), argc, CHECK_NULL);
|
||||
info->obj_at_put(1, args_oop); // may overwrite with args[0] below
|
||||
objArrayHandle args(THREAD, args_oop);
|
||||
copy_bootstrap_arguments_at_impl(this_cp, index, 0, argc, args, 0, true, Handle(), CHECK_NULL);
|
||||
if (argc == 1) {
|
||||
// try to discard the singleton array
|
||||
oop arg_oop = args->obj_at(0);
|
||||
if (arg_oop != NULL && !arg_oop->is_array()) {
|
||||
// JVM treats arrays and nulls specially in this position,
|
||||
// but other things are just single arguments
|
||||
info->obj_at_put(1, arg_oop);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// return {bsm, {arg_count, pool_index}}; JDK code must pull the arguments as needed
|
||||
typeArrayOop ints_oop = oopFactory::new_typeArray(T_INT, 2, CHECK_NULL);
|
||||
ints_oop->int_at_put(0, argc);
|
||||
ints_oop->int_at_put(1, index);
|
||||
info->obj_at_put(1, ints_oop);
|
||||
}
|
||||
return info();
|
||||
}
|
||||
|
||||
void ConstantPool::copy_bootstrap_arguments_at_impl(const constantPoolHandle& this_cp, int index,
|
||||
int start_arg, int end_arg,
|
||||
objArrayHandle info, int pos,
|
||||
@ -1848,8 +1730,8 @@ bool ConstantPool::compare_operand_to(int idx1, const constantPoolHandle& cp2, i
|
||||
} // end compare_operand_to()
|
||||
|
||||
// Search constant pool search_cp for a bootstrap specifier that matches
|
||||
// this constant pool's bootstrap specifier at pattern_i index.
|
||||
// Return the index of a matching bootstrap specifier or (-1) if there is no match.
|
||||
// this constant pool's bootstrap specifier data at pattern_i index.
|
||||
// Return the index of a matching bootstrap attribute record or (-1) if there is no match.
|
||||
int ConstantPool::find_matching_operand(int pattern_i,
|
||||
const constantPoolHandle& search_cp, int search_len, TRAPS) {
|
||||
for (int i = 0; i < search_len; i++) {
|
||||
@ -1858,7 +1740,7 @@ int ConstantPool::find_matching_operand(int pattern_i,
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1; // bootstrap specifier not found; return unused index (-1)
|
||||
return -1; // bootstrap specifier data not found; return unused index (-1)
|
||||
} // end find_matching_operand()
|
||||
|
||||
|
||||
|
@ -746,11 +746,6 @@ class ConstantPool : public Metadata {
|
||||
return resolve_constant_at_impl(h_this, pool_index, _possible_index_sentinel, &found_it, THREAD);
|
||||
}
|
||||
|
||||
oop resolve_bootstrap_specifier_at(int index, TRAPS) {
|
||||
constantPoolHandle h_this(THREAD, this);
|
||||
return resolve_bootstrap_specifier_at_impl(h_this, index, THREAD);
|
||||
}
|
||||
|
||||
void copy_bootstrap_arguments_at(int index,
|
||||
int start_arg, int end_arg,
|
||||
objArrayHandle info, int pos,
|
||||
@ -871,7 +866,6 @@ class ConstantPool : public Metadata {
|
||||
|
||||
static oop resolve_constant_at_impl(const constantPoolHandle& this_cp, int index, int cache_index,
|
||||
bool* status_return, TRAPS);
|
||||
static oop resolve_bootstrap_specifier_at_impl(const constantPoolHandle& this_cp, int index, TRAPS);
|
||||
static void copy_bootstrap_arguments_at_impl(const constantPoolHandle& this_cp, int index,
|
||||
int start_arg, int end_arg,
|
||||
objArrayHandle info, int pos,
|
||||
|
Loading…
x
Reference in New Issue
Block a user