8210012: Implement Unified Logging Option for -XX:+TraceMethodHandles and -XX:+TraceInvokeDynamic

Transition the tracing method handles command line options to unified logging, -Xlog:methodhandles.

Reviewed-by: dholmes, iklam, jrose
This commit is contained in:
Lois Foltan 2020-04-15 21:01:02 +00:00
parent ed18906c08
commit d37985cd70
23 changed files with 364 additions and 121 deletions

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2020, 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
@ -31,6 +31,7 @@
#include "classfile/javaClasses.inline.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
#include "logging/log.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "prims/methodHandles.hpp"
@ -540,7 +541,7 @@ void trace_method_handle_stub(const char* adaptername,
}
void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adaptername) {
if (!TraceMethodHandles) return;
if (!log_is_enabled(Info, methodhandles)) return;
BLOCK_COMMENT("trace_method_handle {");
// register saving
// must correspond to trace_mh_nregs and trace_mh_regs defined above

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -28,6 +28,7 @@
#include "asm/macroAssembler.inline.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "interpreter/interpreter.hpp"
#include "logging/log.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "prims/methodHandles.hpp"
@ -264,7 +265,7 @@ address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler*
DEBUG_ONLY(param_size = noreg);
}
if (TraceMethodHandles) {
if (log_is_enabled(Info, methodhandles)) {
if (tmp_mh != noreg) {
__ mr(R23_method_handle, tmp_mh); // make stub happy
}
@ -545,7 +546,7 @@ void trace_method_handle_stub(const char* adaptername,
}
void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adaptername) {
if (!TraceMethodHandles) return;
if (!log_is_enabled(Info, methodhandles)) return;
BLOCK_COMMENT("trace_method_handle {");

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -28,6 +28,7 @@
#include "asm/macroAssembler.inline.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "interpreter/interpreter.hpp"
#include "logging/log.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "prims/methodHandles.hpp"
@ -616,7 +617,7 @@ void trace_method_handle_stub(const char* adaptername,
}
void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adaptername) {
if (!TraceMethodHandles) { return; }
if (!log_is_enabled(Info, methodhandles)) { return; }
// If arg registers are contiguous, we can use STMG/LMG.
assert((Z_ARG5->encoding() - Z_ARG1->encoding() + 1) == RegisterImpl::number_of_arg_registers, "Oops");

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2020, 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
@ -28,6 +28,7 @@
#include "classfile/javaClasses.inline.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interp_masm.hpp"
#include "logging/log.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "prims/methodHandles.hpp"
@ -274,7 +275,7 @@ address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler*
// O4_first_arg_addr is live!
if (TraceMethodHandles) {
if (log_is_enabled(Info, methodhandles)) {
if (O0_mh != noreg)
__ mov(O0_mh, G3_method_handle); // make stub happy
trace_method_handle_interpreter_entry(_masm, iid);
@ -576,7 +577,7 @@ void trace_method_handle_stub(const char* adaptername,
}
void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adaptername) {
if (!TraceMethodHandles) return;
if (!log_is_enabled(Info, methodhandles)) return;
BLOCK_COMMENT("trace_method_handle {");
// save: Gargs, O5_savedSP
__ save_frame(16); // need space for saving required FPU state

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, 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
@ -29,6 +29,7 @@
#include "classfile/javaClasses.inline.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
#include "logging/log.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "prims/methodHandles.hpp"
@ -594,7 +595,7 @@ void trace_method_handle_stub_wrapper(MethodHandleStubArguments* args) {
}
void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adaptername) {
if (!TraceMethodHandles) return;
if (!log_is_enabled(Info, methodhandles)) return;
BLOCK_COMMENT(err_msg("trace_method_handle %s {", adaptername));
__ enter();
__ andptr(rsp, -16); // align stack if needed for FPU state

@ -2456,15 +2456,16 @@ static Method* unpack_method_and_appendix(Handle mname,
Method* m = java_lang_invoke_MemberName::vmtarget(mname());
if (m != NULL) {
oop appendix = appendix_box->obj_at(0);
if (TraceMethodHandles) {
#ifndef PRODUCT
ttyLocker ttyl;
tty->print("Linked method=" INTPTR_FORMAT ": ", p2i(m));
m->print();
if (appendix != NULL) { tty->print("appendix = "); appendix->print(); }
tty->cr();
#endif //PRODUCT
LogTarget(Info, methodhandles) lt;
if (lt.develop_is_enabled()) {
ResourceMark rm(THREAD);
LogStream ls(lt);
ls.print("Linked method=" INTPTR_FORMAT ": ", p2i(m));
m->print_on(&ls);
if (appendix != NULL) { ls.print("appendix = "); appendix->print_on(&ls); }
ls.cr();
}
(*appendix_result) = Handle(THREAD, appendix);
// the target is stored in the cpCache and if a reference to this
// MemberName is dropped we need a way to make sure the

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2020, 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
@ -242,7 +242,7 @@ void CompileTask::print_impl(outputStream* st, Method* method, int compile_id, i
jlong time_queued, jlong time_started) {
if (!short_form) {
// Print current time
st->print("%7d ", (int)st->time_stamp().milliseconds());
st->print("%7d ", (int)tty->time_stamp().milliseconds());
if (Verbose && time_queued != 0) {
// Print time in queue and time being processed by compiler thread
jlong now = os::elapsed_counter();

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, 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
@ -65,7 +65,7 @@ bool BootstrapInfo::resolve_previously_linked_invokedynamic(CallInfo& result, TR
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);
Exceptions::wrap_dynamic_exception(/* is_indy */ true, CHECK_false);
return true;
} else if (cpce->indy_resolution_failed()) {
int encoded_index = ResolutionErrorTable::encode_cpcache_index(_indy_index);
@ -81,24 +81,28 @@ bool BootstrapInfo::resolve_previously_linked_invokedynamic(CallInfo& result, TR
// - 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;
if (_bsm.not_null()) {
return _bsm;
}
bool is_indy = is_method_call();
// 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);
Exceptions::wrap_dynamic_exception(is_indy, 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);
Exceptions::wrap_dynamic_exception(is_indy, CHECK_NH);
// Prepare static arguments
resolve_args(THREAD);
Exceptions::wrap_dynamic_exception(CHECK_NH);
Exceptions::wrap_dynamic_exception(is_indy, CHECK_NH);
return _bsm;
}
@ -253,7 +257,7 @@ void BootstrapInfo::print_msg_on(outputStream* st, const char* msg) {
st->print_cr(" argument indexes: {%s}", argbuf);
}
if (_bsm.not_null()) {
st->print(" resolved BSM: "); _bsm->print();
st->print(" resolved BSM: "); _bsm->print_on(st);
}
// How the array of resolved arguments is printed depends highly
@ -264,7 +268,7 @@ void BootstrapInfo::print_msg_on(outputStream* st, const char* msg) {
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();
st->print(" resolved arg[0]: "); static_args->print_on(st);
} else if (static_args->is_objArray()) {
int lines = 0;
for (int i = 0; i < _argc; i++) {
@ -274,7 +278,7 @@ void BootstrapInfo::print_msg_on(outputStream* st, const char* msg) {
st->print_cr(" resolved arg[%d]: ...", i);
break;
}
st->print(" resolved arg[%d]: ", i); x->print();
st->print(" resolved arg[%d]: ", i); x->print_on(st);
}
}
} else if (static_args->is_typeArray()) {

@ -436,17 +436,16 @@ Method* LinkResolver::lookup_method_in_interfaces(const LinkInfo& cp_info) {
Method* LinkResolver::lookup_polymorphic_method(const LinkInfo& link_info,
Handle *appendix_result_or_null,
TRAPS) {
ResourceMark rm(THREAD);
Klass* klass = link_info.resolved_klass();
Symbol* name = link_info.name();
Symbol* full_signature = link_info.signature();
LogTarget(Info, methodhandles) lt_mh;
vmIntrinsics::ID iid = MethodHandles::signature_polymorphic_name_id(name);
if (TraceMethodHandles) {
ResourceMark rm(THREAD);
tty->print_cr("lookup_polymorphic_method iid=%s %s.%s%s",
vmIntrinsics::name_at(iid), klass->external_name(),
name->as_C_string(), full_signature->as_C_string());
}
log_info(methodhandles)("lookup_polymorphic_method iid=%s %s.%s%s",
vmIntrinsics::name_at(iid), klass->external_name(),
name->as_C_string(), full_signature->as_C_string());
if ((klass == SystemDictionary::MethodHandle_klass() ||
klass == SystemDictionary::VarHandle_klass()) &&
iid != vmIntrinsics::_none) {
@ -456,13 +455,10 @@ Method* LinkResolver::lookup_polymorphic_method(const LinkInfo& link_info,
bool keep_last_arg = MethodHandles::is_signature_polymorphic_static(iid);
TempNewSymbol basic_signature =
MethodHandles::lookup_basic_type_signature(full_signature, keep_last_arg, CHECK_NULL);
if (TraceMethodHandles) {
ResourceMark rm(THREAD);
tty->print_cr("lookup_polymorphic_method %s %s => basic %s",
name->as_C_string(),
full_signature->as_C_string(),
basic_signature->as_C_string());
}
log_info(methodhandles)("lookup_polymorphic_method %s %s => basic %s",
name->as_C_string(),
full_signature->as_C_string(),
basic_signature->as_C_string());
Method* result = SystemDictionary::find_method_handle_intrinsic(iid,
basic_signature,
CHECK_NULL);
@ -470,10 +466,10 @@ Method* LinkResolver::lookup_polymorphic_method(const LinkInfo& link_info,
assert(result->is_method_handle_intrinsic(), "MH.invokeBasic or MH.linkTo* intrinsic");
assert(result->intrinsic_id() != vmIntrinsics::_invokeGeneric, "wrong place to find this");
assert(basic_signature == result->signature(), "predict the result signature");
if (TraceMethodHandles) {
ttyLocker ttyl;
tty->print("lookup_polymorphic_method => intrinsic ");
result->print_on(tty);
if (lt_mh.is_enabled()) {
LogStream ls(lt_mh);
ls.print("lookup_polymorphic_method => intrinsic ");
result->print_on(&ls);
}
}
return result;
@ -503,13 +499,12 @@ Method* LinkResolver::lookup_polymorphic_method(const LinkInfo& link_info,
link_info.current_klass(),
&appendix,
CHECK_NULL);
if (TraceMethodHandles) {
ttyLocker ttyl;
tty->print("lookup_polymorphic_method => (via Java) ");
result->print_on(tty);
tty->print(" lookup_polymorphic_method => appendix = ");
if (appendix.is_null()) tty->print_cr("(none)");
else appendix->print_on(tty);
if (lt_mh.is_enabled()) {
LogStream ls(lt_mh);
ls.print("lookup_polymorphic_method => (via Java) ");
result->print_on(&ls);
ls.print(" lookup_polymorphic_method => appendix = ");
appendix.is_null() ? ls.print_cr("(none)") : appendix->print_on(&ls);
}
if (result != NULL) {
#ifdef ASSERT
@ -1669,10 +1664,10 @@ void LinkResolver::resolve_invokeinterface(CallInfo& result, Handle recv, const
void LinkResolver::resolve_invokehandle(CallInfo& result, const constantPoolHandle& pool, int index, TRAPS) {
// This guy is reached from InterpreterRuntime::resolve_invokehandle.
LinkInfo link_info(pool, index, CHECK);
if (TraceMethodHandles) {
if (log_is_enabled(Info, methodhandles)) {
ResourceMark rm(THREAD);
tty->print_cr("resolve_invokehandle %s %s", link_info.name()->as_C_string(),
link_info.signature()->as_C_string());
log_info(methodhandles)("resolve_invokehandle %s %s", link_info.name()->as_C_string(),
link_info.signature()->as_C_string());
}
resolve_handle_call(result, link_info, CHECK);
}
@ -1713,8 +1708,10 @@ void LinkResolver::resolve_invokedynamic(CallInfo& result, const constantPoolHan
resolve_dynamic_call(result, bootstrap_specifier, CHECK);
if (TraceMethodHandles) {
bootstrap_specifier.print_msg_on(tty, "resolve_invokedynamic");
LogTarget(Debug, methodhandles, indy) lt_indy;
if (lt_indy.is_enabled()) {
LogStream ls(lt_indy);
bootstrap_specifier.print_msg_on(&ls, "resolve_invokedynamic");
}
// The returned linkage result is provisional up to the moment
@ -1735,7 +1732,7 @@ void LinkResolver::resolve_dynamic_call(CallInfo& result,
// 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);
Exceptions::wrap_dynamic_exception(/* is_indy */ true, THREAD);
if (HAS_PENDING_EXCEPTION) {
if (!PENDING_EXCEPTION->is_a(SystemDictionary::LinkageError_klass())) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2020, 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
@ -189,6 +189,11 @@ public:
return LogImpl<T0, T1, T2, T3, T4, GuardTag>::is_level(level);
}
static bool develop_is_enabled() {
NOT_PRODUCT(return is_enabled());
PRODUCT_ONLY(return false);
}
static void print(const char* fmt, ...) ATTRIBUTE_PRINTF(1, 2) {
va_list args;
va_start(args, fmt);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2020, 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
@ -93,6 +93,10 @@ public:
// LogStreamBase(level, tageset);
LogStream(LogLevelType level, LogTagSet* tagset) : _log_handle(level, tagset) {}
bool is_enabled() const {
return _log_handle.is_enabled();
}
void write(const char* s, size_t len);
};

@ -52,6 +52,7 @@
LOG_TAG(codecache) \
LOG_TAG(compaction) \
LOG_TAG(compilation) \
LOG_TAG(condy) \
LOG_TAG(constraints) \
LOG_TAG(constantpool) \
LOG_TAG(container) \
@ -80,6 +81,7 @@
LOG_TAG(humongous) \
LOG_TAG(ihop) \
LOG_TAG(iklass) \
LOG_TAG(indy) \
LOG_TAG(init) \
LOG_TAG(inlining) \
LOG_TAG(install) \
@ -102,6 +104,7 @@
LOG_TAG(methodcomparator) \
LOG_TAG(metadata) \
LOG_TAG(metaspace) \
LOG_TAG(methodhandles) \
LOG_TAG(mmu) \
LOG_TAG(module) \
LOG_TAG(monitorinflation) \

@ -32,6 +32,8 @@
#include "classfile/vmSymbols.hpp"
#include "interpreter/bootstrapInfo.hpp"
#include "interpreter/linkResolver.hpp"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/heapShared.hpp"
#include "memory/metadataFactory.hpp"
@ -941,7 +943,7 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp,
// (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);
Exceptions::wrap_dynamic_exception(/* is_indy */ false, 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.
@ -969,8 +971,10 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp,
}
}
if (TraceMethodHandles) {
bootstrap_specifier.print_msg_on(tty, "resolve_constant_at_impl");
LogTarget(Debug, methodhandles, condy) lt_condy;
if (lt_condy.is_enabled()) {
LogStream ls(lt_condy);
bootstrap_specifier.print_msg_on(&ls, "resolve_constant_at_impl");
}
break;
}

@ -30,6 +30,7 @@
#include "interpreter/linkResolver.hpp"
#include "interpreter/rewriter.hpp"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/heapShared.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/metaspaceClosure.hpp"
@ -412,15 +413,18 @@ void ConstantPoolCacheEntry::set_method_handle_common(const constantPoolHandle&
( 1 << is_final_shift ),
adapter->size_of_parameters());
if (TraceInvokeDynamic) {
ttyLocker ttyl;
tty->print_cr("set_method_handle bc=%d appendix=" PTR_FORMAT "%s method=" PTR_FORMAT " (local signature) ",
invoke_code,
p2i(appendix()),
(has_appendix ? "" : " (unused)"),
p2i(adapter));
adapter->print();
if (has_appendix) appendix()->print();
LogStream* log_stream = NULL;
LogStreamHandle(Debug, methodhandles, indy) lsh_indy;
if (lsh_indy.is_enabled()) {
ResourceMark rm;
log_stream = &lsh_indy;
log_stream->print_cr("set_method_handle bc=%d appendix=" PTR_FORMAT "%s method=" PTR_FORMAT " (local signature) ",
invoke_code,
p2i(appendix()),
(has_appendix ? "" : " (unused)"),
p2i(adapter));
adapter->print_on(log_stream);
if (has_appendix) appendix()->print_on(log_stream);
}
// Method handle invokes and invokedynamic sites use both cp cache words.
@ -456,9 +460,9 @@ void ConstantPoolCacheEntry::set_method_handle_common(const constantPoolHandle&
// but it is used by is_resolved, method_if_resolved, etc.
set_bytecode_1(invoke_code);
NOT_PRODUCT(verify(tty));
if (TraceInvokeDynamic) {
ttyLocker ttyl;
this->print(tty, 0);
if (log_stream != NULL) {
this->print(log_stream, 0);
}
assert(has_appendix == this->has_appendix(), "proper storage of appendix flag");

@ -38,6 +38,7 @@
#include "interpreter/oopMapCache.hpp"
#include "logging/log.hpp"
#include "logging/logTag.hpp"
#include "logging/logStream.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/metaspaceClosure.hpp"
@ -1417,9 +1418,8 @@ methodHandle Method::make_method_handle_intrinsic(vmIntrinsics::ID iid,
InstanceKlass* holder = SystemDictionary::MethodHandle_klass();
Symbol* name = MethodHandles::signature_polymorphic_intrinsic_name(iid);
assert(iid == MethodHandles::signature_polymorphic_name_id(name), "");
if (TraceMethodHandles) {
tty->print_cr("make_method_handle_intrinsic MH.%s%s", name->as_C_string(), signature->as_C_string());
}
log_info(methodhandles)("make_method_handle_intrinsic MH.%s%s", name->as_C_string(), signature->as_C_string());
// invariant: cp->symbol_at_put is preceded by a refcount increment (more usually a lookup)
name->increment_refcount();
@ -1470,9 +1470,10 @@ methodHandle Method::make_method_handle_intrinsic(vmIntrinsics::ID iid,
m->set_vtable_index(Method::nonvirtual_vtable_index);
m->link_method(m, CHECK_(empty));
if (TraceMethodHandles && (Verbose || WizardMode)) {
ttyLocker ttyl;
m->print_on(tty);
if (log_is_enabled(Info, methodhandles) && (Verbose || WizardMode)) {
LogTarget(Info, methodhandles) lt;
LogStream ls(lt);
m->print_on(&ls);
}
return m;

@ -32,6 +32,8 @@
#include "interpreter/interpreter.hpp"
#include "interpreter/oopMapCache.hpp"
#include "interpreter/linkResolver.hpp"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
@ -228,6 +230,7 @@ oop MethodHandles::init_method_MemberName(Handle mname, CallInfo& info) {
assert(m_klass != NULL, "null holder for method handle");
int flags = (jushort)( m->access_flags().as_short() & JVM_RECOGNIZED_METHOD_MODIFIERS );
int vmindex = Method::invalid_vtable_index;
LogTarget(Debug, methodhandles, indy) lt_indy;
switch (info.call_kind()) {
case CallInfo::itable_call:
@ -235,22 +238,22 @@ oop MethodHandles::init_method_MemberName(Handle mname, CallInfo& info) {
// More importantly, the itable index only works with the method holder.
assert(m_klass->verify_itable_index(vmindex), "");
flags |= IS_METHOD | (JVM_REF_invokeInterface << REFERENCE_KIND_SHIFT);
if (TraceInvokeDynamic) {
ttyLocker ttyl;
if (lt_indy.is_enabled()) {
ResourceMark rm;
tty->print_cr("memberName: invokeinterface method_holder::method: %s, itableindex: %d, access_flags:",
Method::name_and_sig_as_C_string(m->method_holder(), m->name(), m->signature()),
vmindex);
m->access_flags().print_on(tty);
LogStream ls(lt_indy);
ls.print_cr("memberName: invokeinterface method_holder::method: %s, itableindex: %d, access_flags:",
Method::name_and_sig_as_C_string(m->method_holder(), m->name(), m->signature()),
vmindex);
m->access_flags().print_on(&ls);
if (!m->is_abstract()) {
if (!m->is_private()) {
tty->print("default");
ls.print("default");
}
else {
tty->print("private-intf");
ls.print("private-intf");
}
}
tty->cr();
ls.cr();
}
break;
@ -282,17 +285,17 @@ oop MethodHandles::init_method_MemberName(Handle mname, CallInfo& info) {
assert(info.resolved_klass()->is_subtype_of(m_klass_non_interface), "virtual call must be type-safe");
m_klass = m_klass_non_interface;
}
if (TraceInvokeDynamic) {
ttyLocker ttyl;
if (lt_indy.is_enabled()) {
ResourceMark rm;
tty->print_cr("memberName: invokevirtual method_holder::method: %s, receiver: %s, vtableindex: %d, access_flags:",
Method::name_and_sig_as_C_string(m->method_holder(), m->name(), m->signature()),
m_klass->internal_name(), vmindex);
m->access_flags().print_on(tty);
LogStream ls(lt_indy);
ls.print_cr("memberName: invokevirtual method_holder::method: %s, receiver: %s, vtableindex: %d, access_flags:",
Method::name_and_sig_as_C_string(m->method_holder(), m->name(), m->signature()),
m_klass->internal_name(), vmindex);
m->access_flags().print_on(&ls);
if (m->is_default_method()) {
tty->print("default");
ls.print("default");
}
tty->cr();
ls.cr();
}
break;
@ -1069,7 +1072,7 @@ void MethodHandles::flush_dependent_nmethods(Handle call_site, Handle target) {
}
void MethodHandles::trace_method_handle_interpreter_entry(MacroAssembler* _masm, vmIntrinsics::ID iid) {
if (TraceMethodHandles) {
if (log_is_enabled(Info, methodhandles)) {
const char* name = vmIntrinsics::name_at(iid);
if (*name == '_') name += 1;
const size_t len = strlen(name) + 50;
@ -1555,9 +1558,7 @@ JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class))
"register java.lang.invoke.MethodHandle natives");
}
if (TraceInvokeDynamic) {
tty->print_cr("MethodHandle support loaded (using LambdaForms)");
}
log_debug(methodhandles, indy)("MethodHandle support loaded (using LambdaForms)");
MethodHandles::set_enabled(true);
}

@ -586,7 +586,9 @@ static AliasedLoggingFlag const aliased_logging_flags[] = {
{ "TraceClassResolution", LogLevel::Debug, true, LOG_TAGS(class, resolve) },
{ "TraceClassUnloading", LogLevel::Info, true, LOG_TAGS(class, unload) },
{ "TraceExceptions", LogLevel::Info, true, LOG_TAGS(exceptions) },
{ "TraceInvokeDynamic", LogLevel::Debug, true, LOG_TAGS(methodhandles, indy) },
{ "TraceLoaderConstraints", LogLevel::Info, true, LOG_TAGS(class, loader, constraints) },
{ "TraceMethodHandles", LogLevel::Info, true, LOG_TAGS(methodhandles) },
{ "TraceMonitorInflation", LogLevel::Trace, true, LOG_TAGS(monitorinflation) },
{ "TraceSafepointCleanupTime", LogLevel::Info, true, LOG_TAGS(safepoint, cleanup) },
{ "TraceJVMTIObjectTagging", LogLevel::Debug, true, LOG_TAGS(jvmti, objecttagging) },

@ -2298,9 +2298,6 @@ const size_t minimumSymbolTableSize = 1024;
diagnostic(bool, PrintMethodHandleStubs, false, \
"Print generated stub code for method handles") \
\
develop(bool, TraceMethodHandles, false, \
"trace internal method handle operations") \
\
diagnostic(bool, VerifyMethodHandles, trueInDebug, \
"perform extra checks when constructing method handles") \
\
@ -2313,9 +2310,6 @@ const size_t minimumSymbolTableSize = 1024;
diagnostic(bool, FoldStableValues, true, \
"Optimize loads from stable fields (marked w/ @Stable)") \
\
develop(bool, TraceInvokeDynamic, false, \
"trace internal invoke dynamic operations") \
\
diagnostic(int, UseBootstrapCallInfo, 1, \
"0: when resolving InDy or ConDy, force all BSM arguments to be " \
"resolved before the bootstrap method is called; 1: when a BSM " \

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2020, 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
@ -401,25 +401,36 @@ Handle Exceptions::new_exception(Thread* thread, Symbol* name,
// dynamically computed constant uses wrap_dynamic_exception for:
// - bootstrap method resolution
// - post call to MethodHandleNatives::linkDynamicConstant
void Exceptions::wrap_dynamic_exception(Thread* THREAD) {
void Exceptions::wrap_dynamic_exception(bool is_indy, Thread* THREAD) {
if (THREAD->has_pending_exception()) {
bool log_indy = log_is_enabled(Debug, methodhandles, indy) && is_indy;
bool log_condy = log_is_enabled(Debug, methodhandles, condy) && !is_indy;
LogStreamHandle(Debug, methodhandles, indy) lsh_indy;
LogStreamHandle(Debug, methodhandles, condy) lsh_condy;
LogStream* ls = NULL;
if (log_indy) {
ls = &lsh_indy;
} else if (log_condy) {
ls = &lsh_condy;
}
oop exception = THREAD->pending_exception();
// See the "Linking Exceptions" section for the invokedynamic instruction
// in JVMS 6.5.
if (exception->is_a(SystemDictionary::Error_klass())) {
// Pass through an Error, including BootstrapMethodError, any other form
// of linkage error, or say ThreadDeath/OutOfMemoryError
if (TraceMethodHandles) {
tty->print_cr("bootstrap method invocation wraps BSME around " INTPTR_FORMAT, p2i((void *)exception));
exception->print();
if (ls != NULL) {
ls->print_cr("bootstrap method invocation wraps BSME around " INTPTR_FORMAT, p2i((void *)exception));
exception->print_on(ls);
}
return;
}
// Otherwise wrap the exception in a BootstrapMethodError
if (TraceMethodHandles) {
tty->print_cr("[constant/invoke]dynamic throws BSME for " INTPTR_FORMAT, p2i((void *)exception));
exception->print();
if (ls != NULL) {
ls->print_cr("%s throws BSME for " INTPTR_FORMAT, is_indy ? "invokedynamic" : "dynamic constant", p2i((void *)exception));
exception->print_on(ls);
}
Handle nested_exception(THREAD, exception);
THREAD->clear_pending_exception();

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2020, 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
@ -170,7 +170,7 @@ class Exceptions {
static void throw_stack_overflow_exception(Thread* thread, const char* file, int line, const methodHandle& method);
static void wrap_dynamic_exception(Thread* thread);
static void wrap_dynamic_exception(bool is_indy, Thread* thread);
// Exception counting for error files of interesting exceptions that may have
// caused a problem for the jvm

@ -0,0 +1,101 @@
/*
* Copyright (c) 2020, 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.
*/
super public class CondyIndy
version 59:0
{
public static Field add1:"LCondyIndyMathOperation;";
public Method "<init>":"()V"
stack 1 locals 1
{
aload_0;
invokespecial Method java/lang/Object."<init>":"()V";
return;
}
public static Method condy_bsm:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/Object;)Ljava/lang/Object;"
stack 2 locals 4
{
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
ldc String "In condy_bsm";
invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
ldc String "1";
areturn;
}
public static Method operate:"(IILCondyIndyMathOperation;)I"
stack 3 locals 3
{
aload_2;
iload_0;
iload_1;
invokeinterface InterfaceMethod CondyIndyMathOperation.operation:"(II)I", 3;
ireturn;
}
public static Method main:"([Ljava/lang/String;)V"
stack 4 locals 2
{
new class CondyIndy;
dup;
invokespecial Method "<init>":"()V";
astore_1;
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
bipush 10;
iconst_5;
aload_1;
pop;
getstatic Field add1:"LCondyIndyMathOperation;";
invokestatic Method operate:"(IILCondyIndyMathOperation;)I";
invokevirtual Method java/io/PrintStream.println:"(I)V";
ldc Dynamic REF_invokeStatic:CondyIndy.condy_bsm:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/Object;)Ljava/lang/Object;":invoke:"Ljava/lang/Object;" {
int 0
};
return;
}
private static synthetic Method lambda$static$0:"(II)I"
stack 2 locals 2
{
iload_0;
iload_1;
iadd;
ireturn;
}
static Method "<clinit>":"()V"
stack 1 locals 0
{
invokedynamic InvokeDynamic REF_invokeStatic:java/lang/invoke/LambdaMetafactory.metafactory:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;":operation:"()LCondyIndyMathOperation;"
MethodType "(II)I",
MethodHandle REF_invokeStatic:CondyIndy.lambda$static$0:"(II)I",
MethodType "(II)I";
putstatic Field add1:"LCondyIndyMathOperation;";
return;
}
public static final InnerClass Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles;
} // end Class CondyIndy

@ -0,0 +1,31 @@
/*
* Copyright (c) 2020, 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.
*/
interface CondyIndyMathOperation
version 59:0
{
public abstract Method operation:"(II)I";
} // end Class CondyIndyMathOperation

@ -0,0 +1,75 @@
/*
* Copyright (c) 2020, 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.
*/
/*
* @test
* @summary Test -Xlog:methodhandles with a test that contains both a condy and indy.
* @modules java.base/jdk.internal.misc
* @library /test/lib
* @compile CondyIndyMathOperation.jasm
* @compile CondyIndy.jasm
* @run driver CondyIndyTest
*/
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.compiler.InMemoryJavaCompiler;
public class CondyIndyTest {
public static void main(String... args) throws Exception {
// (1) methodhandles should turn on, no indy, no condy
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:methodhandles",
"CondyIndy");
OutputAnalyzer o = new OutputAnalyzer(pb.start());
o.shouldContain("[info][methodhandles");
o.shouldNotContain("[debug][methodhandles,indy");
o.shouldNotContain("[debug][methodhandles,condy");
// (2) methodhandles+condy=debug only
pb = ProcessTools.createJavaProcessBuilder("-Xlog:methodhandles+condy=debug",
"CondyIndy");
o = new OutputAnalyzer(pb.start());
o.shouldNotContain("[info ][methodhandles");
o.shouldNotContain("[debug][methodhandles,indy");
o.shouldContain("[debug][methodhandles,condy");
// (3) methodhandles+indy=debug only
pb = ProcessTools.createJavaProcessBuilder("-Xlog:methodhandles+indy=debug",
"CondyIndy");
o = new OutputAnalyzer(pb.start());
o.shouldNotContain("[info ][methodhandles");
o.shouldContain("[debug][methodhandles,indy");
o.shouldNotContain("[debug][methodhandles,condy");
// (4) methodhandles, condy, indy all on
pb = ProcessTools.createJavaProcessBuilder("-Xlog:methodhandles=info",
"-Xlog:methodhandles+condy=debug",
"-Xlog:methodhandles+indy=debug",
"CondyIndy");
o = new OutputAnalyzer(pb.start());
o.shouldContain("[info ][methodhandles");
o.shouldContain("[debug][methodhandles,indy");
o.shouldContain("[debug][methodhandles,condy");
};
}