# HG changeset patch # User amurillo # Date 1433787107 25200 # Node ID 4c45af8f8225a2f893e5bb64a70719e5a71b589e # Parent 5b500c93ce4822d47061cd518ff3f72d9d8cb5b5# Parent 15832b86bab0adefc9b175bb2c288288cbeb4a4d Merge diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/make/linux/makefiles/dtrace.make --- a/hotspot/make/linux/makefiles/dtrace.make Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/make/linux/makefiles/dtrace.make Mon Jun 08 11:11:47 2015 -0700 @@ -31,8 +31,8 @@ REASON = "This JDK does not support SDT probes" else -# We need a recent GCC for the default -ifeq "$(shell expr \( $(CC_VER_MAJOR) \>= 4 \) \& \( $(CC_VER_MINOR) \>= 4 \) )" "0" +# We need a recent GCC for the default (4.4 or later) +ifeq "$(shell expr \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 4 \) \) \| \( $(CC_VER_MAJOR) \>= 5 \) )" "0" REASON = "gcc version is too old" else diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/make/test/JtregNative.gmk --- a/hotspot/make/test/JtregNative.gmk Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/make/test/JtregNative.gmk Mon Jun 08 11:11:47 2015 -0700 @@ -44,6 +44,7 @@ $(HOTSPOT_TOPDIR)/test/native_sanity \ $(HOTSPOT_TOPDIR)/test/runtime/jni/8025979 \ $(HOTSPOT_TOPDIR)/test/runtime/jni/8033445 \ + $(HOTSPOT_TOPDIR)/test/runtime/jni/ToStringInInterfaceTest \ # BUILD_HOTSPOT_JTREG_OUTPUT_DIR := $(BUILD_OUTPUT)/support/test/hotspot/jtreg/native diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.hpp diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/cpu/sparc/vm/sparc.ad --- a/hotspot/src/cpu/sparc/vm/sparc.ad Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/cpu/sparc/vm/sparc.ad Mon Jun 08 11:11:47 2015 -0700 @@ -3372,6 +3372,25 @@ interface(CONST_INTER); %} +// Integer Immediate: 0-bit +operand immI0() %{ + predicate(n->get_int() == 0); + match(ConI); + op_cost(0); + + format %{ %} + interface(CONST_INTER); +%} + +// Integer Immediate: 5-bit +operand immI5() %{ + predicate(Assembler::is_simm5(n->get_int())); + match(ConI); + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + // Integer Immediate: 8-bit operand immI8() %{ predicate(Assembler::is_simm8(n->get_int())); @@ -3381,6 +3400,25 @@ interface(CONST_INTER); %} +// Integer Immediate: the value 10 +operand immI10() %{ + predicate(n->get_int() == 10); + match(ConI); + op_cost(0); + + format %{ %} + interface(CONST_INTER); +%} + +// Integer Immediate: 11-bit +operand immI11() %{ + predicate(Assembler::is_simm11(n->get_int())); + match(ConI); + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + // Integer Immediate: 13-bit operand immI13() %{ predicate(Assembler::is_simm13(n->get_int())); @@ -3410,84 +3448,6 @@ interface(CONST_INTER); %} -// Unsigned Integer Immediate: 12-bit (non-negative that fits in simm13) -operand immU12() %{ - predicate((0 <= n->get_int()) && Assembler::is_simm13(n->get_int())); - match(ConI); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -// Integer Immediate: 6-bit -operand immU6() %{ - predicate(n->get_int() >= 0 && n->get_int() <= 63); - match(ConI); - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -// Integer Immediate: 11-bit -operand immI11() %{ - predicate(Assembler::is_simm11(n->get_int())); - match(ConI); - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -// Integer Immediate: 5-bit -operand immI5() %{ - predicate(Assembler::is_simm5(n->get_int())); - match(ConI); - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -// Int Immediate non-negative -operand immU31() -%{ - predicate(n->get_int() >= 0); - match(ConI); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -// Integer Immediate: 0-bit -operand immI0() %{ - predicate(n->get_int() == 0); - match(ConI); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -// Integer Immediate: the value 10 -operand immI10() %{ - predicate(n->get_int() == 10); - match(ConI); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -// Integer Immediate: the values 0-31 -operand immU5() %{ - predicate(n->get_int() >= 0 && n->get_int() <= 31); - match(ConI); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - // Integer Immediate: the values 1-31 operand immI_1_31() %{ predicate(n->get_int() >= 1 && n->get_int() <= 31); @@ -3529,7 +3489,6 @@ format %{ %} interface(CONST_INTER); %} - // Integer Immediate: the value 255 operand immI_255() %{ predicate( n->get_int() == 255 ); @@ -3550,6 +3509,46 @@ interface(CONST_INTER); %} +// Integer Immediate: the values 0-31 +operand immU5() %{ + predicate(n->get_int() >= 0 && n->get_int() <= 31); + match(ConI); + op_cost(0); + + format %{ %} + interface(CONST_INTER); +%} + +// Integer Immediate: 6-bit +operand immU6() %{ + predicate(n->get_int() >= 0 && n->get_int() <= 63); + match(ConI); + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// Unsigned Integer Immediate: 12-bit (non-negative that fits in simm13) +operand immU12() %{ + predicate((0 <= n->get_int()) && Assembler::is_simm13(n->get_int())); + match(ConI); + op_cost(0); + + format %{ %} + interface(CONST_INTER); +%} + +// Integer Immediate non-negative +operand immU31() +%{ + predicate(n->get_int() >= 0); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + // Long Immediate: the value FF operand immL_FF() %{ predicate( n->get_long() == 0xFFL ); @@ -5653,17 +5652,17 @@ ins_pipe(iload_mem); %} -// Load Unsigned Byte (8 bit UNsigned) with 8-bit mask into Long Register -instruct loadUB2L_immI8(iRegL dst, memory mem, immI8 mask) %{ +// Load Unsigned Byte (8 bit UNsigned) with 32-bit mask into Long Register +instruct loadUB2L_immI(iRegL dst, memory mem, immI mask) %{ match(Set dst (ConvI2L (AndI (LoadUB mem) mask))); ins_cost(MEMORY_REF_COST + DEFAULT_COST); size(2*4); - format %{ "LDUB $mem,$dst\t# ubyte & 8-bit mask -> long\n\t" - "AND $dst,$mask,$dst" %} + format %{ "LDUB $mem,$dst\t# ubyte & 32-bit mask -> long\n\t" + "AND $dst,right_n_bits($mask, 8),$dst" %} ins_encode %{ __ ldub($mem$$Address, $dst$$Register); - __ and3($dst$$Register, $mask$$constant, $dst$$Register); + __ and3($dst$$Register, $mask$$constant & right_n_bits(8), $dst$$Register); %} ins_pipe(iload_mem); %} @@ -5776,20 +5775,20 @@ ins_pipe(iload_mem); %} -// Load Unsigned Short/Char (16bit UNsigned) with a 16-bit mask into a Long Register -instruct loadUS2L_immI16(iRegL dst, memory mem, immI16 mask, iRegL tmp) %{ +// Load Unsigned Short/Char (16bit UNsigned) with a 32-bit mask into a Long Register +instruct loadUS2L_immI(iRegL dst, memory mem, immI mask, iRegL tmp) %{ match(Set dst (ConvI2L (AndI (LoadUS mem) mask))); effect(TEMP dst, TEMP tmp); ins_cost(MEMORY_REF_COST + 2*DEFAULT_COST); - format %{ "LDUH $mem,$dst\t! ushort/char & 16-bit mask -> long\n\t" - "SET $mask,$tmp\n\t" + format %{ "LDUH $mem,$dst\t! ushort/char & 32-bit mask -> long\n\t" + "SET right_n_bits($mask, 16),$tmp\n\t" "AND $dst,$tmp,$dst" %} ins_encode %{ Register Rdst = $dst$$Register; Register Rtmp = $tmp$$Register; __ lduh($mem$$Address, Rdst); - __ set($mask$$constant, Rtmp); + __ set($mask$$constant & right_n_bits(16), Rtmp); __ and3(Rdst, Rtmp, Rdst); %} ins_pipe(iload_mem); diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/cpu/x86/vm/interp_masm_x86.cpp diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/cpu/x86/vm/interp_masm_x86.hpp diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/cpu/x86/vm/x86_32.ad --- a/hotspot/src/cpu/x86/vm/x86_32.ad Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/cpu/x86/vm/x86_32.ad Mon Jun 08 11:11:47 2015 -0700 @@ -5431,18 +5431,18 @@ %} // Load Unsigned Byte (8 bit UNsigned) with mask into Long Register -instruct loadUB2L_immI8(eRegL dst, memory mem, immI8 mask, eFlagsReg cr) %{ +instruct loadUB2L_immI(eRegL dst, memory mem, immI mask, eFlagsReg cr) %{ match(Set dst (ConvI2L (AndI (LoadUB mem) mask))); effect(KILL cr); - format %{ "MOVZX8 $dst.lo,$mem\t# ubyte & 8-bit mask -> long\n\t" + format %{ "MOVZX8 $dst.lo,$mem\t# ubyte & 32-bit mask -> long\n\t" "XOR $dst.hi,$dst.hi\n\t" - "AND $dst.lo,$mask" %} + "AND $dst.lo,right_n_bits($mask, 8)" %} ins_encode %{ Register Rdst = $dst$$Register; __ movzbl(Rdst, $mem$$Address); __ xorl(HIGH_FROM_LOW(Rdst), HIGH_FROM_LOW(Rdst)); - __ andl(Rdst, $mask$$constant); + __ andl(Rdst, $mask$$constant & right_n_bits(8)); %} ins_pipe(ialu_reg_mem); %} @@ -5550,19 +5550,19 @@ ins_pipe(ialu_reg_mem); %} -// Load Unsigned Short/Char (16 bit UNsigned) with a 16-bit mask into Long Register -instruct loadUS2L_immI16(eRegL dst, memory mem, immI16 mask, eFlagsReg cr) %{ +// Load Unsigned Short/Char (16 bit UNsigned) with a 32-bit mask into Long Register +instruct loadUS2L_immI(eRegL dst, memory mem, immI mask, eFlagsReg cr) %{ match(Set dst (ConvI2L (AndI (LoadUS mem) mask))); effect(KILL cr); - format %{ "MOVZX $dst.lo, $mem\t# ushort/char & 16-bit mask -> long\n\t" + format %{ "MOVZX $dst.lo, $mem\t# ushort/char & 32-bit mask -> long\n\t" "XOR $dst.hi,$dst.hi\n\t" - "AND $dst.lo,$mask" %} + "AND $dst.lo,right_n_bits($mask, 16)" %} ins_encode %{ Register Rdst = $dst$$Register; __ movzwl(Rdst, $mem$$Address); __ xorl(HIGH_FROM_LOW(Rdst), HIGH_FROM_LOW(Rdst)); - __ andl(Rdst, $mask$$constant); + __ andl(Rdst, $mask$$constant & right_n_bits(16)); %} ins_pipe(ialu_reg_mem); %} diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/cpu/x86/vm/x86_64.ad --- a/hotspot/src/cpu/x86/vm/x86_64.ad Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/cpu/x86/vm/x86_64.ad Mon Jun 08 11:11:47 2015 -0700 @@ -4753,17 +4753,17 @@ ins_pipe(ialu_reg_mem); %} -// Load Unsigned Byte (8 bit UNsigned) with a 8-bit mask into Long Register -instruct loadUB2L_immI8(rRegL dst, memory mem, immI8 mask, rFlagsReg cr) %{ +// Load Unsigned Byte (8 bit UNsigned) with 32-bit mask into Long Register +instruct loadUB2L_immI(rRegL dst, memory mem, immI mask, rFlagsReg cr) %{ match(Set dst (ConvI2L (AndI (LoadUB mem) mask))); effect(KILL cr); - format %{ "movzbq $dst, $mem\t# ubyte & 8-bit mask -> long\n\t" - "andl $dst, $mask" %} + format %{ "movzbq $dst, $mem\t# ubyte & 32-bit mask -> long\n\t" + "andl $dst, right_n_bits($mask, 8)" %} ins_encode %{ Register Rdst = $dst$$Register; __ movzbq(Rdst, $mem$$Address); - __ andl(Rdst, $mask$$constant); + __ andl(Rdst, $mask$$constant & right_n_bits(8)); %} ins_pipe(ialu_reg_mem); %} @@ -4863,17 +4863,17 @@ ins_pipe(ialu_reg_mem); %} -// Load Unsigned Short/Char (16 bit UNsigned) with mask into Long Register -instruct loadUS2L_immI16(rRegL dst, memory mem, immI16 mask, rFlagsReg cr) %{ +// Load Unsigned Short/Char (16 bit UNsigned) with 32-bit mask into Long Register +instruct loadUS2L_immI(rRegL dst, memory mem, immI mask, rFlagsReg cr) %{ match(Set dst (ConvI2L (AndI (LoadUS mem) mask))); effect(KILL cr); - format %{ "movzwq $dst, $mem\t# ushort/char & 16-bit mask -> long\n\t" - "andl $dst, $mask" %} + format %{ "movzwq $dst, $mem\t# ushort/char & 32-bit mask -> long\n\t" + "andl $dst, right_n_bits($mask, 16)" %} ins_encode %{ Register Rdst = $dst$$Register; __ movzwq(Rdst, $mem$$Address); - __ andl(Rdst, $mask$$constant); + __ andl(Rdst, $mask$$constant & right_n_bits(16)); %} ins_pipe(ialu_reg_mem); %} diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/os/aix/vm/os_aix.cpp --- a/hotspot/src/os/aix/vm/os_aix.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/os/aix/vm/os_aix.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -1267,10 +1267,6 @@ // Note: os::abort() might be called very early during initialization, or // called from signal handler. Before adding something to os::abort(), make // sure it is async-safe and can handle partially initialized VM. -void os::abort(bool dump_core) { - abort(dump_core, NULL, NULL); -} - void os::abort(bool dump_core, void* siginfo, void* context) { os::shutdown(); if (dump_core) { diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/os/bsd/vm/os_bsd.cpp --- a/hotspot/src/os/bsd/vm/os_bsd.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -1131,10 +1131,6 @@ // Note: os::abort() might be called very early during initialization, or // called from signal handler. Before adding something to os::abort(), make // sure it is async-safe and can handle partially initialized VM. -void os::abort(bool dump_core) { - abort(dump_core, NULL, NULL); -} - void os::abort(bool dump_core, void* siginfo, void* context) { os::shutdown(); if (dump_core) { diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/os/linux/vm/os_linux.cpp --- a/hotspot/src/os/linux/vm/os_linux.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/os/linux/vm/os_linux.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -1478,10 +1478,6 @@ // Note: os::abort() might be called very early during initialization, or // called from signal handler. Before adding something to os::abort(), make // sure it is async-safe and can handle partially initialized VM. -void os::abort(bool dump_core) { - abort(dump_core, NULL, NULL); -} - void os::abort(bool dump_core, void* siginfo, void* context) { os::shutdown(); if (dump_core) { diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/os/solaris/vm/os_solaris.cpp --- a/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -1520,10 +1520,6 @@ // Note: os::abort() might be called very early during initialization, or // called from signal handler. Before adding something to os::abort(), make // sure it is async-safe and can handle partially initialized VM. -void os::abort(bool dump_core) { - abort(dump_core, NULL, NULL); -} - void os::abort(bool dump_core, void* siginfo, void* context) { os::shutdown(); if (dump_core) { diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/os/windows/vm/os_windows.cpp --- a/hotspot/src/os/windows/vm/os_windows.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/os/windows/vm/os_windows.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -997,7 +997,16 @@ if (!FLAG_IS_DEFAULT(CreateCoredumpOnCrash) && !CreateCoredumpOnCrash) { jio_snprintf(buffer, buffsz, "CreateCoredumpOnCrash is disabled from command line"); status = false; - } else { + } + +#ifndef ASSERT + if (!os::win32::is_windows_server() && FLAG_IS_DEFAULT(CreateCoredumpOnCrash)) { + jio_snprintf(buffer, buffsz, "Minidumps are not enabled by default on client versions of Windows"); + status = false; + } +#endif + + if (status) { const char* cwd = get_current_directory(NULL, 0); int pid = current_process_id(); if (cwd != NULL) { @@ -1086,10 +1095,6 @@ win32::exit_process_or_thread(win32::EPT_PROCESS, 1); } -void os::abort(bool dump_core) { - abort(dump_core, NULL, NULL); -} - // Die immediately, no exit hook, no abort hook, no cleanup. void os::die() { win32::exit_process_or_thread(win32::EPT_PROCESS_DIE, -1); diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/ci/ciCallSite.cpp --- a/hotspot/src/share/vm/ci/ciCallSite.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciCallSite.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -50,25 +50,6 @@ } // ------------------------------------------------------------------ -// ciCallSite::get_context -// -// Return the target MethodHandle of this CallSite. -ciKlass* ciCallSite::get_context() { - assert(!is_constant_call_site(), ""); - - VM_ENTRY_MARK; - oop call_site_oop = get_oop(); - InstanceKlass* ctxk = MethodHandles::get_call_site_context(call_site_oop); - if (ctxk == NULL) { - // The call site doesn't have a context associated. Set it to the default context. - oop def_context_oop = java_lang_invoke_CallSite::default_context(); - java_lang_invoke_CallSite::set_context_cas(call_site_oop, def_context_oop, /*expected=*/NULL); - ctxk = MethodHandles::get_call_site_context(call_site_oop); - } - return (CURRENT_ENV->get_metadata(ctxk))->as_klass(); -} - -// ------------------------------------------------------------------ // ciCallSite::print // // Print debugging information about the CallSite. diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/ci/ciCallSite.hpp --- a/hotspot/src/share/vm/ci/ciCallSite.hpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciCallSite.hpp Mon Jun 08 11:11:47 2015 -0700 @@ -43,7 +43,6 @@ // Return the target MethodHandle of this CallSite. ciMethodHandle* get_target() const; - ciKlass* get_context(); void print(); }; diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/ci/ciEnv.cpp --- a/hotspot/src/share/vm/ci/ciEnv.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciEnv.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -709,24 +709,23 @@ KlassHandle h_holder(THREAD, holder); LinkResolver::check_klass_accessability(h_accessor, h_holder, KILL_COMPILE_ON_FATAL_(NULL)); methodHandle dest_method; + LinkInfo link_info(h_holder, name, sig, h_accessor, /*check_access*/true); switch (bc) { case Bytecodes::_invokestatic: dest_method = - LinkResolver::resolve_static_call_or_null(h_holder, name, sig, h_accessor); + LinkResolver::resolve_static_call_or_null(link_info); break; case Bytecodes::_invokespecial: dest_method = - LinkResolver::resolve_special_call_or_null(h_holder, name, sig, h_accessor); + LinkResolver::resolve_special_call_or_null(link_info); break; case Bytecodes::_invokeinterface: dest_method = - LinkResolver::linktime_resolve_interface_method_or_null(h_holder, name, sig, - h_accessor, true); + LinkResolver::linktime_resolve_interface_method_or_null(link_info); break; case Bytecodes::_invokevirtual: dest_method = - LinkResolver::linktime_resolve_virtual_method_or_null(h_holder, name, sig, - h_accessor, true); + LinkResolver::linktime_resolve_virtual_method_or_null(link_info); break; default: ShouldNotReachHere(); } diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/ci/ciField.cpp --- a/hotspot/src/share/vm/ci/ciField.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciField.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -352,11 +352,11 @@ } } + LinkInfo link_info(_holder->get_instanceKlass(), + _name->get_symbol(), _signature->get_symbol(), + accessing_klass->get_Klass()); fieldDescriptor result; - LinkResolver::resolve_field(result, _holder->get_instanceKlass(), - _name->get_symbol(), _signature->get_symbol(), - accessing_klass->get_Klass(), bc, true, false, - KILL_COMPILE_ON_FATAL_(false)); + LinkResolver::resolve_field(result, link_info, bc, false, KILL_COMPILE_ON_FATAL_(false)); // update the hit-cache, unless there is a problem with memory scoping: if (accessing_klass->is_shared() || !is_shared()) { diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/ci/ciInstanceKlass.cpp --- a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -453,8 +453,12 @@ if (fields == NULL) { // This can happen if this class (java.lang.Class) has invisible fields. - _nonstatic_fields = super_fields; - return super_fields->length(); + if (super_fields != NULL) { + _nonstatic_fields = super_fields; + return super_fields->length(); + } else { + return 0; + } } int flen = fields->length(); diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/ci/ciMethod.cpp --- a/hotspot/src/share/vm/ci/ciMethod.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciMethod.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, 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 @@ -786,6 +786,7 @@ Symbol* h_name = name()->get_symbol(); Symbol* h_signature = signature()->get_symbol(); + LinkInfo link_info(h_resolved, h_name, h_signature, caller_klass, check_access); methodHandle m; // Only do exact lookup if receiver klass has been linked. Otherwise, // the vtable has not been setup, and the LinkResolver will fail. @@ -793,9 +794,9 @@ || InstanceKlass::cast(h_recv())->is_linked() && !exact_receiver->is_interface()) { if (holder()->is_interface()) { - m = LinkResolver::resolve_interface_call_or_null(h_recv, h_resolved, h_name, h_signature, caller_klass, check_access); + m = LinkResolver::resolve_interface_call_or_null(h_recv, link_info); } else { - m = LinkResolver::resolve_virtual_call_or_null(h_recv, h_resolved, h_name, h_signature, caller_klass, check_access); + m = LinkResolver::resolve_virtual_call_or_null(h_recv, link_info); } } @@ -839,7 +840,8 @@ Symbol* h_name = name()->get_symbol(); Symbol* h_signature = signature()->get_symbol(); - vtable_index = LinkResolver::resolve_virtual_vtable_index(h_recv, h_recv, h_name, h_signature, caller_klass); + LinkInfo link_info(h_recv, h_name, h_signature, caller_klass); + vtable_index = LinkResolver::resolve_virtual_vtable_index(h_recv, link_info); if (vtable_index == Method::nonvirtual_vtable_index) { // A statically bound method. Return "no such index". vtable_index = Method::invalid_vtable_index; @@ -1285,10 +1287,8 @@ EXCEPTION_MARK; HandleMark hm(THREAD); constantPoolHandle pool (THREAD, get_Method()->constants()); - methodHandle spec_method; - KlassHandle spec_klass; Bytecodes::Code code = (is_static ? Bytecodes::_invokestatic : Bytecodes::_invokevirtual); - LinkResolver::resolve_method_statically(spec_method, spec_klass, code, pool, refinfo_index, THREAD); + methodHandle spec_method = LinkResolver::resolve_method_statically(code, pool, refinfo_index, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return false; diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/ci/ciStreams.cpp diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/classfile/classLoaderData.cpp diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/classfile/classLoaderData.hpp diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/classfile/javaClasses.cpp --- a/hotspot/src/share/vm/classfile/javaClasses.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -2967,47 +2967,42 @@ int java_lang_invoke_CallSite::_target_offset; int java_lang_invoke_CallSite::_context_offset; -int java_lang_invoke_CallSite::_default_context_offset; void java_lang_invoke_CallSite::compute_offsets() { Klass* k = SystemDictionary::CallSite_klass(); if (k != NULL) { compute_offset(_target_offset, k, vmSymbols::target_name(), vmSymbols::java_lang_invoke_MethodHandle_signature()); - compute_offset(_context_offset, k, vmSymbols::context_name(), vmSymbols::sun_misc_Cleaner_signature()); - compute_offset(_default_context_offset, k, - vmSymbols::DEFAULT_CONTEXT_name(), vmSymbols::sun_misc_Cleaner_signature(), - /*is_static=*/true, /*allow_super=*/false); + compute_offset(_context_offset, k, vmSymbols::context_name(), + vmSymbols::java_lang_invoke_MethodHandleNatives_CallSiteContext_signature()); } } -oop java_lang_invoke_CallSite::context_volatile(oop call_site) { - assert(java_lang_invoke_CallSite::is_instance(call_site), ""); - - oop dep_oop = call_site->obj_field_volatile(_context_offset); - return dep_oop; -} - -void java_lang_invoke_CallSite::set_context_volatile(oop call_site, oop context) { +oop java_lang_invoke_CallSite::context(oop call_site) { assert(java_lang_invoke_CallSite::is_instance(call_site), ""); - call_site->obj_field_put_volatile(_context_offset, context); -} - -bool java_lang_invoke_CallSite::set_context_cas(oop call_site, oop context, oop expected) { - assert(java_lang_invoke_CallSite::is_instance(call_site), ""); - HeapWord* context_addr = call_site->obj_field_addr(_context_offset); - oop res = oopDesc::atomic_compare_exchange_oop(context, context_addr, expected, true); - bool success = (res == expected); - if (success) { - update_barrier_set((void*)context_addr, context); + + oop dep_oop = call_site->obj_field(_context_offset); + return dep_oop; +} + +// Support for java_lang_invoke_MethodHandleNatives_CallSiteContext + +int java_lang_invoke_MethodHandleNatives_CallSiteContext::_vmdependencies_offset; + +void java_lang_invoke_MethodHandleNatives_CallSiteContext::compute_offsets() { + Klass* k = SystemDictionary::Context_klass(); + if (k != NULL) { + CALLSITECONTEXT_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); } - return success; -} - -oop java_lang_invoke_CallSite::default_context() { - InstanceKlass* ik = InstanceKlass::cast(SystemDictionary::CallSite_klass()); - oop def_context_oop = ik->java_mirror()->obj_field(_default_context_offset); - assert(!oopDesc::is_null(def_context_oop), ""); - return def_context_oop; +} + +nmethodBucket* java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(oop call_site) { + assert(java_lang_invoke_MethodHandleNatives_CallSiteContext::is_instance(call_site), ""); + return (nmethodBucket*) (address) call_site->long_field(_vmdependencies_offset); +} + +void java_lang_invoke_MethodHandleNatives_CallSiteContext::set_vmdependencies(oop call_site, nmethodBucket* context) { + assert(java_lang_invoke_MethodHandleNatives_CallSiteContext::is_instance(call_site), ""); + call_site->long_field_put(_vmdependencies_offset, (jlong) (address) context); } // Support for java_security_AccessControlContext @@ -3403,6 +3398,7 @@ java_lang_invoke_LambdaForm::compute_offsets(); java_lang_invoke_MethodType::compute_offsets(); java_lang_invoke_CallSite::compute_offsets(); + java_lang_invoke_MethodHandleNatives_CallSiteContext::compute_offsets(); java_security_AccessControlContext::compute_offsets(); // Initialize reflection classes. The layouts of these classes // changed with the new reflection implementation in JDK 1.4, and diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/classfile/javaClasses.hpp --- a/hotspot/src/share/vm/classfile/javaClasses.hpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Mon Jun 08 11:11:47 2015 -0700 @@ -1170,8 +1170,6 @@ private: static int _target_offset; static int _context_offset; - static int _default_context_offset; - static void compute_offsets(); @@ -1181,11 +1179,7 @@ static void set_target( oop site, oop target); static void set_target_volatile( oop site, oop target); - static oop context_volatile(oop site); - static void set_context_volatile(oop site, oop context); - static bool set_context_cas (oop site, oop context, oop expected); - - static oop default_context(); + static oop context(oop site); // Testers static bool is_subclass(Klass* klass) { @@ -1197,6 +1191,31 @@ static int target_offset_in_bytes() { return _target_offset; } }; +// Interface to java.lang.invoke.MethodHandleNatives$CallSiteContext objects + +#define CALLSITECONTEXT_INJECTED_FIELDS(macro) \ + macro(java_lang_invoke_MethodHandleNatives_CallSiteContext, vmdependencies, intptr_signature, false) + +class java_lang_invoke_MethodHandleNatives_CallSiteContext : AllStatic { + friend class JavaClasses; + +private: + static int _vmdependencies_offset; + + static void compute_offsets(); + +public: + // Accessors + static nmethodBucket* vmdependencies(oop context); + static void set_vmdependencies(oop context, nmethodBucket* bucket); + + // Testers + static bool is_subclass(Klass* klass) { + return klass->is_subclass_of(SystemDictionary::Context_klass()); + } + static bool is_instance(oop obj); +}; + // Interface to java.security.AccessControlContext objects class java_security_AccessControlContext: AllStatic { @@ -1406,7 +1425,8 @@ #define ALL_INJECTED_FIELDS(macro) \ CLASS_INJECTED_FIELDS(macro) \ CLASSLOADER_INJECTED_FIELDS(macro) \ - MEMBERNAME_INJECTED_FIELDS(macro) + MEMBERNAME_INJECTED_FIELDS(macro) \ + CALLSITECONTEXT_INJECTED_FIELDS(macro) // Interface to hard-coded offset checking diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/classfile/javaClasses.inline.hpp --- a/hotspot/src/share/vm/classfile/javaClasses.inline.hpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/classfile/javaClasses.inline.hpp Mon Jun 08 11:11:47 2015 -0700 @@ -49,6 +49,10 @@ return obj != NULL && is_subclass(obj->klass()); } +inline bool java_lang_invoke_MethodHandleNatives_CallSiteContext::is_instance(oop obj) { + return obj != NULL && is_subclass(obj->klass()); +} + inline bool java_lang_invoke_MemberName::is_instance(oop obj) { return obj != NULL && is_subclass(obj->klass()); } diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/classfile/systemDictionary.hpp --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp Mon Jun 08 11:11:47 2015 -0700 @@ -159,6 +159,7 @@ do_klass(MethodType_klass, java_lang_invoke_MethodType, Pre ) \ do_klass(BootstrapMethodError_klass, java_lang_BootstrapMethodError, Pre ) \ do_klass(CallSite_klass, java_lang_invoke_CallSite, Pre ) \ + do_klass(Context_klass, java_lang_invoke_MethodHandleNatives_CallSiteContext, Pre ) \ do_klass(ConstantCallSite_klass, java_lang_invoke_ConstantCallSite, Pre ) \ do_klass(MutableCallSite_klass, java_lang_invoke_MutableCallSite, Pre ) \ do_klass(VolatileCallSite_klass, java_lang_invoke_VolatileCallSite, Pre ) \ diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/classfile/verifier.cpp --- a/hotspot/src/share/vm/classfile/verifier.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/classfile/verifier.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -45,6 +45,8 @@ #include "runtime/javaCalls.hpp" #include "runtime/orderAccess.inline.hpp" #include "runtime/os.hpp" +#include "runtime/thread.hpp" +#include "services/threadService.hpp" #include "utilities/bytes.hpp" #define NOFAILOVER_MAJOR_VERSION 51 @@ -130,6 +132,16 @@ return true; } + // Timer includes any side effects of class verification (resolution, + // etc), but not recursive calls to Verifier::verify(). + JavaThread* jt = (JavaThread*)THREAD; + PerfClassTraceTime timer(ClassLoader::perf_class_verify_time(), + ClassLoader::perf_class_verify_selftime(), + ClassLoader::perf_classes_verified(), + jt->get_thread_stat()->perf_recursion_counts_addr(), + jt->get_thread_stat()->perf_timers_addr(), + PerfClassTraceTime::CLASS_VERIFY); + // If the class should be verified, first see if we can use the split // verifier. If not, or if verification fails and FailOverToOldVerifier // is set, then call the inference verifier. diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/classfile/vmSymbols.hpp --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Mon Jun 08 11:11:47 2015 -0700 @@ -274,12 +274,14 @@ /* internal classes known only to the JVM: */ \ template(java_lang_invoke_MemberName, "java/lang/invoke/MemberName") \ template(java_lang_invoke_MethodHandleNatives, "java/lang/invoke/MethodHandleNatives") \ + template(java_lang_invoke_MethodHandleNatives_CallSiteContext, "java/lang/invoke/MethodHandleNatives$CallSiteContext") \ template(java_lang_invoke_LambdaForm, "java/lang/invoke/LambdaForm") \ template(java_lang_invoke_ForceInline_signature, "Ljava/lang/invoke/ForceInline;") \ template(java_lang_invoke_DontInline_signature, "Ljava/lang/invoke/DontInline;") \ template(java_lang_invoke_Stable_signature, "Ljava/lang/invoke/Stable;") \ template(java_lang_invoke_LambdaForm_Compiled_signature, "Ljava/lang/invoke/LambdaForm$Compiled;") \ template(java_lang_invoke_LambdaForm_Hidden_signature, "Ljava/lang/invoke/LambdaForm$Hidden;") \ + template(java_lang_invoke_MethodHandleNatives_CallSiteContext_signature, "Ljava/lang/invoke/MethodHandleNatives$CallSiteContext;") \ /* internal up-calls made only by the JVM, via class sun.invoke.MethodHandleNatives: */ \ template(findMethodHandleType_name, "findMethodHandleType") \ template(findMethodHandleType_signature, "(Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/invoke/MethodType;") \ @@ -401,7 +403,7 @@ template(protection_domain_name, "protection_domain") \ template(signers_name, "signers_name") \ template(loader_data_name, "loader_data") \ - template(dependencies_name, "dependencies") \ + template(vmdependencies_name, "vmdependencies") \ template(input_stream_void_signature, "(Ljava/io/InputStream;)V") \ template(getFileURL_name, "getFileURL") \ template(getFileURL_signature, "(Ljava/io/File;)Ljava/net/URL;") \ diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/code/codeCache.cpp --- a/hotspot/src/share/vm/code/codeCache.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/code/codeCache.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -1047,40 +1047,6 @@ } } -// Flushes compiled methods dependent on a particular CallSite -// instance when its target is different than the given MethodHandle. -void CodeCache::flush_dependents_on(Handle call_site, Handle method_handle) { - assert_lock_strong(Compile_lock); - - if (number_of_nmethods_with_dependencies() == 0) return; - - // CodeCache can only be updated by a thread_in_VM and they will all be - // stopped during the safepoint so CodeCache will be safe to update without - // holding the CodeCache_lock. - - CallSiteDepChange changes(call_site(), method_handle()); - - // Compute the dependent nmethods that have a reference to a - // CallSite object. We use InstanceKlass::mark_dependent_nmethod - // directly instead of CodeCache::mark_for_deoptimization because we - // want dependents on the call site class only not all classes in - // the ContextStream. - int marked = 0; - { - MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - InstanceKlass* ctxk = MethodHandles::get_call_site_context(call_site()); - if (ctxk == NULL) { - return; // No dependencies to invalidate yet. - } - marked = ctxk->mark_dependent_nmethods(changes); - } - if (marked > 0) { - // At least one nmethod has been marked for deoptimization - VM_Deoptimize op; - VMThread::execute(&op); - } -} - #ifdef HOTSWAP // Flushes compiled methods dependent on dependee in the evolutionary sense void CodeCache::flush_evol_dependents_on(instanceKlassHandle ev_k_h) { diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/code/codeCache.hpp --- a/hotspot/src/share/vm/code/codeCache.hpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/code/codeCache.hpp Mon Jun 08 11:11:47 2015 -0700 @@ -224,7 +224,6 @@ // Flushing and deoptimization static void flush_dependents_on(instanceKlassHandle dependee); - static void flush_dependents_on(Handle call_site, Handle method_handle); #ifdef HOTSWAP // Flushing and deoptimization in case of evolution static void flush_evol_dependents_on(instanceKlassHandle dependee); diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/code/dependencies.cpp --- a/hotspot/src/share/vm/code/dependencies.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/code/dependencies.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -117,9 +117,7 @@ } void Dependencies::assert_call_site_target_value(ciCallSite* call_site, ciMethodHandle* method_handle) { - ciKlass* ctxk = call_site->get_context(); - check_ctxk(ctxk); - assert_common_3(call_site_target_value, ctxk, call_site, method_handle); + assert_common_2(call_site_target_value, call_site, method_handle); } // Helper function. If we are adding a new dep. under ctxk2, @@ -175,7 +173,6 @@ } } } else { - assert(dep_implicit_context_arg(dept) == 0, "sanity"); if (note_dep_seen(dept, x0) && note_dep_seen(dept, x1)) { // look in this bucket for redundant assertions const int stride = 2; @@ -389,7 +386,7 @@ 3, // unique_concrete_subtypes_2 ctxk, k1, k2 3, // unique_concrete_methods_2 ctxk, m1, m2 1, // no_finalizable_subclasses ctxk - 3 // call_site_target_value ctxk, call_site, method_handle + 2 // call_site_target_value call_site, method_handle }; const char* Dependencies::dep_name(Dependencies::DepType dept) { @@ -1515,16 +1512,11 @@ return find_finalizable_subclass(search_at); } -Klass* Dependencies::check_call_site_target_value(Klass* recorded_ctxk, oop call_site, oop method_handle, CallSiteDepChange* changes) { +Klass* Dependencies::check_call_site_target_value(oop call_site, oop method_handle, CallSiteDepChange* changes) { + assert(!oopDesc::is_null(call_site), "sanity"); + assert(!oopDesc::is_null(method_handle), "sanity"); assert(call_site->is_a(SystemDictionary::CallSite_klass()), "sanity"); - assert(!oopDesc::is_null(method_handle), "sanity"); - Klass* call_site_ctxk = MethodHandles::get_call_site_context(call_site); - assert(!Klass::is_null(call_site_ctxk), "call site context should be initialized already"); - if (recorded_ctxk != call_site_ctxk) { - // Stale context - return recorded_ctxk; - } if (changes == NULL) { // Validate all CallSites if (java_lang_invoke_CallSite::target(call_site) != method_handle) @@ -1599,7 +1591,7 @@ Klass* witness = NULL; switch (type()) { case call_site_target_value: - witness = check_call_site_target_value(context_type(), argument_oop(1), argument_oop(2), changes); + witness = check_call_site_target_value(argument_oop(0), argument_oop(1), changes); break; default: witness = NULL; diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/code/dependencies.hpp --- a/hotspot/src/share/vm/code/dependencies.hpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/code/dependencies.hpp Mon Jun 08 11:11:47 2015 -0700 @@ -173,7 +173,7 @@ non_klass_types = (1 << call_site_target_value), klass_types = all_types & ~non_klass_types, - non_ctxk_types = (1 << evol_method), + non_ctxk_types = (1 << evol_method) | (1 << call_site_target_value), implicit_ctxk_types = 0, explicit_ctxk_types = all_types & ~(non_ctxk_types | implicit_ctxk_types), @@ -330,7 +330,7 @@ static Klass* check_exclusive_concrete_methods(Klass* ctxk, Method* m1, Method* m2, KlassDepChange* changes = NULL); static Klass* check_has_no_finalizable_subclasses(Klass* ctxk, KlassDepChange* changes = NULL); - static Klass* check_call_site_target_value(Klass* recorded_ctxk, oop call_site, oop method_handle, CallSiteDepChange* changes = NULL); + static Klass* check_call_site_target_value(oop call_site, oop method_handle, CallSiteDepChange* changes = NULL); // A returned Klass* is NULL if the dependency assertion is still // valid. A non-NULL Klass* is a 'witness' to the assertion // failure, a point in the class hierarchy where the assertion has @@ -496,7 +496,7 @@ bool next(); DepType type() { return _type; } - bool is_oop_argument(int i) { return type() == call_site_target_value && i > 0; } + bool is_oop_argument(int i) { return type() == call_site_target_value; } uintptr_t get_identifier(int i); int argument_count() { return dep_args(type()); } diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/code/nmethod.cpp --- a/hotspot/src/share/vm/code/nmethod.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/code/nmethod.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -565,13 +565,18 @@ // the number of methods compiled. For applications with a lot // classes the slow way is too slow. for (Dependencies::DepStream deps(nm); deps.next(); ) { - Klass* klass = deps.context_type(); - if (klass == NULL) { - continue; // ignore things like evol_method + if (deps.type() == Dependencies::call_site_target_value) { + // CallSite dependencies are managed on per-CallSite instance basis. + oop call_site = deps.argument_oop(0); + MethodHandles::add_dependent_nmethod(call_site, nm); + } else { + Klass* klass = deps.context_type(); + if (klass == NULL) { + continue; // ignore things like evol_method + } + // record this nmethod as dependent on this klass + InstanceKlass::cast(klass)->add_dependent_nmethod(nm); } - - // record this nmethod as dependent on this klass - InstanceKlass::cast(klass)->add_dependent_nmethod(nm); } NOT_PRODUCT(nmethod_stats.note_nmethod(nm)); if (PrintAssembly || CompilerOracle::has_option_string(method, "PrintAssembly")) { @@ -1464,13 +1469,20 @@ if (!has_flushed_dependencies()) { set_has_flushed_dependencies(); for (Dependencies::DepStream deps(this); deps.next(); ) { - Klass* klass = deps.context_type(); - if (klass == NULL) continue; // ignore things like evol_method - - // During GC the is_alive closure is non-NULL, and is used to - // determine liveness of dependees that need to be updated. - if (is_alive == NULL || klass->is_loader_alive(is_alive)) { - InstanceKlass::cast(klass)->remove_dependent_nmethod(this); + if (deps.type() == Dependencies::call_site_target_value) { + // CallSite dependencies are managed on per-CallSite instance basis. + oop call_site = deps.argument_oop(0); + MethodHandles::remove_dependent_nmethod(call_site, this); + } else { + Klass* klass = deps.context_type(); + if (klass == NULL) { + continue; // ignore things like evol_method + } + // During GC the is_alive closure is non-NULL, and is used to + // determine liveness of dependees that need to be updated. + if (is_alive == NULL || klass->is_loader_alive(is_alive)) { + InstanceKlass::cast(klass)->remove_dependent_nmethod(this); + } } } } diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/gc/cms/vmCMSOperations.cpp --- a/hotspot/src/share/vm/gc/cms/vmCMSOperations.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/gc/cms/vmCMSOperations.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -254,9 +254,9 @@ if (_gc_cause != GCCause::_gc_locker && gch->total_full_collections_completed() <= _full_gc_count_before) { // maybe we should change the condition to test _gc_cause == - // GCCause::_java_lang_system_gc, instead of - // _gc_cause != GCCause::_gc_locker - assert(_gc_cause == GCCause::_java_lang_system_gc, + // GCCause::_java_lang_system_gc or GCCause::_dcmd_gc_run, + // instead of _gc_cause != GCCause::_gc_locker + assert(GCCause::is_user_requested_gc(_gc_cause), "the only way to get here if this was a System.gc()-induced GC"); assert(ExplicitGCInvokesConcurrent, "Error"); // Now, wait for witnessing concurrent gc cycle to complete, diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/gc/cms/yieldingWorkgroup.cpp --- a/hotspot/src/share/vm/gc/cms/yieldingWorkgroup.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/gc/cms/yieldingWorkgroup.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -43,7 +43,7 @@ } // Run a task; returns when the task is done, or the workers yield, -// or the task is aborted, or the work gang is terminated via stop(). +// or the task is aborted. // A task that has been yielded can be continued via this interface // by using the same task repeatedly as the argument to the call. // It is expected that the YieldingFlexibleGangTask carries the appropriate @@ -297,16 +297,9 @@ WorkData data; int id; while (true) { - // Check if there is work to do or if we have been asked - // to terminate + // Check if there is work to do. gang()->internal_worker_poll(&data); - if (data.terminate()) { - // We have been asked to terminate. - assert(gang()->task() == NULL, "No task binding"); - // set_status(TERMINATED); - return; - } else if (data.task() != NULL && - data.sequence_number() != previous_sequence_number) { + if (data.task() != NULL && data.sequence_number() != previous_sequence_number) { // There is work to be done. // First check if we need to become active or if there // are already the requisite number of workers diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/gc/cms/yieldingWorkgroup.hpp --- a/hotspot/src/share/vm/gc/cms/yieldingWorkgroup.hpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/gc/cms/yieldingWorkgroup.hpp Mon Jun 08 11:11:47 2015 -0700 @@ -176,7 +176,7 @@ GangWorker* allocate_worker(uint which); // Run a task; returns when the task is done, or the workers yield, - // or the task is aborted, or the work gang is terminated via stop(). + // or the task is aborted. // A task that has been yielded can be continued via this same interface // by using the same task repeatedly as the argument to the call. // It is expected that the YieldingFlexibleGangTask carries the appropriate diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -1183,7 +1183,7 @@ IsGCActiveMark x; // Timing - assert(gc_cause() != GCCause::_java_lang_system_gc || explicit_gc, "invariant"); + assert(!GCCause::is_user_requested_gc(gc_cause()) || explicit_gc, "invariant"); TraceCPUTime tcpu(G1Log::finer(), true, gclog_or_tty); { @@ -2199,6 +2199,7 @@ switch (cause) { case GCCause::_gc_locker: return GCLockerInvokesConcurrent; case GCCause::_java_lang_system_gc: return ExplicitGCInvokesConcurrent; + case GCCause::_dcmd_gc_run: return ExplicitGCInvokesConcurrent; case GCCause::_g1_humongous_allocation: return true; case GCCause::_update_allocation_context_stats_inc: return true; case GCCause::_wb_conc_mark: return true; diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Mon Jun 08 11:11:47 2015 -0700 @@ -324,7 +324,8 @@ // explicitly started if: // (a) cause == _gc_locker and +GCLockerInvokesConcurrent, or // (b) cause == _java_lang_system_gc and +ExplicitGCInvokesConcurrent. - // (c) cause == _g1_humongous_allocation + // (c) cause == _dcmd_gc_run and +ExplicitGCInvokesConcurrent. + // (d) cause == _g1_humongous_allocation bool should_do_concurrent_full_gc(GCCause::Cause cause); // Keeps track of how many "old marking cycles" (i.e., Full GCs or diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/gc/g1/vm_operations_g1.cpp --- a/hotspot/src/share/vm/gc/g1/vm_operations_g1.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/gc/g1/vm_operations_g1.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -168,7 +168,7 @@ // +ExplicitGCInvokesConcurrent, we have to wait here for the cycle // that just started (or maybe one that was already in progress) to // finish. - if (_gc_cause == GCCause::_java_lang_system_gc && + if (GCCause::is_user_requested_gc(_gc_cause) && _should_initiate_conc_mark) { assert(ExplicitGCInvokesConcurrent, "the only way to be here is if ExplicitGCInvokesConcurrent is set"); diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/gc/parallel/psAdaptiveSizePolicy.cpp --- a/hotspot/src/share/vm/gc/parallel/psAdaptiveSizePolicy.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/gc/parallel/psAdaptiveSizePolicy.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -130,7 +130,7 @@ // Update the pause time. _major_timer.stop(); - if (gc_cause != GCCause::_java_lang_system_gc || + if (!GCCause::is_user_requested_gc(gc_cause) || UseAdaptiveSizePolicyWithSystemGC) { double major_pause_in_seconds = _major_timer.seconds(); double major_pause_in_ms = major_pause_in_seconds * MILLIUNITS; diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp --- a/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -272,7 +272,7 @@ // Don't check if the size_policy is ready here. Let // the size_policy check that internally. if (UseAdaptiveGenerationSizePolicyAtMajorCollection && - ((gc_cause != GCCause::_java_lang_system_gc) || + (!GCCause::is_user_requested_gc(gc_cause) || UseAdaptiveSizePolicyWithSystemGC)) { // Swap the survivor spaces if from_space is empty. The // resize_young_gen() called below is normally used after diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp --- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -2053,7 +2053,7 @@ marking_phase(vmthread_cm, maximum_heap_compaction, &_gc_tracer); bool max_on_system_gc = UseMaximumCompactionOnSystemGC - && gc_cause == GCCause::_java_lang_system_gc; + && GCCause::is_user_requested_gc(gc_cause); summary_phase(vmthread_cm, maximum_heap_compaction || max_on_system_gc); COMPILER2_PRESENT(assert(DerivedPointerTable::is_active(), "Sanity")); @@ -2089,7 +2089,7 @@ // Don't check if the size_policy is ready here. Let // the size_policy check that internally. if (UseAdaptiveGenerationSizePolicyAtMajorCollection && - ((gc_cause != GCCause::_java_lang_system_gc) || + (!GCCause::is_user_requested_gc(gc_cause) || UseAdaptiveSizePolicyWithSystemGC)) { // Swap the survivor spaces if from_space is empty. The // resize_young_gen() called below is normally used after diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/gc/parallel/psScavenge.cpp --- a/hotspot/src/share/vm/gc/parallel/psScavenge.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/gc/parallel/psScavenge.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -290,7 +290,7 @@ AdaptiveSizePolicyOutput(size_policy, heap->total_collections()); - if ((gc_cause != GCCause::_java_lang_system_gc) || + if (!GCCause::is_user_requested_gc(gc_cause) || UseAdaptiveSizePolicyWithSystemGC) { // Gather the feedback data for eden occupancy. young_gen->eden_space()->accumulate_statistics(); diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/gc/serial/defNewGeneration.cpp --- a/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -960,7 +960,7 @@ GCCause::to_string(gch->gc_cause())); } assert(gch->gc_cause() == GCCause::_scavenge_alot || - (gch->gc_cause() == GCCause::_java_lang_system_gc && UseConcMarkSweepGC && ExplicitGCInvokesConcurrent) || + (GCCause::is_user_requested_gc(gch->gc_cause()) && UseConcMarkSweepGC && ExplicitGCInvokesConcurrent) || !gch->incremental_collection_failed(), "Twice in a row"); seen_incremental_collection_failed = false; diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/gc/shared/adaptiveSizePolicy.cpp --- a/hotspot/src/share/vm/gc/shared/adaptiveSizePolicy.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/gc/shared/adaptiveSizePolicy.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -244,7 +244,7 @@ // Update the pause time. _minor_timer.stop(); - if (gc_cause != GCCause::_java_lang_system_gc || + if (!GCCause::is_user_requested_gc(gc_cause) || UseAdaptiveSizePolicyWithSystemGC) { double minor_pause_in_seconds = _minor_timer.seconds(); double minor_pause_in_ms = minor_pause_in_seconds * MILLIUNITS; diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/gc/shared/gcCause.cpp --- a/hotspot/src/share/vm/gc/shared/gcCause.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/gc/shared/gcCause.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -103,6 +103,9 @@ case _last_ditch_collection: return "Last ditch collection"; + case _dcmd_gc_run: + return "Diagnostic Command"; + case _last_gc_cause: return "ILLEGAL VALUE - last gc cause - ILLEGAL VALUE"; diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/gc/shared/gcCause.hpp --- a/hotspot/src/share/vm/gc/shared/gcCause.hpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/gc/shared/gcCause.hpp Mon Jun 08 11:11:47 2015 -0700 @@ -74,12 +74,15 @@ _g1_humongous_allocation, _last_ditch_collection, + + _dcmd_gc_run, + _last_gc_cause }; inline static bool is_user_requested_gc(GCCause::Cause cause) { return (cause == GCCause::_java_lang_system_gc || - cause == GCCause::_jvmti_force_gc); + cause == GCCause::_dcmd_gc_run); } inline static bool is_serviceability_requested_gc(GCCause::Cause diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp --- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -304,9 +304,16 @@ } bool GenCollectedHeap::should_do_concurrent_full_gc(GCCause::Cause cause) { - return UseConcMarkSweepGC && - ((cause == GCCause::_gc_locker && GCLockerInvokesConcurrent) || - (cause == GCCause::_java_lang_system_gc && ExplicitGCInvokesConcurrent)); + if (!UseConcMarkSweepGC) { + return false; + } + + switch (cause) { + case GCCause::_gc_locker: return GCLockerInvokesConcurrent; + case GCCause::_java_lang_system_gc: + case GCCause::_dcmd_gc_run: return ExplicitGCInvokesConcurrent; + default: return false; + } } void GenCollectedHeap::collect_generation(Generation* gen, bool full, size_t size, diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/gc/shared/workgroup.cpp --- a/hotspot/src/share/vm/gc/shared/workgroup.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/gc/shared/workgroup.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -47,7 +47,6 @@ /* allow_vm_block */ are_GC_task_threads, Monitor::_safepoint_check_sometimes); assert(monitor() != NULL, "Failed to allocate monitor"); - _terminate = false; _task = NULL; _sequence_number = 0; _started_workers = 0; @@ -106,18 +105,6 @@ return true; } -AbstractWorkGang::~AbstractWorkGang() { - if (TraceWorkGang) { - tty->print_cr("Destructing work gang %s", name()); - } - stop(); // stop all the workers - for (uint worker = 0; worker < total_workers(); worker += 1) { - delete gang_worker(worker); - } - delete gang_workers(); - delete monitor(); -} - GangWorker* AbstractWorkGang::gang_worker(uint i) const { // Array index bounds checking. GangWorker* result = NULL; @@ -175,28 +162,9 @@ WorkGang::run_task(task, (uint) active_workers()); } -void AbstractWorkGang::stop() { - // Tell all workers to terminate, then wait for them to become inactive. - MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); - if (TraceWorkGang) { - tty->print_cr("Stopping work gang %s task %s", name(), task()->name()); - } - _task = NULL; - _terminate = true; - monitor()->notify_all(); - while (finished_workers() < active_workers()) { - if (TraceWorkGang) { - tty->print_cr("Waiting in work gang %s: %u/%u finished", - name(), finished_workers(), active_workers()); - } - monitor()->wait(/* no_safepoint_check */ true); - } -} - void AbstractWorkGang::internal_worker_poll(WorkData* data) const { assert(monitor()->owned_by_self(), "worker_poll is an internal method"); assert(data != NULL, "worker data is null"); - data->set_terminate(terminate()); data->set_task(task()); data->set_sequence_number(sequence_number()); } @@ -259,7 +227,7 @@ void GangWorker::loop() { int previous_sequence_number = 0; Monitor* gang_monitor = gang()->monitor(); - for ( ; /* !terminate() */; ) { + for ( ; ; ) { WorkData data; int part; // Initialized below. { @@ -272,8 +240,6 @@ if (TraceWorkGang) { tty->print("Polled outside for work in gang %s worker %u", gang()->name(), id()); - tty->print(" terminate: %s", - data.terminate() ? "true" : "false"); tty->print(" sequence: %d (prev: %d)", data.sequence_number(), previous_sequence_number); if (data.task() != NULL) { @@ -283,13 +249,7 @@ } tty->cr(); } - for ( ; /* break or return */; ) { - // Terminate if requested. - if (data.terminate()) { - gang()->internal_note_finish(); - gang_monitor->notify_all(); - return; - } + for ( ; /* break */; ) { // Check for new work. if ((data.task() != NULL) && (data.sequence_number() != previous_sequence_number)) { @@ -306,8 +266,6 @@ if (TraceWorkGang) { tty->print("Polled inside for work in gang %s worker %u", gang()->name(), id()); - tty->print(" terminate: %s", - data.terminate() ? "true" : "false"); tty->print(" sequence: %d (prev: %d)", data.sequence_number(), previous_sequence_number); if (data.task() != NULL) { diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/gc/shared/workgroup.hpp --- a/hotspot/src/share/vm/gc/shared/workgroup.hpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/gc/shared/workgroup.hpp Mon Jun 08 11:11:47 2015 -0700 @@ -103,16 +103,15 @@ // An abstract class representing a gang of workers. // You subclass this to supply an implementation of run_task(). class AbstractWorkGang: public CHeapObj { - // Here's the public interface to this class. +protected: + // Work gangs are never deleted, so no need to cleanup. + ~AbstractWorkGang() { ShouldNotReachHere(); } public: - // Constructor and destructor. + // Constructor. AbstractWorkGang(const char* name, bool are_GC_task_threads, bool are_ConcurrentGC_threads); - ~AbstractWorkGang(); // Run a task, returns when the task is done (or terminated). virtual void run_task(AbstractGangTask* task) = 0; - // Stop and terminate all workers. - virtual void stop(); // Return true if more workers should be applied to the task. virtual bool needs_more_workers() const { return true; } public: @@ -129,8 +128,6 @@ Monitor* _monitor; // The count of the number of workers in the gang. uint _total_workers; - // Whether the workers should terminate. - bool _terminate; // The array of worker threads for this gang. // This is only needed for cleaning up. GangWorker** _gang_workers; @@ -153,9 +150,6 @@ virtual uint active_workers() const { return _total_workers; } - bool terminate() const { - return _terminate; - } GangWorker** gang_workers() const { return _gang_workers; } @@ -205,21 +199,16 @@ class WorkData: public StackObj { // This would be a struct, but I want accessor methods. private: - bool _terminate; AbstractGangTask* _task; int _sequence_number; public: // Constructor and destructor WorkData() { - _terminate = false; _task = NULL; _sequence_number = 0; } ~WorkData() { } - // Accessors and modifiers - bool terminate() const { return _terminate; } - void set_terminate(bool value) { _terminate = value; } AbstractGangTask* task() const { return _task; } void set_task(AbstractGangTask* value) { _task = value; } int sequence_number() const { return _sequence_number; } diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/interpreter/bytecode.cpp --- a/hotspot/src/share/vm/interpreter/bytecode.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/interpreter/bytecode.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, 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 @@ -147,13 +147,10 @@ methodHandle Bytecode_invoke::static_target(TRAPS) { - methodHandle m; - KlassHandle resolved_klass; constantPoolHandle constants(THREAD, this->constants()); Bytecodes::Code bc = invoke_code(); - LinkResolver::resolve_method_statically(m, resolved_klass, bc, constants, index(), CHECK_(methodHandle())); - return m; + return LinkResolver::resolve_method_statically(bc, constants, index(), THREAD); } Handle Bytecode_invoke::appendix(TRAPS) { diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/interpreter/linkResolver.cpp --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -52,13 +52,17 @@ // Implementation of CallInfo -void CallInfo::set_static(KlassHandle resolved_klass, methodHandle resolved_method, TRAPS) { +void CallInfo::set_static(KlassHandle resolved_klass, const methodHandle& resolved_method, TRAPS) { int vtable_index = Method::nonvirtual_vtable_index; set_common(resolved_klass, resolved_klass, resolved_method, resolved_method, CallInfo::direct_call, vtable_index, CHECK); } -void CallInfo::set_interface(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int itable_index, TRAPS) { +void CallInfo::set_interface(KlassHandle resolved_klass, + KlassHandle selected_klass, + const methodHandle& resolved_method, + const methodHandle& selected_method, + int itable_index, TRAPS) { // This is only called for interface methods. If the resolved_method // comes from java/lang/Object, it can be the subject of a virtual call, so // we should pick the vtable index from the resolved method. @@ -68,7 +72,11 @@ set_common(resolved_klass, selected_klass, resolved_method, selected_method, CallInfo::itable_call, itable_index, CHECK); } -void CallInfo::set_virtual(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index, TRAPS) { +void CallInfo::set_virtual(KlassHandle resolved_klass, + KlassHandle selected_klass, + const methodHandle& resolved_method, + const methodHandle& selected_method, + int vtable_index, TRAPS) { assert(vtable_index >= 0 || vtable_index == Method::nonvirtual_vtable_index, "valid index"); assert(vtable_index < 0 || !resolved_method->has_vtable_index() || vtable_index == resolved_method->vtable_index(), ""); CallKind kind = (vtable_index >= 0 && !resolved_method->can_be_statically_bound() ? CallInfo::vtable_call : CallInfo::direct_call); @@ -76,7 +84,9 @@ assert(!resolved_method->is_compiled_lambda_form(), "these must be handled via an invokehandle call"); } -void CallInfo::set_handle(methodHandle resolved_method, Handle resolved_appendix, Handle resolved_method_type, TRAPS) { +void CallInfo::set_handle(const methodHandle& resolved_method, + Handle resolved_appendix, + Handle resolved_method_type, TRAPS) { if (resolved_method.is_null()) { THROW_MSG(vmSymbols::java_lang_InternalError(), "resolved method is null"); } @@ -93,8 +103,8 @@ void CallInfo::set_common(KlassHandle resolved_klass, KlassHandle selected_klass, - methodHandle resolved_method, - methodHandle selected_method, + const methodHandle& resolved_method, + const methodHandle& selected_method, CallKind kind, int index, TRAPS) { @@ -210,8 +220,52 @@ } #endif //ASSERT +#ifndef PRODUCT +void CallInfo::print() { + ResourceMark rm; + const char* kindstr = "unknown"; + switch (_call_kind) { + case direct_call: kindstr = "direct"; break; + case vtable_call: kindstr = "vtable"; break; + case itable_call: kindstr = "itable"; break; + } + tty->print_cr("Call %s@%d %s", kindstr, _call_index, + _resolved_method.is_null() ? "(none)" : _resolved_method->name_and_sig_as_C_string()); +} +#endif +//------------------------------------------------------------------------------------------------------------------------ +// Implementation of LinkInfo +LinkInfo::LinkInfo(constantPoolHandle pool, int index, TRAPS) { + // resolve klass + Klass* result = pool->klass_ref_at(index, CHECK); + _resolved_klass = KlassHandle(THREAD, result); + + // Get name, signature, and static klass + _name = pool->name_ref_at(index); + _signature = pool->signature_ref_at(index); + _current_klass = KlassHandle(THREAD, pool->pool_holder()); + + // Coming from the constant pool always checks access + _check_access = true; +} + +char* LinkInfo::method_string() const { + return Method::name_and_sig_as_C_string(_resolved_klass(), _name, _signature); +} + +#ifndef PRODUCT +void LinkInfo::print() { + ResourceMark rm; + tty->print_cr("Link resolved_klass=%s name=%s signature=%s current_klass=%s check_access=%s", + _resolved_klass->name()->as_C_string(), + _name->as_C_string(), + _signature->as_C_string(), + _current_klass.is_null() ? "(none)" : _current_klass->name()->as_C_string(), + _check_access ? "true" : "false"); +} +#endif // PRODUCT //------------------------------------------------------------------------------------------------------------------------ // Klass resolution @@ -231,11 +285,6 @@ } } -void LinkResolver::resolve_klass(KlassHandle& result, constantPoolHandle pool, int index, TRAPS) { - Klass* result_oop = pool->klass_ref_at(index, CHECK); - result = KlassHandle(THREAD, result_oop); -} - //------------------------------------------------------------------------------------------------------------------------ // Method resolution // @@ -243,76 +292,84 @@ // Look up method in klasses, including static methods // Then look up local default methods -void LinkResolver::lookup_method_in_klasses(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, bool checkpolymorphism, bool in_imethod_resolve, TRAPS) { +methodHandle LinkResolver::lookup_method_in_klasses(const LinkInfo& link_info, + bool checkpolymorphism, + bool in_imethod_resolve, TRAPS) { + KlassHandle klass = link_info.resolved_klass(); + Symbol* name = link_info.name(); + Symbol* signature = link_info.signature(); + // Ignore overpasses so statics can be found during resolution - Method* result_oop = klass->uncached_lookup_method(name, signature, Klass::skip_overpass); + Method* result = klass->uncached_lookup_method(name, signature, Klass::skip_overpass); if (klass->oop_is_array()) { // Only consider klass and super klass for arrays - result = methodHandle(THREAD, result_oop); - return; + return methodHandle(THREAD, result); } // JDK 8, JVMS 5.4.3.4: Interface method resolution should // ignore static and non-public methods of java.lang.Object, // like clone, finalize, registerNatives. if (in_imethod_resolve && - result_oop != NULL && + result != NULL && klass->is_interface() && - (result_oop->is_static() || !result_oop->is_public()) && - result_oop->method_holder() == SystemDictionary::Object_klass()) { - result_oop = NULL; + (result->is_static() || !result->is_public()) && + result->method_holder() == SystemDictionary::Object_klass()) { + result = NULL; } // Before considering default methods, check for an overpass in the // current class if a method has not been found. - if (result_oop == NULL) { - result_oop = InstanceKlass::cast(klass())->find_method(name, signature); + if (result == NULL) { + result = InstanceKlass::cast(klass())->find_method(name, signature); } - if (result_oop == NULL) { + if (result == NULL) { Array* default_methods = InstanceKlass::cast(klass())->default_methods(); if (default_methods != NULL) { - result_oop = InstanceKlass::find_method(default_methods, name, signature); + result = InstanceKlass::find_method(default_methods, name, signature); } } - if (checkpolymorphism && result_oop != NULL) { - vmIntrinsics::ID iid = result_oop->intrinsic_id(); + if (checkpolymorphism && result != NULL) { + vmIntrinsics::ID iid = result->intrinsic_id(); if (MethodHandles::is_signature_polymorphic(iid)) { // Do not link directly to these. The VM must produce a synthetic one using lookup_polymorphic_method. - return; + return NULL; } } - result = methodHandle(THREAD, result_oop); + return methodHandle(THREAD, result); } // returns first instance method // Looks up method in classes, then looks up local default methods -void LinkResolver::lookup_instance_method_in_klasses(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) { - Method* result_oop = klass->uncached_lookup_method(name, signature, Klass::find_overpass); - result = methodHandle(THREAD, result_oop); - while (!result.is_null() && result->is_static() && result->method_holder()->super() != NULL) { - KlassHandle super_klass = KlassHandle(THREAD, result->method_holder()->super()); - result = methodHandle(THREAD, super_klass->uncached_lookup_method(name, signature, Klass::find_overpass)); +methodHandle LinkResolver::lookup_instance_method_in_klasses(KlassHandle klass, + Symbol* name, + Symbol* signature, TRAPS) { + Method* result = klass->uncached_lookup_method(name, signature, Klass::find_overpass); + + while (result != NULL && result->is_static() && result->method_holder()->super() != NULL) { + Klass* super_klass = result->method_holder()->super(); + result = super_klass->uncached_lookup_method(name, signature, Klass::find_overpass); } if (klass->oop_is_array()) { // Only consider klass and super klass for arrays - return; + return methodHandle(THREAD, result); } - if (result.is_null()) { + if (result == NULL) { Array* default_methods = InstanceKlass::cast(klass())->default_methods(); if (default_methods != NULL) { - result = methodHandle(InstanceKlass::find_method(default_methods, name, signature)); - assert(result.is_null() || !result->is_static(), "static defaults not allowed"); + result = InstanceKlass::find_method(default_methods, name, signature); + assert(result == NULL || !result->is_static(), "static defaults not allowed"); } } + return methodHandle(THREAD, result); } int LinkResolver::vtable_index_of_interface_method(KlassHandle klass, - methodHandle resolved_method) { + const methodHandle& resolved_method) { int vtable_index = Method::invalid_vtable_index; Symbol* name = resolved_method->name(); @@ -336,21 +393,26 @@ return vtable_index; } -void LinkResolver::lookup_method_in_interfaces(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) { - InstanceKlass *ik = InstanceKlass::cast(klass()); +methodHandle LinkResolver::lookup_method_in_interfaces(const LinkInfo& cp_info, TRAPS) { + InstanceKlass *ik = InstanceKlass::cast(cp_info.resolved_klass()()); // Specify 'true' in order to skip default methods when searching the // interfaces. Function lookup_method_in_klasses() already looked for // the method in the default methods table. - result = methodHandle(THREAD, ik->lookup_method_in_all_interfaces(name, signature, Klass::skip_defaults)); + return methodHandle(THREAD, + ik->lookup_method_in_all_interfaces(cp_info.name(), cp_info.signature(), + Klass::skip_defaults)); } -void LinkResolver::lookup_polymorphic_method(methodHandle& result, - KlassHandle klass, Symbol* name, Symbol* full_signature, - KlassHandle current_klass, +methodHandle LinkResolver::lookup_polymorphic_method( + const LinkInfo& link_info, Handle *appendix_result_or_null, Handle *method_type_result, TRAPS) { + KlassHandle klass = link_info.resolved_klass(); + Symbol* name = link_info.name(); + Symbol* full_signature = link_info.signature(); + vmIntrinsics::ID iid = MethodHandles::signature_polymorphic_name_id(name); if (TraceMethodHandles) { ResourceMark rm(THREAD); @@ -365,7 +427,7 @@ // Do not erase last argument type (MemberName) if it is a static linkTo method. bool keep_last_arg = MethodHandles::is_signature_polymorphic_static(iid); TempNewSymbol basic_signature = - MethodHandles::lookup_basic_type_signature(full_signature, keep_last_arg, CHECK); + 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", @@ -373,9 +435,9 @@ full_signature->as_C_string(), basic_signature->as_C_string()); } - result = SystemDictionary::find_method_handle_intrinsic(iid, + methodHandle result = SystemDictionary::find_method_handle_intrinsic(iid, basic_signature, - CHECK); + CHECK_NULL); if (result.not_null()) { assert(result->is_method_handle_intrinsic(), "MH.invokeBasic or MH.linkTo* intrinsic"); assert(result->intrinsic_id() != vmIntrinsics::_invokeGeneric, "wrong place to find this"); @@ -384,8 +446,8 @@ tty->print("lookup_polymorphic_method => intrinsic "); result->print_on(tty); } - return; } + return result; } else if (iid == vmIntrinsics::_invokeGeneric && !THREAD->is_Compiler_thread() && appendix_result_or_null != NULL) { @@ -399,18 +461,19 @@ Handle(), Handle(), true, - CHECK); + CHECK_NULL); } } Handle appendix; Handle method_type; - result = SystemDictionary::find_method_handle_invoker(name, + methodHandle result = SystemDictionary::find_method_handle_invoker( + name, full_signature, - current_klass, + link_info.current_klass(), &appendix, &method_type, - CHECK); + CHECK_NULL); if (TraceMethodHandles) { tty->print("lookup_polymorphic_method => (via Java) "); result->print_on(tty); @@ -423,7 +486,7 @@ ResourceMark rm(THREAD); TempNewSymbol basic_signature = - MethodHandles::lookup_basic_type_signature(full_signature, CHECK); + MethodHandles::lookup_basic_type_signature(full_signature, CHECK_NULL); int actual_size_of_params = result->size_of_parameters(); int expected_size_of_params = ArgumentSizeComputer(basic_signature).size(); // +1 for MethodHandle.this, +1 for trailing MethodType @@ -441,16 +504,17 @@ assert(appendix_result_or_null != NULL, ""); (*appendix_result_or_null) = appendix; (*method_type_result) = method_type; - return; } + return result; } } + return NULL; } void LinkResolver::check_method_accessability(KlassHandle ref_klass, KlassHandle resolved_klass, KlassHandle sel_klass, - methodHandle sel_method, + const methodHandle& sel_method, TRAPS) { AccessFlags flags = sel_method->access_flags(); @@ -493,8 +557,8 @@ } } -void LinkResolver::resolve_method_statically(methodHandle& resolved_method, KlassHandle& resolved_klass, - Bytecodes::Code code, constantPoolHandle pool, int index, TRAPS) { +methodHandle LinkResolver::resolve_method_statically(Bytecodes::Code code, + constantPoolHandle pool, int index, TRAPS) { // This method is used only // (1) in C2 from InlineTree::ok_to_inline (via ciMethod::check_call), // and @@ -502,49 +566,108 @@ // It appears to fail when applied to an invokeinterface call site. // FIXME: Remove this method and ciMethod::check_call; refactor to use the other LinkResolver entry points. // resolve klass + KlassHandle resolved_klass; if (code == Bytecodes::_invokedynamic) { resolved_klass = SystemDictionary::MethodHandle_klass(); Symbol* method_name = vmSymbols::invoke_name(); Symbol* method_signature = pool->signature_ref_at(index); KlassHandle current_klass(THREAD, pool->pool_holder()); - resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, false, CHECK); - return; + LinkInfo link_info(resolved_klass, method_name, method_signature, current_klass); + return resolve_method(link_info, /*require_methodref*/false, THREAD); } - resolve_klass(resolved_klass, pool, index, CHECK); - - Symbol* method_name = pool->name_ref_at(index); - Symbol* method_signature = pool->signature_ref_at(index); - KlassHandle current_klass(THREAD, pool->pool_holder()); + LinkInfo link_info(pool, index, CHECK_NULL); + resolved_klass = link_info.resolved_klass(); if (pool->has_preresolution() || (resolved_klass() == SystemDictionary::MethodHandle_klass() && - MethodHandles::is_signature_polymorphic_name(resolved_klass(), method_name))) { - Method* result_oop = ConstantPool::method_at_if_loaded(pool, index); - if (result_oop != NULL) { - resolved_method = methodHandle(THREAD, result_oop); - return; + MethodHandles::is_signature_polymorphic_name(resolved_klass(), link_info.name()))) { + Method* result = ConstantPool::method_at_if_loaded(pool, index); + if (result != NULL) { + return methodHandle(THREAD, result); } } if (code == Bytecodes::_invokeinterface) { - resolve_interface_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, true, CHECK); + return resolve_interface_method(link_info, true, THREAD); } else if (code == Bytecodes::_invokevirtual) { - resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, true, CHECK); + return resolve_method(link_info, /*require_methodref*/true, THREAD); } else if (!resolved_klass->is_interface()) { - resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, false, CHECK); + return resolve_method(link_info, /*require_methodref*/false, THREAD); } else { bool nostatics = (code == Bytecodes::_invokestatic) ? false : true; - resolve_interface_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, nostatics, CHECK); + return resolve_interface_method(link_info, nostatics, THREAD); } } -void LinkResolver::resolve_method(methodHandle& resolved_method, KlassHandle resolved_klass, - Symbol* method_name, Symbol* method_signature, - KlassHandle current_klass, bool check_access, - bool require_methodref, TRAPS) { +// Check and print a loader constraint violation message for method or interface method +void LinkResolver::check_method_loader_constraints(const LinkInfo& link_info, + const methodHandle& resolved_method, + const char* method_type, TRAPS) { + Handle current_loader(THREAD, link_info.current_klass()->class_loader()); + Handle resolved_loader(THREAD, resolved_method->method_holder()->class_loader()); + + ResourceMark rm(THREAD); + Symbol* failed_type_symbol = + SystemDictionary::check_signature_loaders(link_info.signature(), current_loader, + resolved_loader, true, CHECK); + if (failed_type_symbol != NULL) { + const char* msg = "loader constraint violation: when resolving %s" + " \"%s\" the class loader (instance of %s) of the current class, %s," + " and the class loader (instance of %s) for the method's defining class, %s, have" + " different Class objects for the type %s used in the signature"; + char* sig = link_info.method_string(); + const char* loader1_name = SystemDictionary::loader_name(current_loader()); + char* current = link_info.current_klass()->name()->as_C_string(); + const char* loader2_name = SystemDictionary::loader_name(resolved_loader()); + char* target = resolved_method->method_holder()->name()->as_C_string(); + char* failed_type_name = failed_type_symbol->as_C_string(); + size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1_name) + + strlen(current) + strlen(loader2_name) + strlen(target) + + strlen(failed_type_name) + strlen(method_type) + 1; + char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen); + jio_snprintf(buf, buflen, msg, method_type, sig, loader1_name, current, loader2_name, + target, failed_type_name); + THROW_MSG(vmSymbols::java_lang_LinkageError(), buf); + } +} + +void LinkResolver::check_field_loader_constraints(Symbol* field, Symbol* sig, + KlassHandle current_klass, + KlassHandle sel_klass, TRAPS) { + Handle ref_loader(THREAD, current_klass->class_loader()); + Handle sel_loader(THREAD, sel_klass->class_loader()); + + ResourceMark rm(THREAD); // needed for check_signature_loaders + Symbol* failed_type_symbol = + SystemDictionary::check_signature_loaders(sig, + ref_loader, sel_loader, + false, + CHECK); + if (failed_type_symbol != NULL) { + const char* msg = "loader constraint violation: when resolving field" + " \"%s\" the class loader (instance of %s) of the referring class, " + "%s, and the class loader (instance of %s) for the field's resolved " + "type, %s, have different Class objects for that type"; + char* field_name = field->as_C_string(); + const char* loader1_name = SystemDictionary::loader_name(ref_loader()); + char* sel = sel_klass->name()->as_C_string(); + const char* loader2_name = SystemDictionary::loader_name(sel_loader()); + char* failed_type_name = failed_type_symbol->as_C_string(); + size_t buflen = strlen(msg) + strlen(field_name) + strlen(loader1_name) + + strlen(sel) + strlen(loader2_name) + strlen(failed_type_name) + 1; + char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen); + jio_snprintf(buf, buflen, msg, field_name, loader1_name, sel, loader2_name, + failed_type_name); + THROW_MSG(vmSymbols::java_lang_LinkageError(), buf); + } +} + +methodHandle LinkResolver::resolve_method(const LinkInfo& link_info, + bool require_methodref, TRAPS) { Handle nested_exception; + KlassHandle resolved_klass = link_info.resolved_klass(); // 1. check if methodref required, that resolved_klass is not interfacemethodref if (require_methodref && resolved_klass->is_interface()) { @@ -552,20 +675,19 @@ char buf[200]; jio_snprintf(buf, sizeof(buf), "Found interface %s, but class was expected", resolved_klass()->external_name()); - THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } // 2. lookup method in resolved klass and its super klasses - lookup_method_in_klasses(resolved_method, resolved_klass, method_name, method_signature, true, false, CHECK); + methodHandle resolved_method = lookup_method_in_klasses(link_info, true, false, CHECK_NULL); if (resolved_method.is_null() && !resolved_klass->oop_is_array()) { // not found in the class hierarchy // 3. lookup method in all the interfaces implemented by the resolved klass - lookup_method_in_interfaces(resolved_method, resolved_klass, method_name, method_signature, CHECK); + resolved_method = lookup_method_in_interfaces(link_info, CHECK_NULL); if (resolved_method.is_null()) { // JSR 292: see if this is an implicitly generated method MethodHandle.linkToVirtual(*...), etc - lookup_polymorphic_method(resolved_method, resolved_klass, method_name, method_signature, - current_klass, (Handle*)NULL, (Handle*)NULL, THREAD); + resolved_method = lookup_polymorphic_method(link_info, (Handle*)NULL, (Handle*)NULL, THREAD); if (HAS_PENDING_EXCEPTION) { nested_exception = Handle(THREAD, PENDING_EXCEPTION); CLEAR_PENDING_EXCEPTION; @@ -576,15 +698,16 @@ if (resolved_method.is_null()) { // 4. method lookup failed ResourceMark rm(THREAD); - THROW_MSG_CAUSE(vmSymbols::java_lang_NoSuchMethodError(), + THROW_MSG_CAUSE_(vmSymbols::java_lang_NoSuchMethodError(), Method::name_and_sig_as_C_string(resolved_klass(), - method_name, - method_signature), - nested_exception); + link_info.name(), + link_info.signature()), + nested_exception, NULL); } // 5. access checks, access checking may be turned off when calling from within the VM. - if (check_access) { + KlassHandle current_klass = link_info.current_klass(); + if (link_info.check_access()) { assert(current_klass.not_null() , "current_klass should not be null"); // check if method can be accessed by the referring class @@ -592,76 +715,50 @@ resolved_klass, KlassHandle(THREAD, resolved_method->method_holder()), resolved_method, - CHECK); + CHECK_NULL); // check loader constraints - Handle loader (THREAD, InstanceKlass::cast(current_klass())->class_loader()); - Handle class_loader (THREAD, resolved_method->method_holder()->class_loader()); - { - ResourceMark rm(THREAD); - Symbol* failed_type_symbol = - SystemDictionary::check_signature_loaders(method_signature, loader, - class_loader, true, CHECK); - if (failed_type_symbol != NULL) { - const char* msg = "loader constraint violation: when resolving method" - " \"%s\" the class loader (instance of %s) of the current class, %s," - " and the class loader (instance of %s) for the method's defining class, %s, have" - " different Class objects for the type %s used in the signature"; - char* sig = Method::name_and_sig_as_C_string(resolved_klass(),method_name,method_signature); - const char* loader1 = SystemDictionary::loader_name(loader()); - char* current = InstanceKlass::cast(current_klass())->name()->as_C_string(); - const char* loader2 = SystemDictionary::loader_name(class_loader()); - char* target = InstanceKlass::cast(resolved_method->method_holder()) - ->name()->as_C_string(); - char* failed_type_name = failed_type_symbol->as_C_string(); - size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1) + - strlen(current) + strlen(loader2) + strlen(target) + - strlen(failed_type_name) + 1; - char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen); - jio_snprintf(buf, buflen, msg, sig, loader1, current, loader2, - target, failed_type_name); - THROW_MSG(vmSymbols::java_lang_LinkageError(), buf); - } - } + check_method_loader_constraints(link_info, resolved_method, "method", CHECK_NULL); } + + return resolved_method; } -void LinkResolver::resolve_interface_method(methodHandle& resolved_method, - KlassHandle resolved_klass, - Symbol* method_name, - Symbol* method_signature, - KlassHandle current_klass, - bool check_access, - bool nostatics, TRAPS) { +methodHandle LinkResolver::resolve_interface_method(const LinkInfo& link_info, + bool nostatics, TRAPS) { + + KlassHandle resolved_klass = link_info.resolved_klass(); // check if klass is interface if (!resolved_klass->is_interface()) { ResourceMark rm(THREAD); char buf[200]; jio_snprintf(buf, sizeof(buf), "Found class %s, but interface was expected", resolved_klass()->external_name()); - THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } // lookup method in this interface or its super, java.lang.Object // JDK8: also look for static methods - lookup_method_in_klasses(resolved_method, resolved_klass, method_name, method_signature, false, true, CHECK); + methodHandle resolved_method = lookup_method_in_klasses(link_info, false, true, CHECK_NULL); if (resolved_method.is_null() && !resolved_klass->oop_is_array()) { // lookup method in all the super-interfaces - lookup_method_in_interfaces(resolved_method, resolved_klass, method_name, method_signature, CHECK); + resolved_method = lookup_method_in_interfaces(link_info, CHECK_NULL); } if (resolved_method.is_null()) { // no method found ResourceMark rm(THREAD); - THROW_MSG(vmSymbols::java_lang_NoSuchMethodError(), - Method::name_and_sig_as_C_string(resolved_klass(), - method_name, - method_signature)); + THROW_MSG_NULL(vmSymbols::java_lang_NoSuchMethodError(), + Method::name_and_sig_as_C_string(resolved_klass(), + link_info.name(), + link_info.signature())); } - if (check_access) { + if (link_info.check_access()) { // JDK8 adds non-public interface methods, and accessability check requirement + KlassHandle current_klass = link_info.current_klass(); + assert(current_klass.not_null() , "current_klass should not be null"); // check if method can be accessed by the referring class @@ -669,38 +766,9 @@ resolved_klass, KlassHandle(THREAD, resolved_method->method_holder()), resolved_method, - CHECK); + CHECK_NULL); - HandleMark hm(THREAD); - Handle loader (THREAD, InstanceKlass::cast(current_klass())->class_loader()); - Handle class_loader (THREAD, resolved_method->method_holder()->class_loader()); - { - ResourceMark rm(THREAD); - Symbol* failed_type_symbol = - SystemDictionary::check_signature_loaders(method_signature, loader, - class_loader, true, CHECK); - if (failed_type_symbol != NULL) { - const char* msg = "loader constraint violation: when resolving " - "interface method \"%s\" the class loader (instance of %s) of the " - "current class, %s, and the class loader (instance of %s) for " - "the method's defining class, %s, have different Class objects for the type %s " - "used in the signature"; - char* sig = Method::name_and_sig_as_C_string(resolved_klass(),method_name,method_signature); - const char* loader1 = SystemDictionary::loader_name(loader()); - char* current = InstanceKlass::cast(current_klass())->name()->as_C_string(); - const char* loader2 = SystemDictionary::loader_name(class_loader()); - char* target = InstanceKlass::cast(resolved_method->method_holder()) - ->name()->as_C_string(); - char* failed_type_name = failed_type_symbol->as_C_string(); - size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1) + - strlen(current) + strlen(loader2) + strlen(target) + - strlen(failed_type_name) + 1; - char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen); - jio_snprintf(buf, buflen, msg, sig, loader1, current, loader2, - target, failed_type_name); - THROW_MSG(vmSymbols::java_lang_LinkageError(), buf); - } - } + check_method_loader_constraints(link_info, resolved_method, "interface method", CHECK_NULL); } if (nostatics && resolved_method->is_static()) { @@ -709,28 +777,16 @@ jio_snprintf(buf, sizeof(buf), "Expected instance not static method %s", Method::name_and_sig_as_C_string(resolved_klass(), resolved_method->name(), resolved_method->signature())); - THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } if (TraceItables && Verbose) { - ResourceMark rm(THREAD); - tty->print("invokeinterface resolved method: caller-class:%s, compile-time-class:%s, method:%s, method_holder:%s, access_flags: ", - (current_klass.is_null() ? "" : current_klass->internal_name()), - (resolved_klass.is_null() ? "" : resolved_klass->internal_name()), - Method::name_and_sig_as_C_string(resolved_klass(), - resolved_method->name(), - resolved_method->signature()), - resolved_method->method_holder()->internal_name() - ); - resolved_method->access_flags().print_on(tty); - if (resolved_method->is_default_method()) { - tty->print("default "); - } - if (resolved_method->is_overpass()) { - tty->print("overpass"); - } + trace_method_resolution("invokeinterface resolved method: caller-class", + link_info.current_klass(), resolved_klass, resolved_method); tty->cr(); } + + return resolved_method; } //------------------------------------------------------------------------------------------------------------------------ @@ -739,7 +795,7 @@ void LinkResolver::check_field_accessability(KlassHandle ref_klass, KlassHandle resolved_klass, KlassHandle sel_klass, - fieldDescriptor& fd, + const fieldDescriptor& fd, TRAPS) { if (!Reflection::verify_field_access(ref_klass(), resolved_klass(), @@ -759,30 +815,27 @@ } } -void LinkResolver::resolve_field_access(fieldDescriptor& result, constantPoolHandle pool, int index, Bytecodes::Code byte, TRAPS) { - // Load these early in case the resolve of the containing klass fails - Symbol* field = pool->name_ref_at(index); - Symbol* sig = pool->signature_ref_at(index); - - // resolve specified klass - KlassHandle resolved_klass; - resolve_klass(resolved_klass, pool, index, CHECK); - - KlassHandle current_klass(THREAD, pool->pool_holder()); - resolve_field(result, resolved_klass, field, sig, current_klass, byte, true, true, CHECK); +void LinkResolver::resolve_field_access(fieldDescriptor& fd, constantPoolHandle pool, int index, Bytecodes::Code byte, TRAPS) { + LinkInfo link_info(pool, index, CHECK); + resolve_field(fd, link_info, byte, true, CHECK); } -void LinkResolver::resolve_field(fieldDescriptor& fd, KlassHandle resolved_klass, Symbol* field, Symbol* sig, - KlassHandle current_klass, Bytecodes::Code byte, bool check_access, bool initialize_class, +void LinkResolver::resolve_field(fieldDescriptor& fd, + const LinkInfo& link_info, + Bytecodes::Code byte, bool initialize_class, TRAPS) { assert(byte == Bytecodes::_getstatic || byte == Bytecodes::_putstatic || byte == Bytecodes::_getfield || byte == Bytecodes::_putfield || byte == Bytecodes::_nofast_getfield || byte == Bytecodes::_nofast_putfield || - (byte == Bytecodes::_nop && !check_access), "bad field access bytecode"); + (byte == Bytecodes::_nop && !link_info.check_access()), "bad field access bytecode"); bool is_static = (byte == Bytecodes::_getstatic || byte == Bytecodes::_putstatic); bool is_put = (byte == Bytecodes::_putfield || byte == Bytecodes::_putstatic || byte == Bytecodes::_nofast_putfield); // Check if there's a resolved klass containing the field + KlassHandle resolved_klass = link_info.resolved_klass(); + Symbol* field = link_info.name(); + Symbol* sig = link_info.signature(); + if (resolved_klass.is_null()) { ResourceMark rm(THREAD); THROW_MSG(vmSymbols::java_lang_NoSuchFieldError(), field->as_C_string()); @@ -796,11 +849,12 @@ THROW_MSG(vmSymbols::java_lang_NoSuchFieldError(), field->as_C_string()); } - if (!check_access) + if (!link_info.check_access()) // Access checking may be turned off when calling from within the VM. return; // check access + KlassHandle current_klass = link_info.current_klass(); check_field_accessability(current_klass, resolved_klass, sel_klass, fd, CHECK); // check for errors @@ -827,34 +881,7 @@ } if (sel_klass() != current_klass()) { - HandleMark hm(THREAD); - Handle ref_loader (THREAD, InstanceKlass::cast(current_klass())->class_loader()); - Handle sel_loader (THREAD, InstanceKlass::cast(sel_klass())->class_loader()); - { - ResourceMark rm(THREAD); - Symbol* failed_type_symbol = - SystemDictionary::check_signature_loaders(sig, - ref_loader, sel_loader, - false, - CHECK); - if (failed_type_symbol != NULL) { - const char* msg = "loader constraint violation: when resolving field" - " \"%s\" the class loader (instance of %s) of the referring class, " - "%s, and the class loader (instance of %s) for the field's resolved " - "type, %s, have different Class objects for that type"; - char* field_name = field->as_C_string(); - const char* loader1 = SystemDictionary::loader_name(ref_loader()); - char* sel = InstanceKlass::cast(sel_klass())->name()->as_C_string(); - const char* loader2 = SystemDictionary::loader_name(sel_loader()); - char* failed_type_name = failed_type_symbol->as_C_string(); - size_t buflen = strlen(msg) + strlen(field_name) + strlen(loader1) + - strlen(sel) + strlen(loader2) + strlen(failed_type_name) + 1; - char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen); - jio_snprintf(buf, buflen, msg, field_name, loader1, sel, loader2, - failed_type_name); - THROW_MSG(vmSymbols::java_lang_LinkageError(), buf); - } - } + check_field_loader_constraints(field, sig, current_klass, sel_klass, CHECK); } // return information. note that the klass is set to the actual klass containing the @@ -873,32 +900,38 @@ // recv_klass the receiver klass -void LinkResolver::resolve_static_call(CallInfo& result, KlassHandle& resolved_klass, Symbol* method_name, - Symbol* method_signature, KlassHandle current_klass, - bool check_access, bool initialize_class, TRAPS) { - methodHandle resolved_method; - linktime_resolve_static_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK); - resolved_klass = KlassHandle(THREAD, resolved_method->method_holder()); +void LinkResolver::resolve_static_call(CallInfo& result, + const LinkInfo& link_info, + bool initialize_class, TRAPS) { + methodHandle resolved_method = linktime_resolve_static_method(link_info, CHECK); + // The resolved class can change as a result of this resolution. + KlassHandle resolved_klass = KlassHandle(THREAD, resolved_method->method_holder()); + + Method* save_resolved_method = resolved_method(); // Initialize klass (this should only happen if everything is ok) if (initialize_class && resolved_klass->should_be_initialized()) { resolved_klass->initialize(CHECK); - linktime_resolve_static_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK); + // Use updated LinkInfo (to reresolve with resolved_klass as method_holder?) + LinkInfo new_info(resolved_klass, link_info.name(), link_info.signature(), + link_info.current_klass(), link_info.check_access()); + resolved_method = linktime_resolve_static_method(new_info, CHECK); } + assert(save_resolved_method == resolved_method(), "does this change?"); // setup result result.set_static(resolved_klass, resolved_method, CHECK); } // throws linktime exceptions -void LinkResolver::linktime_resolve_static_method(methodHandle& resolved_method, KlassHandle resolved_klass, - Symbol* method_name, Symbol* method_signature, - KlassHandle current_klass, bool check_access, TRAPS) { +methodHandle LinkResolver::linktime_resolve_static_method(const LinkInfo& link_info, TRAPS) { + KlassHandle resolved_klass = link_info.resolved_klass(); + methodHandle resolved_method; if (!resolved_klass->is_interface()) { - resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, false, CHECK); + resolved_method = resolve_method(link_info, /*require_methodref*/false, CHECK_NULL); } else { - resolve_interface_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, false, CHECK); + resolved_method = resolve_interface_method(link_info, /*nostatics*/false, CHECK_NULL); } assert(resolved_method->name() != vmSymbols::class_initializer_name(), "should have been checked in verifier"); @@ -909,22 +942,25 @@ jio_snprintf(buf, sizeof(buf), "Expected static method %s", Method::name_and_sig_as_C_string(resolved_klass(), resolved_method->name(), resolved_method->signature())); - THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } + return resolved_method; } -void LinkResolver::resolve_special_call(CallInfo& result, KlassHandle resolved_klass, Symbol* method_name, - Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS) { - methodHandle resolved_method; - linktime_resolve_special_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK); - runtime_resolve_special_method(result, resolved_method, resolved_klass, current_klass, check_access, CHECK); +void LinkResolver::resolve_special_call(CallInfo& result, + const LinkInfo& link_info, + TRAPS) { + methodHandle resolved_method = linktime_resolve_special_method(link_info, CHECK); + runtime_resolve_special_method(result, resolved_method, + link_info.resolved_klass(), + link_info.current_klass(), + link_info.check_access(), CHECK); } // throws linktime exceptions -void LinkResolver::linktime_resolve_special_method(methodHandle& resolved_method, KlassHandle resolved_klass, - Symbol* method_name, Symbol* method_signature, - KlassHandle current_klass, bool check_access, TRAPS) { +methodHandle LinkResolver::linktime_resolve_special_method(const LinkInfo& link_info, + TRAPS) { // Invokespecial is called for multiple special reasons: // @@ -932,11 +968,13 @@ // superclass.method, which can also resolve to a default method // and the selected method is recalculated relative to the direct superclass // superinterface.method, which explicitly does not check shadowing + KlassHandle resolved_klass = link_info.resolved_klass(); + methodHandle resolved_method; if (!resolved_klass->is_interface()) { - resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, false, CHECK); + resolved_method = resolve_method(link_info, /*require_methodref*/false, CHECK_NULL); } else { - resolve_interface_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, true, CHECK); + resolved_method = resolve_interface_method(link_info, /*nostatics*/true, CHECK_NULL); } // check if method name is , that it is found in same klass as static type @@ -951,10 +989,11 @@ resolved_method->name()->as_C_string(), resolved_method->signature()->as_C_string() ); - return; + return NULL; } // check if invokespecial's interface method reference is in an indirect superinterface + KlassHandle current_klass = link_info.current_klass(); if (!current_klass.is_null() && resolved_klass->is_interface()) { Klass *klass_to_check = !InstanceKlass::cast(current_klass())->is_anonymous() ? current_klass() : @@ -973,7 +1012,7 @@ resolved_method->name(), resolved_method->signature()), current_klass->external_name()); - THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } } @@ -984,35 +1023,26 @@ jio_snprintf(buf, sizeof(buf), "Expecting non-static method %s", Method::name_and_sig_as_C_string(resolved_klass(), - resolved_method->name(), - resolved_method->signature())); - THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + resolved_method->name(), + resolved_method->signature())); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } if (TraceItables && Verbose) { - ResourceMark rm(THREAD); - tty->print("invokespecial resolved method: caller-class:%s, compile-time-class:%s, method:%s, method_holder:%s, access_flags: ", - (current_klass.is_null() ? "" : current_klass->internal_name()), - (resolved_klass.is_null() ? "" : resolved_klass->internal_name()), - Method::name_and_sig_as_C_string(resolved_klass(), - resolved_method->name(), - resolved_method->signature()), - resolved_method->method_holder()->internal_name() - ); - resolved_method->access_flags().print_on(tty); - if (resolved_method->is_default_method()) { - tty->print("default "); - } - if (resolved_method->is_overpass()) { - tty->print("overpass"); - } + trace_method_resolution("invokespecial resolved method: caller-class:", + current_klass, resolved_klass, resolved_method); tty->cr(); } + + return resolved_method; } // throws runtime exceptions -void LinkResolver::runtime_resolve_special_method(CallInfo& result, methodHandle resolved_method, KlassHandle resolved_klass, - KlassHandle current_klass, bool check_access, TRAPS) { +void LinkResolver::runtime_resolve_special_method(CallInfo& result, + const methodHandle& resolved_method, + KlassHandle resolved_klass, + KlassHandle current_klass, + bool check_access, TRAPS) { // resolved method is selected method unless we have an old-style lookup // for a superclass method @@ -1037,7 +1067,7 @@ resolved_method->name() != vmSymbols::object_initializer_name()) { // Lookup super method KlassHandle super_klass(THREAD, current_klass->super()); - lookup_instance_method_in_klasses(sel_method, super_klass, + sel_method = lookup_instance_method_in_klasses(super_klass, resolved_method->name(), resolved_method->signature(), CHECK); // check if found @@ -1066,26 +1096,13 @@ ResourceMark rm(THREAD); THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), Method::name_and_sig_as_C_string(resolved_klass(), - sel_method->name(), - sel_method->signature())); + sel_method->name(), + sel_method->signature())); } if (TraceItables && Verbose) { - ResourceMark rm(THREAD); - tty->print("invokespecial selected method: resolved-class:%s, method:%s, method_holder:%s, access_flags: ", - (resolved_klass.is_null() ? "" : resolved_klass->internal_name()), - Method::name_and_sig_as_C_string(resolved_klass(), - sel_method->name(), - sel_method->signature()), - sel_method->method_holder()->internal_name() - ); - sel_method->access_flags().print_on(tty); - if (sel_method->is_default_method()) { - tty->print("default "); - } - if (sel_method->is_overpass()) { - tty->print("overpass"); - } + trace_method_resolution("invokespecial selected method: resolved-class:", + resolved_klass, resolved_klass, sel_method); tty->cr(); } @@ -1093,25 +1110,29 @@ result.set_static(resolved_klass, sel_method, CHECK); } -void LinkResolver::resolve_virtual_call(CallInfo& result, Handle recv, KlassHandle receiver_klass, KlassHandle resolved_klass, - Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, - bool check_access, bool check_null_and_abstract, TRAPS) { - methodHandle resolved_method; - linktime_resolve_virtual_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK); - runtime_resolve_virtual_method(result, resolved_method, resolved_klass, recv, receiver_klass, check_null_and_abstract, CHECK); +void LinkResolver::resolve_virtual_call(CallInfo& result, Handle recv, KlassHandle receiver_klass, + const LinkInfo& link_info, + bool check_null_and_abstract, TRAPS) { + methodHandle resolved_method = linktime_resolve_virtual_method(link_info, CHECK); + runtime_resolve_virtual_method(result, resolved_method, + link_info.resolved_klass(), + recv, receiver_klass, + check_null_and_abstract, CHECK); } // throws linktime exceptions -void LinkResolver::linktime_resolve_virtual_method(methodHandle &resolved_method, KlassHandle resolved_klass, - Symbol* method_name, Symbol* method_signature, - KlassHandle current_klass, bool check_access, TRAPS) { +methodHandle LinkResolver::linktime_resolve_virtual_method(const LinkInfo& link_info, + TRAPS) { // normal method resolution - resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, true, CHECK); + methodHandle resolved_method = resolve_method(link_info, /*require_methodref*/true, CHECK_NULL); assert(resolved_method->name() != vmSymbols::object_initializer_name(), "should have been checked in verifier"); assert(resolved_method->name() != vmSymbols::class_initializer_name (), "should have been checked in verifier"); // check if private interface method + KlassHandle resolved_klass = link_info.resolved_klass(); + KlassHandle current_klass = link_info.current_klass(); + if (resolved_klass->is_interface() && resolved_method->is_private()) { ResourceMark rm(THREAD); char buf[200]; @@ -1120,7 +1141,7 @@ resolved_method->name(), resolved_method->signature()), (current_klass.is_null() ? "" : current_klass->internal_name())); - THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } // check if not static @@ -1130,33 +1151,21 @@ jio_snprintf(buf, sizeof(buf), "Expecting non-static method %s", Method::name_and_sig_as_C_string(resolved_klass(), resolved_method->name(), resolved_method->signature())); - THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } if (PrintVtables && Verbose) { - ResourceMark rm(THREAD); - tty->print("invokevirtual resolved method: caller-class:%s, compile-time-class:%s, method:%s, method_holder:%s, access_flags: ", - (current_klass.is_null() ? "" : current_klass->internal_name()), - (resolved_klass.is_null() ? "" : resolved_klass->internal_name()), - Method::name_and_sig_as_C_string(resolved_klass(), - resolved_method->name(), - resolved_method->signature()), - resolved_method->method_holder()->internal_name() - ); - resolved_method->access_flags().print_on(tty); - if (resolved_method->is_default_method()) { - tty->print("default "); - } - if (resolved_method->is_overpass()) { - tty->print("overpass"); - } + trace_method_resolution("invokevirtual resolved method: caller-class:", + current_klass, resolved_klass, resolved_method); tty->cr(); } + + return resolved_method; } // throws runtime exceptions void LinkResolver::runtime_resolve_virtual_method(CallInfo& result, - methodHandle resolved_method, + const methodHandle& resolved_method, KlassHandle resolved_klass, Handle recv, KlassHandle recv_klass, @@ -1227,50 +1236,40 @@ } if (PrintVtables && Verbose) { - ResourceMark rm(THREAD); - tty->print("invokevirtual selected method: receiver-class:%s, resolved-class:%s, method:%s, method_holder:%s, vtable_index:%d, access_flags: ", - (recv_klass.is_null() ? "" : recv_klass->internal_name()), - (resolved_klass.is_null() ? "" : resolved_klass->internal_name()), - Method::name_and_sig_as_C_string(resolved_klass(), - resolved_method->name(), - resolved_method->signature()), - selected_method->method_holder()->internal_name(), - vtable_index - ); - selected_method->access_flags().print_on(tty); - if (selected_method->is_default_method()) { - tty->print("default "); - } - if (selected_method->is_overpass()) { - tty->print("overpass"); - } - tty->cr(); + trace_method_resolution("invokevirtual selected method: receiver-class:", + recv_klass, resolved_klass, selected_method); + tty->print_cr("vtable_index:%d", vtable_index); } // setup result result.set_virtual(resolved_klass, recv_klass, resolved_method, selected_method, vtable_index, CHECK); } -void LinkResolver::resolve_interface_call(CallInfo& result, Handle recv, KlassHandle recv_klass, KlassHandle resolved_klass, - Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, - bool check_access, bool check_null_and_abstract, TRAPS) { - methodHandle resolved_method; - linktime_resolve_interface_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK); - runtime_resolve_interface_method(result, resolved_method, resolved_klass, recv, recv_klass, check_null_and_abstract, CHECK); +void LinkResolver::resolve_interface_call(CallInfo& result, Handle recv, KlassHandle recv_klass, + const LinkInfo& link_info, + bool check_null_and_abstract, TRAPS) { + // throws linktime exceptions + methodHandle resolved_method = linktime_resolve_interface_method(link_info, CHECK); + runtime_resolve_interface_method(result, resolved_method,link_info.resolved_klass(), + recv, recv_klass, check_null_and_abstract, CHECK); } -// throws linktime exceptions -void LinkResolver::linktime_resolve_interface_method(methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, - Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS) { +methodHandle LinkResolver::linktime_resolve_interface_method(const LinkInfo& link_info, + TRAPS) { // normal interface method resolution - resolve_interface_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, true, CHECK); - + methodHandle resolved_method = resolve_interface_method(link_info, true, CHECK_NULL); assert(resolved_method->name() != vmSymbols::object_initializer_name(), "should have been checked in verifier"); assert(resolved_method->name() != vmSymbols::class_initializer_name (), "should have been checked in verifier"); + + return resolved_method; } // throws runtime exceptions -void LinkResolver::runtime_resolve_interface_method(CallInfo& result, methodHandle resolved_method, KlassHandle resolved_klass, - Handle recv, KlassHandle recv_klass, bool check_null_and_abstract, TRAPS) { +void LinkResolver::runtime_resolve_interface_method(CallInfo& result, + const methodHandle& resolved_method, + KlassHandle resolved_klass, + Handle recv, + KlassHandle recv_klass, + bool check_null_and_abstract, TRAPS) { // check if receiver exists if (check_null_and_abstract && recv.is_null()) { THROW(vmSymbols::java_lang_NullPointerException()); @@ -1298,12 +1297,11 @@ } // do lookup based on receiver klass - methodHandle sel_method; // This search must match the linktime preparation search for itable initialization // to correctly enforce loader constraints for interface method inheritance - lookup_instance_method_in_klasses(sel_method, recv_klass, - resolved_method->name(), - resolved_method->signature(), CHECK); + methodHandle sel_method = lookup_instance_method_in_klasses(recv_klass, + resolved_method->name(), + resolved_method->signature(), CHECK); if (sel_method.is_null() && !check_null_and_abstract) { // In theory this is a harmless placeholder value, but // in practice leaving in null affects the nsk default method tests. @@ -1314,9 +1312,9 @@ if (sel_method.is_null()) { ResourceMark rm(THREAD); THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), - Method::name_and_sig_as_C_string(recv_klass(), - resolved_method->name(), - resolved_method->signature())); + Method::name_and_sig_as_C_string(recv_klass(), + resolved_method->name(), + resolved_method->signature())); } // check access // Throw Illegal Access Error if sel_method is not public. @@ -1337,22 +1335,8 @@ } if (TraceItables && Verbose) { - ResourceMark rm(THREAD); - tty->print("invokeinterface selected method: receiver-class:%s, resolved-class:%s, method:%s, method_holder:%s, access_flags: ", - (recv_klass.is_null() ? "" : recv_klass->internal_name()), - (resolved_klass.is_null() ? "" : resolved_klass->internal_name()), - Method::name_and_sig_as_C_string(resolved_klass(), - resolved_method->name(), - resolved_method->signature()), - sel_method->method_holder()->internal_name() - ); - sel_method->access_flags().print_on(tty); - if (sel_method->is_default_method()) { - tty->print("default "); - } - if (sel_method->is_overpass()) { - tty->print("overpass"); - } + trace_method_resolution("invokeinterface selected method: receiver-class", + recv_klass, resolved_klass, sel_method); tty->cr(); } // setup result @@ -1368,14 +1352,9 @@ methodHandle LinkResolver::linktime_resolve_interface_method_or_null( - KlassHandle resolved_klass, - Symbol* method_name, - Symbol* method_signature, - KlassHandle current_klass, - bool check_access) { + const LinkInfo& link_info) { EXCEPTION_MARK; - methodHandle method_result; - linktime_resolve_interface_method(method_result, resolved_klass, method_name, method_signature, current_klass, check_access, THREAD); + methodHandle method_result = linktime_resolve_interface_method(link_info, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return methodHandle(); @@ -1385,14 +1364,9 @@ } methodHandle LinkResolver::linktime_resolve_virtual_method_or_null( - KlassHandle resolved_klass, - Symbol* method_name, - Symbol* method_signature, - KlassHandle current_klass, - bool check_access) { + const LinkInfo& link_info) { EXCEPTION_MARK; - methodHandle method_result; - linktime_resolve_virtual_method(method_result, resolved_klass, method_name, method_signature, current_klass, check_access, THREAD); + methodHandle method_result = linktime_resolve_virtual_method(link_info, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return methodHandle(); @@ -1403,14 +1377,10 @@ methodHandle LinkResolver::resolve_virtual_call_or_null( KlassHandle receiver_klass, - KlassHandle resolved_klass, - Symbol* name, - Symbol* signature, - KlassHandle current_klass, - bool check_access) { + const LinkInfo& link_info) { EXCEPTION_MARK; CallInfo info; - resolve_virtual_call(info, Handle(), receiver_klass, resolved_klass, name, signature, current_klass, check_access, false, THREAD); + resolve_virtual_call(info, Handle(), receiver_klass, link_info, false, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return methodHandle(); @@ -1420,14 +1390,10 @@ methodHandle LinkResolver::resolve_interface_call_or_null( KlassHandle receiver_klass, - KlassHandle resolved_klass, - Symbol* name, - Symbol* signature, - KlassHandle current_klass, - bool check_access) { + const LinkInfo& link_info) { EXCEPTION_MARK; CallInfo info; - resolve_interface_call(info, Handle(), receiver_klass, resolved_klass, name, signature, current_klass, check_access, false, THREAD); + resolve_interface_call(info, Handle(), receiver_klass, link_info, false, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return methodHandle(); @@ -1435,15 +1401,12 @@ return info.selected_method(); } -int LinkResolver::resolve_virtual_vtable_index( - KlassHandle receiver_klass, - KlassHandle resolved_klass, - Symbol* name, - Symbol* signature, - KlassHandle current_klass) { +int LinkResolver::resolve_virtual_vtable_index(KlassHandle receiver_klass, + const LinkInfo& link_info) { EXCEPTION_MARK; CallInfo info; - resolve_virtual_call(info, Handle(), receiver_klass, resolved_klass, name, signature, current_klass, true, false, THREAD); + resolve_virtual_call(info, Handle(), receiver_klass, link_info, + /*check_null_or_abstract*/false, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return Method::invalid_vtable_index; @@ -1451,15 +1414,10 @@ return info.vtable_index(); } -methodHandle LinkResolver::resolve_static_call_or_null( - KlassHandle resolved_klass, - Symbol* name, - Symbol* signature, - KlassHandle current_klass, - bool check_access) { +methodHandle LinkResolver::resolve_static_call_or_null(const LinkInfo& link_info) { EXCEPTION_MARK; CallInfo info; - resolve_static_call(info, resolved_klass, name, signature, current_klass, check_access, false, THREAD); + resolve_static_call(info, link_info, /*initialize_class*/false, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return methodHandle(); @@ -1467,15 +1425,10 @@ return info.selected_method(); } -methodHandle LinkResolver::resolve_special_call_or_null( - KlassHandle resolved_klass, - Symbol* name, - Symbol* signature, - KlassHandle current_klass, - bool check_access) { +methodHandle LinkResolver::resolve_special_call_or_null(const LinkInfo& link_info) { EXCEPTION_MARK; CallInfo info; - resolve_special_call(info, resolved_klass, name, signature, current_klass, check_access, THREAD); + resolve_special_call(info, link_info, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return methodHandle(); @@ -1500,35 +1453,15 @@ return; } -void LinkResolver::resolve_pool(KlassHandle& resolved_klass, Symbol*& method_name, Symbol*& method_signature, - KlassHandle& current_klass, constantPoolHandle pool, int index, TRAPS) { - // resolve klass - resolve_klass(resolved_klass, pool, index, CHECK); - - // Get name, signature, and static klass - method_name = pool->name_ref_at(index); - method_signature = pool->signature_ref_at(index); - current_klass = KlassHandle(THREAD, pool->pool_holder()); -} - - void LinkResolver::resolve_invokestatic(CallInfo& result, constantPoolHandle pool, int index, TRAPS) { - KlassHandle resolved_klass; - Symbol* method_name = NULL; - Symbol* method_signature = NULL; - KlassHandle current_klass; - resolve_pool(resolved_klass, method_name, method_signature, current_klass, pool, index, CHECK); - resolve_static_call(result, resolved_klass, method_name, method_signature, current_klass, true, true, CHECK); + LinkInfo link_info(pool, index, CHECK); + resolve_static_call(result, link_info, /*initialize_class*/true, CHECK); } void LinkResolver::resolve_invokespecial(CallInfo& result, constantPoolHandle pool, int index, TRAPS) { - KlassHandle resolved_klass; - Symbol* method_name = NULL; - Symbol* method_signature = NULL; - KlassHandle current_klass; - resolve_pool(resolved_klass, method_name, method_signature, current_klass, pool, index, CHECK); - resolve_special_call(result, resolved_klass, method_name, method_signature, current_klass, true, CHECK); + LinkInfo link_info(pool, index, CHECK); + resolve_special_call(result, link_info, CHECK); } @@ -1536,54 +1469,40 @@ constantPoolHandle pool, int index, TRAPS) { - KlassHandle resolved_klass; - Symbol* method_name = NULL; - Symbol* method_signature = NULL; - KlassHandle current_klass; - resolve_pool(resolved_klass, method_name, method_signature, current_klass, pool, index, CHECK); + LinkInfo link_info(pool, index, CHECK); KlassHandle recvrKlass (THREAD, recv.is_null() ? (Klass*)NULL : recv->klass()); - resolve_virtual_call(result, recv, recvrKlass, resolved_klass, method_name, method_signature, current_klass, true, true, CHECK); + resolve_virtual_call(result, recv, recvrKlass, link_info, /*check_null_or_abstract*/true, CHECK); } void LinkResolver::resolve_invokeinterface(CallInfo& result, Handle recv, constantPoolHandle pool, int index, TRAPS) { - KlassHandle resolved_klass; - Symbol* method_name = NULL; - Symbol* method_signature = NULL; - KlassHandle current_klass; - resolve_pool(resolved_klass, method_name, method_signature, current_klass, pool, index, CHECK); + LinkInfo link_info(pool, index, CHECK); KlassHandle recvrKlass (THREAD, recv.is_null() ? (Klass*)NULL : recv->klass()); - resolve_interface_call(result, recv, recvrKlass, resolved_klass, method_name, method_signature, current_klass, true, true, CHECK); + resolve_interface_call(result, recv, recvrKlass, link_info, true, CHECK); } void LinkResolver::resolve_invokehandle(CallInfo& result, constantPoolHandle pool, int index, TRAPS) { // This guy is reached from InterpreterRuntime::resolve_invokehandle. - KlassHandle resolved_klass; - Symbol* method_name = NULL; - Symbol* method_signature = NULL; - KlassHandle current_klass; - resolve_pool(resolved_klass, method_name, method_signature, current_klass, pool, index, CHECK); + LinkInfo link_info(pool, index, CHECK); if (TraceMethodHandles) { ResourceMark rm(THREAD); - tty->print_cr("resolve_invokehandle %s %s", method_name->as_C_string(), method_signature->as_C_string()); + tty->print_cr("resolve_invokehandle %s %s", link_info.name()->as_C_string(), + link_info.signature()->as_C_string()); } - resolve_handle_call(result, resolved_klass, method_name, method_signature, current_klass, CHECK); + resolve_handle_call(result, link_info, CHECK); } -void LinkResolver::resolve_handle_call(CallInfo& result, KlassHandle resolved_klass, - Symbol* method_name, Symbol* method_signature, - KlassHandle current_klass, +void LinkResolver::resolve_handle_call(CallInfo& result, + const LinkInfo& link_info, TRAPS) { // JSR 292: this must be an implicitly generated method MethodHandle.invokeExact(*...) or similar - assert(resolved_klass() == SystemDictionary::MethodHandle_klass(), ""); - assert(MethodHandles::is_signature_polymorphic_name(method_name), ""); - methodHandle resolved_method; + assert(link_info.resolved_klass()() == SystemDictionary::MethodHandle_klass(), ""); + assert(MethodHandles::is_signature_polymorphic_name(link_info.name()), ""); Handle resolved_appendix; Handle resolved_method_type; - lookup_polymorphic_method(resolved_method, resolved_klass, - method_name, method_signature, - current_klass, &resolved_appendix, &resolved_method_type, CHECK); + methodHandle resolved_method = lookup_polymorphic_method(link_info, + &resolved_appendix, &resolved_method_type, CHECK); result.set_handle(resolved_method, resolved_appendix, resolved_method_type, CHECK); } @@ -1609,7 +1528,6 @@ } void LinkResolver::resolve_invokedynamic(CallInfo& result, constantPoolHandle pool, int index, TRAPS) { - //resolve_pool(, method_name, method_signature, current_klass, pool, index, CHECK); Symbol* method_name = pool->name_ref_at(index); Symbol* method_signature = pool->signature_ref_at(index); KlassHandle current_klass = KlassHandle(THREAD, pool->pool_holder()); @@ -1667,19 +1585,27 @@ wrap_invokedynamic_exception(CHECK); } -//------------------------------------------------------------------------------------------------------------------------ #ifndef PRODUCT - -void CallInfo::print() { +void LinkResolver::trace_method_resolution(const char* prefix, + KlassHandle klass, + KlassHandle resolved_klass, + const methodHandle& method) { ResourceMark rm; - const char* kindstr = "unknown"; - switch (_call_kind) { - case direct_call: kindstr = "direct"; break; - case vtable_call: kindstr = "vtable"; break; - case itable_call: kindstr = "itable"; break; + tty->print("%s%s, compile-time-class:%s, method:%s, method_holder:%s, access_flags: ", + prefix, + (klass.is_null() ? "" : klass->internal_name()), + (resolved_klass.is_null() ? "" : resolved_klass->internal_name()), + Method::name_and_sig_as_C_string(resolved_klass(), + method->name(), + method->signature()), + method->method_holder()->internal_name() + ); + method->access_flags().print_on(tty); + if (method->is_default_method()) { + tty->print("default "); } - tty->print_cr("Call %s@%d %s", kindstr, _call_index, - _resolved_method.is_null() ? "(none)" : _resolved_method->name_and_sig_as_C_string()); + if (method->is_overpass()) { + tty->print("overpass "); + } } - -#endif +#endif // PRODUCT diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/interpreter/linkResolver.hpp --- a/hotspot/src/share/vm/interpreter/linkResolver.hpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/interpreter/linkResolver.hpp Mon Jun 08 11:11:47 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, 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 @@ -36,7 +36,7 @@ // that method. If the info is invalid, the link has not been resolved // successfully. -class CallInfo VALUE_OBJ_CLASS_SPEC { +class CallInfo : public StackObj { public: // Ways that a method call might be selected (or not) based on receiver type. // Note that an invokevirtual instruction might be linked with no_dispatch, @@ -58,11 +58,22 @@ Handle _resolved_appendix; // extra argument in constant pool (if CPCE::has_appendix) Handle _resolved_method_type; // MethodType (for invokedynamic and invokehandle call sites) - void set_static( KlassHandle resolved_klass, methodHandle resolved_method , TRAPS); - void set_interface(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int itable_index , TRAPS); - void set_virtual( KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index , TRAPS); - void set_handle( methodHandle resolved_method, Handle resolved_appendix, Handle resolved_method_type, TRAPS); - void set_common( KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, CallKind kind, int index, TRAPS); + void set_static(KlassHandle resolved_klass, const methodHandle& resolved_method, TRAPS); + void set_interface(KlassHandle resolved_klass, KlassHandle selected_klass, + const methodHandle& resolved_method, + const methodHandle& selected_method, + int itable_index, TRAPS); + void set_virtual(KlassHandle resolved_klass, KlassHandle selected_klass, + const methodHandle& resolved_method, + const methodHandle& selected_method, + int vtable_index, TRAPS); + void set_handle(const methodHandle& resolved_method, + Handle resolved_appendix, Handle resolved_method_type, TRAPS); + void set_common(KlassHandle resolved_klass, KlassHandle selected_klass, + const methodHandle& resolved_method, + const methodHandle& selected_method, + CallKind kind, + int index, TRAPS); friend class LinkResolver; @@ -113,6 +124,37 @@ void print() PRODUCT_RETURN; }; + +// Condensed information from constant pool to use to resolve the method or field. +// resolved_klass = specified class (i.e., static receiver class) +// current_klass = sending method holder (i.e., class containing the method +// containing the call being resolved) +class LinkInfo : public StackObj { + Symbol* _name; // extracted from JVM_CONSTANT_NameAndType + Symbol* _signature; + KlassHandle _resolved_klass; // class that the constant pool entry points to + KlassHandle _current_klass; // class that owns the constant pool + bool _check_access; + public: + LinkInfo(constantPoolHandle pool, int index, TRAPS); + // Condensed information from other call sites within the vm. + LinkInfo(KlassHandle resolved_klass, Symbol* name, Symbol* signature, + KlassHandle current_klass, bool check_access = true) : + _resolved_klass(resolved_klass), + _name(name), _signature(signature), _current_klass(current_klass), + _check_access(check_access) {} + + // accessors + Symbol* name() const { return _name; } + Symbol* signature() const { return _signature; } + KlassHandle resolved_klass() const { return _resolved_klass; } + KlassHandle current_klass() const { return _current_klass; } + bool check_access() const { return _check_access; } + char* method_string() const; + + void print() PRODUCT_RETURN; +}; + // Link information for getfield/putfield & getstatic/putstatic bytecodes // is represented using a fieldDescriptor. @@ -124,85 +166,136 @@ friend class klassItable; private: - static void lookup_method_in_klasses (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, bool checkpolymorphism, bool in_imethod_resolve, TRAPS); - static void lookup_instance_method_in_klasses (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS); - static void lookup_method_in_interfaces (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS); - static void lookup_polymorphic_method (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, - KlassHandle current_klass, Handle *appendix_result_or_null, Handle *method_type_result, TRAPS); + + static methodHandle lookup_method_in_klasses(const LinkInfo& link_info, + bool checkpolymorphism, + bool in_imethod_resolve, TRAPS); + static methodHandle lookup_method_in_interfaces(const LinkInfo& link_info, TRAPS); + static methodHandle lookup_polymorphic_method(const LinkInfo& link_info, + Handle *appendix_result_or_null, + Handle *method_type_result, TRAPS); + // Not Linktime so doesn't take LinkInfo + static methodHandle lookup_instance_method_in_klasses ( + KlassHandle klass, Symbol* name, Symbol* signature, TRAPS); - static void resolve_klass (KlassHandle& result, constantPoolHandle pool, int index, TRAPS); + // Similar loader constraint checking functions that throw + // LinkageError with descriptive message. + static void check_method_loader_constraints(const LinkInfo& link_info, + const methodHandle& resolved_method, + const char* method_type, TRAPS); + static void check_field_loader_constraints(Symbol* field, Symbol* sig, + KlassHandle current_klass, + KlassHandle sel_klass, TRAPS); - static void resolve_pool (KlassHandle& resolved_klass, Symbol*& method_name, Symbol*& method_signature, KlassHandle& current_klass, constantPoolHandle pool, int index, TRAPS); + static methodHandle resolve_interface_method(const LinkInfo& link_info, bool nostatics, TRAPS); + static methodHandle resolve_method (const LinkInfo& link_info, bool require_methodref, TRAPS); - static void resolve_interface_method(methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, bool nostatics, TRAPS); - static void resolve_method (methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, bool require_methodref, TRAPS); + static methodHandle linktime_resolve_static_method (const LinkInfo& link_info, TRAPS); + static methodHandle linktime_resolve_special_method (const LinkInfo& link_info, TRAPS); + static methodHandle linktime_resolve_virtual_method (const LinkInfo& link_info, TRAPS); + static methodHandle linktime_resolve_interface_method (const LinkInfo& link_info, TRAPS); - static void linktime_resolve_static_method (methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS); - static void linktime_resolve_special_method (methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS); - static void linktime_resolve_virtual_method (methodHandle &resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature,KlassHandle current_klass, bool check_access, TRAPS); - static void linktime_resolve_interface_method (methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS); + static void runtime_resolve_special_method (CallInfo& result, + const methodHandle& resolved_method, + KlassHandle resolved_klass, + KlassHandle current_klass, + bool check_access, TRAPS); + static void runtime_resolve_virtual_method (CallInfo& result, + const methodHandle& resolved_method, + KlassHandle resolved_klass, + Handle recv, + KlassHandle recv_klass, + bool check_null_and_abstract, TRAPS); + static void runtime_resolve_interface_method (CallInfo& result, + const methodHandle& resolved_method, + KlassHandle resolved_klass, + Handle recv, + KlassHandle recv_klass, + bool check_null_and_abstract, TRAPS); - static void runtime_resolve_special_method (CallInfo& result, methodHandle resolved_method, KlassHandle resolved_klass, KlassHandle current_klass, bool check_access, TRAPS); - static void runtime_resolve_virtual_method (CallInfo& result, methodHandle resolved_method, KlassHandle resolved_klass, Handle recv, KlassHandle recv_klass, bool check_null_and_abstract, TRAPS); - static void runtime_resolve_interface_method (CallInfo& result, methodHandle resolved_method, KlassHandle resolved_klass, Handle recv, KlassHandle recv_klass, bool check_null_and_abstract, TRAPS); + static void check_field_accessability(KlassHandle ref_klass, + KlassHandle resolved_klass, + KlassHandle sel_klass, + const fieldDescriptor& fd, TRAPS); + static void check_method_accessability(KlassHandle ref_klass, + KlassHandle resolved_klass, + KlassHandle sel_klass, + const methodHandle& sel_method, TRAPS); - static void check_field_accessability (KlassHandle ref_klass, KlassHandle resolved_klass, KlassHandle sel_klass, fieldDescriptor& fd, TRAPS); - static void check_method_accessability (KlassHandle ref_klass, KlassHandle resolved_klass, KlassHandle sel_klass, methodHandle sel_method, TRAPS); - + // runtime resolving from constant pool + static void resolve_invokestatic (CallInfo& result, + constantPoolHandle pool, int index, TRAPS); + static void resolve_invokespecial (CallInfo& result, + constantPoolHandle pool, int index, TRAPS); + static void resolve_invokevirtual (CallInfo& result, Handle recv, + constantPoolHandle pool, int index, TRAPS); + static void resolve_invokeinterface(CallInfo& result, Handle recv, + constantPoolHandle pool, int index, TRAPS); + static void resolve_invokedynamic (CallInfo& result, + constantPoolHandle pool, int index, TRAPS); + static void resolve_invokehandle (CallInfo& result, + constantPoolHandle pool, int index, TRAPS); public: // constant pool resolving static void check_klass_accessability(KlassHandle ref_klass, KlassHandle sel_klass, TRAPS); - // static resolving calls (will not run any Java code); used only from Bytecode_invoke::static_target - static void resolve_method_statically(methodHandle& method_result, KlassHandle& klass_result, - Bytecodes::Code code, constantPoolHandle pool, int index, TRAPS); + // static resolving calls (will not run any Java code); + // used only from Bytecode_invoke::static_target + static methodHandle resolve_method_statically(Bytecodes::Code code, + constantPoolHandle pool, + int index, TRAPS); - // runtime/static resolving for fields - static void resolve_field_access(fieldDescriptor& result, constantPoolHandle pool, int index, Bytecodes::Code byte, TRAPS); - static void resolve_field(fieldDescriptor& result, KlassHandle resolved_klass, Symbol* field_name, Symbol* field_signature, - KlassHandle current_klass, Bytecodes::Code access_kind, bool check_access, bool initialize_class, TRAPS); - - // source of access_kind codes: - static Bytecodes::Code field_access_kind(bool is_static, bool is_put) { - return (is_static - ? (is_put ? Bytecodes::_putstatic : Bytecodes::_getstatic) - : (is_put ? Bytecodes::_putfield : Bytecodes::_getfield )); - } + static void resolve_field_access(fieldDescriptor& result, + constantPoolHandle pool, + int index, Bytecodes::Code byte, TRAPS); + static void resolve_field(fieldDescriptor& result, const LinkInfo& link_info, + Bytecodes::Code access_kind, + bool initialize_class, TRAPS); - // runtime resolving: - // resolved_klass = specified class (i.e., static receiver class) - // current_klass = sending method holder (i.e., class containing the method containing the call being resolved) - static void resolve_static_call (CallInfo& result, KlassHandle& resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, bool initialize_klass, TRAPS); - static void resolve_special_call (CallInfo& result, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS); - static void resolve_virtual_call (CallInfo& result, Handle recv, KlassHandle recv_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, bool check_null_and_abstract, TRAPS); - static void resolve_interface_call(CallInfo& result, Handle recv, KlassHandle recv_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, bool check_null_and_abstract, TRAPS); - static void resolve_handle_call (CallInfo& result, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, TRAPS); - static void resolve_dynamic_call (CallInfo& result, Handle bootstrap_specifier, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, TRAPS); + static void resolve_static_call (CallInfo& result, + const LinkInfo& link_info, + bool initialize_klass, TRAPS); + static void resolve_special_call (CallInfo& result, + const LinkInfo& link_info, + TRAPS); + static void resolve_virtual_call (CallInfo& result, Handle recv, KlassHandle recv_klass, + const LinkInfo& link_info, + bool check_null_and_abstract, TRAPS); + static void resolve_interface_call(CallInfo& result, Handle recv, KlassHandle recv_klass, + const LinkInfo& link_info, + 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, Handle bootstrap_specifier, + Symbol* method_name, Symbol* method_signature, + KlassHandle current_klass, 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) - static methodHandle resolve_virtual_call_or_null (KlassHandle receiver_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access = true); - static methodHandle resolve_interface_call_or_null(KlassHandle receiver_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access = true); - static methodHandle resolve_static_call_or_null (KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access = true); - static methodHandle resolve_special_call_or_null (KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access = true); - static int vtable_index_of_interface_method(KlassHandle klass, methodHandle resolved_method); + // 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) + static methodHandle resolve_virtual_call_or_null (KlassHandle receiver_klass, + const LinkInfo& link_info); + static methodHandle resolve_interface_call_or_null(KlassHandle receiver_klass, + const LinkInfo& link_info); + static methodHandle resolve_static_call_or_null (const LinkInfo& link_info); + static methodHandle resolve_special_call_or_null (const LinkInfo& link_info); + + static int vtable_index_of_interface_method(KlassHandle klass, const methodHandle& resolved_method); // same as above for compile-time resolution; returns vtable_index if current_klass if linked - static int resolve_virtual_vtable_index (KlassHandle receiver_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass); + static int resolve_virtual_vtable_index (KlassHandle receiver_klass, + const LinkInfo& link_info); // static resolving for compiler (does not throw exceptions, returns null handle if unsuccessful) - static methodHandle linktime_resolve_virtual_method_or_null (KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access); - static methodHandle linktime_resolve_interface_method_or_null(KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access); + static methodHandle linktime_resolve_virtual_method_or_null (const LinkInfo& link_info); + static methodHandle linktime_resolve_interface_method_or_null(const LinkInfo& link_info); // runtime resolving from constant pool - static void resolve_invokestatic (CallInfo& result, constantPoolHandle pool, int index, TRAPS); - static void resolve_invokespecial (CallInfo& result, constantPoolHandle pool, int index, TRAPS); - static void resolve_invokevirtual (CallInfo& result, Handle recv, constantPoolHandle pool, int index, TRAPS); - static void resolve_invokeinterface(CallInfo& result, Handle recv, constantPoolHandle pool, int index, TRAPS); - static void resolve_invokedynamic (CallInfo& result, constantPoolHandle pool, int index, TRAPS); - static void resolve_invokehandle (CallInfo& result, constantPoolHandle pool, int index, TRAPS); - - static void resolve_invoke (CallInfo& result, Handle recv, constantPoolHandle pool, int index, Bytecodes::Code byte, TRAPS); + static void resolve_invoke(CallInfo& result, Handle recv, + constantPoolHandle pool, int index, + Bytecodes::Code byte, TRAPS); + private: + static void trace_method_resolution(const char* prefix, KlassHandle klass, + KlassHandle resolved_klass, + const methodHandle& method) PRODUCT_RETURN; }; - #endif // SHARE_VM_INTERPRETER_LINKRESOLVER_HPP diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/memory/metaspace.cpp --- a/hotspot/src/share/vm/memory/metaspace.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/memory/metaspace.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -614,8 +614,7 @@ Metachunk* _chunks_in_use[NumberOfInUseLists]; Metachunk* _current_chunk; - // Number of small chunks to allocate to a manager - // If class space manager, small chunks are unlimited + // Maximum number of small chunks to allocate to a SpaceManager static uint const _small_chunk_limit; // Sum of all space in allocated chunks @@ -730,6 +729,8 @@ // Block allocation and deallocation. // Allocates a block from the current chunk MetaWord* allocate(size_t word_size); + // Allocates a block from a small chunk + MetaWord* get_small_chunk_and_allocate(size_t word_size); // Helper for allocations MetaWord* allocate_work(size_t word_size); @@ -2011,9 +2012,8 @@ size_t SpaceManager::calc_chunk_size(size_t word_size) { // Decide between a small chunk and a medium chunk. Up to - // _small_chunk_limit small chunks can be allocated but - // once a medium chunk has been allocated, no more small - // chunks will be allocated. + // _small_chunk_limit small chunks can be allocated. + // After that a medium chunk is preferred. size_t chunk_word_size; if (chunks_in_use(MediumIndex) == NULL && sum_count_in_chunks_in_use(SmallIndex) < _small_chunk_limit) { @@ -2081,7 +2081,7 @@ word_size, words_used, words_left); } - // Get another chunk out of the virtual space + // Get another chunk size_t grow_chunks_by_words = calc_chunk_size(word_size); Metachunk* next = get_new_chunk(word_size, grow_chunks_by_words); @@ -2412,6 +2412,43 @@ return next; } +/* + * The policy is to allocate up to _small_chunk_limit small chunks + * after which only medium chunks are allocated. This is done to + * reduce fragmentation. In some cases, this can result in a lot + * of small chunks being allocated to the point where it's not + * possible to expand. If this happens, there may be no medium chunks + * available and OOME would be thrown. Instead of doing that, + * if the allocation request size fits in a small chunk, an attempt + * will be made to allocate a small chunk. + */ +MetaWord* SpaceManager::get_small_chunk_and_allocate(size_t word_size) { + if (word_size + Metachunk::overhead() > small_chunk_size()) { + return NULL; + } + + MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag); + MutexLockerEx cl1(expand_lock(), Mutex::_no_safepoint_check_flag); + + Metachunk* chunk = chunk_manager()->chunk_freelist_allocate(small_chunk_size()); + + MetaWord* mem = NULL; + + if (chunk != NULL) { + // Add chunk to the in-use chunk list and do an allocation from it. + // Add to this manager's list of chunks in use. + add_chunk(chunk, false); + mem = chunk->allocate(word_size); + + inc_used_metrics(word_size); + + // Track metaspace memory usage statistic. + track_metaspace_memory_usage(); + } + + return mem; +} + MetaWord* SpaceManager::allocate(size_t word_size) { MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag); @@ -3560,7 +3597,18 @@ } if (result == NULL) { - report_metadata_oome(loader_data, word_size, type, mdtype, CHECK_NULL); + SpaceManager* sm; + if (is_class_space_allocation(mdtype)) { + sm = loader_data->metaspace_non_null()->class_vsm(); + } else { + sm = loader_data->metaspace_non_null()->vsm(); + } + + result = sm->get_small_chunk_and_allocate(word_size); + + if (result == NULL) { + report_metadata_oome(loader_data, word_size, type, mdtype, CHECK_NULL); + } } // Zero initialize. diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/oops/constantPool.cpp diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/oops/constantPool.hpp diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/oops/instanceKlass.cpp --- a/hotspot/src/share/vm/oops/instanceKlass.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -622,14 +622,6 @@ if (!this_k->is_linked()) { if (!this_k->is_rewritten()) { { - // Timer includes any side effects of class verification (resolution, - // etc), but not recursive entry into verify_code(). - PerfClassTraceTime timer(ClassLoader::perf_class_verify_time(), - ClassLoader::perf_class_verify_selftime(), - ClassLoader::perf_classes_verified(), - jt->get_thread_stat()->perf_recursion_counts_addr(), - jt->get_thread_stat()->perf_timers_addr(), - PerfClassTraceTime::CLASS_VERIFY); bool verify_ok = verify_code(this_k, throw_verifyerror, THREAD); if (!verify_ok) { return false; @@ -1830,11 +1822,10 @@ // are dependent on the changes that were passed in and mark them for // deoptimization. Returns the number of nmethods found. // -int InstanceKlass::mark_dependent_nmethods(DepChange& changes) { +int nmethodBucket::mark_dependent_nmethods(nmethodBucket* deps, DepChange& changes) { assert_locked_or_safepoint(CodeCache_lock); int found = 0; - nmethodBucket* b = _dependencies; - while (b != NULL) { + for (nmethodBucket* b = deps; b != NULL; b = b->next()) { nmethod* nm = b->get_nmethod(); // since dependencies aren't removed until an nmethod becomes a zombie, // the dependency list may contain nmethods which aren't alive. @@ -1842,7 +1833,6 @@ if (TraceDependencies) { ResourceMark rm; tty->print_cr("Marked for deoptimization"); - tty->print_cr(" context = %s", this->external_name()); changes.print(); nm->print(); nm->print_dependencies(); @@ -1850,36 +1840,119 @@ nm->mark_for_deoptimization(); found++; } - b = b->next(); } return found; } +// +// Add an nmethodBucket to the list of dependencies for this nmethod. +// It's possible that an nmethod has multiple dependencies on this klass +// so a count is kept for each bucket to guarantee that creation and +// deletion of dependencies is consistent. Returns new head of the list. +// +nmethodBucket* nmethodBucket::add_dependent_nmethod(nmethodBucket* deps, nmethod* nm) { + assert_locked_or_safepoint(CodeCache_lock); + for (nmethodBucket* b = deps; b != NULL; b = b->next()) { + if (nm == b->get_nmethod()) { + b->increment(); + return deps; + } + } + return new nmethodBucket(nm, deps); +} + +// +// Decrement count of the nmethod in the dependency list and remove +// the bucket completely when the count goes to 0. This method must +// find a corresponding bucket otherwise there's a bug in the +// recording of dependencies. Returns true if the bucket is ready for reclamation. +// +bool nmethodBucket::remove_dependent_nmethod(nmethodBucket* deps, nmethod* nm) { + assert_locked_or_safepoint(CodeCache_lock); + + for (nmethodBucket* b = deps; b != NULL; b = b->next()) { + if (nm == b->get_nmethod()) { + int val = b->decrement(); + guarantee(val >= 0, err_msg("Underflow: %d", val)); + return (val == 0); + } + } +#ifdef ASSERT + tty->print_raw_cr("### can't find dependent nmethod"); + nm->print(); +#endif // ASSERT + ShouldNotReachHere(); + return false; +} + +// +// Reclaim all unused buckets. Returns new head of the list. +// +nmethodBucket* nmethodBucket::clean_dependent_nmethods(nmethodBucket* deps) { + nmethodBucket* first = deps; + nmethodBucket* last = NULL; + nmethodBucket* b = first; + + while (b != NULL) { + assert(b->count() >= 0, err_msg("bucket count: %d", b->count())); + nmethodBucket* next = b->next(); + if (b->count() == 0) { + if (last == NULL) { + first = next; + } else { + last->set_next(next); + } + delete b; + // last stays the same. + } else { + last = b; + } + b = next; + } + return first; +} + +#ifndef PRODUCT +void nmethodBucket::print_dependent_nmethods(nmethodBucket* deps, bool verbose) { + int idx = 0; + for (nmethodBucket* b = deps; b != NULL; b = b->next()) { + nmethod* nm = b->get_nmethod(); + tty->print("[%d] count=%d { ", idx++, b->count()); + if (!verbose) { + nm->print_on(tty, "nmethod"); + tty->print_cr(" } "); + } else { + nm->print(); + nm->print_dependencies(); + tty->print_cr("--- } "); + } + } +} + +bool nmethodBucket::is_dependent_nmethod(nmethodBucket* deps, nmethod* nm) { + for (nmethodBucket* b = deps; b != NULL; b = b->next()) { + if (nm == b->get_nmethod()) { +#ifdef ASSERT + int count = b->count(); + assert(count >= 0, err_msg("count shouldn't be negative: %d", count)); +#endif + return true; + } + } + return false; +} +#endif //PRODUCT + +int InstanceKlass::mark_dependent_nmethods(DepChange& changes) { + assert_locked_or_safepoint(CodeCache_lock); + return nmethodBucket::mark_dependent_nmethods(_dependencies, changes); +} + void InstanceKlass::clean_dependent_nmethods() { assert_locked_or_safepoint(CodeCache_lock); if (has_unloaded_dependent()) { - nmethodBucket* b = _dependencies; - nmethodBucket* last = NULL; - while (b != NULL) { - assert(b->count() >= 0, err_msg("bucket count: %d", b->count())); - - nmethodBucket* next = b->next(); - - if (b->count() == 0) { - if (last == NULL) { - _dependencies = next; - } else { - last->set_next(next); - } - delete b; - // last stays the same. - } else { - last = b; - } - - b = next; - } + _dependencies = nmethodBucket::clean_dependent_nmethods(_dependencies); set_has_unloaded_dependent(false); } #ifdef ASSERT @@ -1893,90 +1966,26 @@ #endif } -// -// Add an nmethodBucket to the list of dependencies for this nmethod. -// It's possible that an nmethod has multiple dependencies on this klass -// so a count is kept for each bucket to guarantee that creation and -// deletion of dependencies is consistent. -// void InstanceKlass::add_dependent_nmethod(nmethod* nm) { assert_locked_or_safepoint(CodeCache_lock); - nmethodBucket* b = _dependencies; - nmethodBucket* last = NULL; - while (b != NULL) { - if (nm == b->get_nmethod()) { - b->increment(); - return; - } - b = b->next(); - } - _dependencies = new nmethodBucket(nm, _dependencies); + _dependencies = nmethodBucket::add_dependent_nmethod(_dependencies, nm); } - -// -// Decrement count of the nmethod in the dependency list and remove -// the bucket competely when the count goes to 0. This method must -// find a corresponding bucket otherwise there's a bug in the -// recording of dependecies. -// void InstanceKlass::remove_dependent_nmethod(nmethod* nm) { assert_locked_or_safepoint(CodeCache_lock); - nmethodBucket* b = _dependencies; - nmethodBucket* last = NULL; - while (b != NULL) { - if (nm == b->get_nmethod()) { - int val = b->decrement(); - guarantee(val >= 0, err_msg("Underflow: %d", val)); - if (val == 0) { - set_has_unloaded_dependent(true); - } - return; - } - last = b; - b = b->next(); + + if (nmethodBucket::remove_dependent_nmethod(_dependencies, nm)) { + set_has_unloaded_dependent(true); } -#ifdef ASSERT - tty->print_cr("### %s can't find dependent nmethod:", this->external_name()); - nm->print(); -#endif // ASSERT - ShouldNotReachHere(); } - #ifndef PRODUCT void InstanceKlass::print_dependent_nmethods(bool verbose) { - nmethodBucket* b = _dependencies; - int idx = 0; - while (b != NULL) { - nmethod* nm = b->get_nmethod(); - tty->print("[%d] count=%d { ", idx++, b->count()); - if (!verbose) { - nm->print_on(tty, "nmethod"); - tty->print_cr(" } "); - } else { - nm->print(); - nm->print_dependencies(); - tty->print_cr("--- } "); - } - b = b->next(); - } + nmethodBucket::print_dependent_nmethods(_dependencies, verbose); } - bool InstanceKlass::is_dependent_nmethod(nmethod* nm) { - nmethodBucket* b = _dependencies; - while (b != NULL) { - if (nm == b->get_nmethod()) { -#ifdef ASSERT - int count = b->count(); - assert(count >= 0, err_msg("count shouldn't be negative: %d", count)); -#endif - return true; - } - b = b->next(); - } - return false; + return nmethodBucket::is_dependent_nmethod(_dependencies, nm); } #endif //PRODUCT diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/oops/instanceKlass.hpp --- a/hotspot/src/share/vm/oops/instanceKlass.hpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Mon Jun 08 11:11:47 2015 -0700 @@ -1290,6 +1290,15 @@ nmethodBucket* next() { return _next; } void set_next(nmethodBucket* b) { _next = b; } nmethod* get_nmethod() { return _nmethod; } + + static int mark_dependent_nmethods(nmethodBucket* deps, DepChange& changes); + static nmethodBucket* add_dependent_nmethod(nmethodBucket* deps, nmethod* nm); + static bool remove_dependent_nmethod(nmethodBucket* deps, nmethod* nm); + static nmethodBucket* clean_dependent_nmethods(nmethodBucket* deps); +#ifndef PRODUCT + static void print_dependent_nmethods(nmethodBucket* deps, bool verbose); + static bool is_dependent_nmethod(nmethodBucket* deps, nmethod* nm); +#endif //PRODUCT }; // An iterator that's used to access the inner classes indices in the diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/oops/klassVtable.cpp --- a/hotspot/src/share/vm/oops/klassVtable.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/oops/klassVtable.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -1136,7 +1136,7 @@ if (m->has_itable_index()) { // This search must match the runtime resolution, i.e. selection search for invokeinterface // to correctly enforce loader constraints for interface method inheritance - LinkResolver::lookup_instance_method_in_klasses(target, _klass, m->name(), m->signature(), CHECK); + target = LinkResolver::lookup_instance_method_in_klasses(_klass, m->name(), m->signature(), CHECK); } if (target == NULL || !target->is_public() || target->is_abstract()) { // Entry does not resolve. Leave it empty for AbstractMethodError. diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/opto/arraycopynode.cpp --- a/hotspot/src/share/vm/opto/arraycopynode.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/opto/arraycopynode.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -599,10 +599,14 @@ } bool ArrayCopyNode::may_modify(const TypeOopPtr *t_oop, PhaseTransform *phase) { - const TypeOopPtr* dest_t = phase->type(in(ArrayCopyNode::Dest))->is_oopptr(); + Node* dest = in(ArrayCopyNode::Dest); + if (dest->is_top()) { + return false; + } + const TypeOopPtr* dest_t = phase->type(dest)->is_oopptr(); assert(!dest_t->is_known_instance() || _dest_type->is_known_instance(), "result of EA not recorded"); - const TypeOopPtr* src_t = phase->type(in(ArrayCopyNode::Src))->is_oopptr(); - assert(!src_t->is_known_instance() || _src_type->is_known_instance(), "result of EA not recorded"); + assert(in(ArrayCopyNode::Src)->is_top() || !phase->type(in(ArrayCopyNode::Src))->is_oopptr()->is_known_instance() || + _src_type->is_known_instance(), "result of EA not recorded"); if (_dest_type != TypeOopPtr::BOTTOM || t_oop->is_known_instance()) { assert(_dest_type == TypeOopPtr::BOTTOM || _dest_type->is_known_instance(), "result of EA is known instance"); diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/opto/callnode.cpp --- a/hotspot/src/share/vm/opto/callnode.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/opto/callnode.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -1946,7 +1946,7 @@ } } } - if (may_modify_arraycopy_helper(phase->type(dest)->is_oopptr(), t_oop, phase)) { + if (!dest->is_top() && may_modify_arraycopy_helper(phase->type(dest)->is_oopptr(), t_oop, phase)) { return true; } return false; diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/opto/graphKit.cpp --- a/hotspot/src/share/vm/opto/graphKit.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/opto/graphKit.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -1457,18 +1457,18 @@ // factory methods in "int adr_idx" Node* GraphKit::make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, int adr_idx, - MemNode::MemOrd mo, bool require_atomic_access) { + MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency, bool require_atomic_access) { assert(adr_idx != Compile::AliasIdxTop, "use other make_load factory" ); const TypePtr* adr_type = NULL; // debug-mode-only argument debug_only(adr_type = C->get_adr_type(adr_idx)); Node* mem = memory(adr_idx); Node* ld; if (require_atomic_access && bt == T_LONG) { - ld = LoadLNode::make_atomic(ctl, mem, adr, adr_type, t, mo); + ld = LoadLNode::make_atomic(ctl, mem, adr, adr_type, t, mo, control_dependency); } else if (require_atomic_access && bt == T_DOUBLE) { - ld = LoadDNode::make_atomic(ctl, mem, adr, adr_type, t, mo); + ld = LoadDNode::make_atomic(ctl, mem, adr, adr_type, t, mo, control_dependency); } else { - ld = LoadNode::make(_gvn, ctl, mem, adr, adr_type, t, bt, mo); + ld = LoadNode::make(_gvn, ctl, mem, adr, adr_type, t, bt, mo, control_dependency); } ld = _gvn.transform(ld); if ((bt == T_OBJECT) && C->do_escape_analysis() || C->eliminate_boxing()) { diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/opto/graphKit.hpp --- a/hotspot/src/share/vm/opto/graphKit.hpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/opto/graphKit.hpp Mon Jun 08 11:11:47 2015 -0700 @@ -512,21 +512,24 @@ // adapted the `do_put_xxx' and `do_get_xxx' procedures for the case // of volatile fields. Node* make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, - MemNode::MemOrd mo, bool require_atomic_access = false) { + MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency = LoadNode::DependsOnlyOnTest, + bool require_atomic_access = false) { // This version computes alias_index from bottom_type return make_load(ctl, adr, t, bt, adr->bottom_type()->is_ptr(), - mo, require_atomic_access); + mo, control_dependency, require_atomic_access); } Node* make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, const TypePtr* adr_type, - MemNode::MemOrd mo, bool require_atomic_access = false) { + MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency = LoadNode::DependsOnlyOnTest, + bool require_atomic_access = false) { // This version computes alias_index from an address type assert(adr_type != NULL, "use other make_load factory"); return make_load(ctl, adr, t, bt, C->get_alias_index(adr_type), - mo, require_atomic_access); + mo, control_dependency, require_atomic_access); } // This is the base version which is given an alias index. Node* make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, int adr_idx, - MemNode::MemOrd mo, bool require_atomic_access = false); + MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency = LoadNode::DependsOnlyOnTest, + bool require_atomic_access = false); // Create & transform a StoreNode and store the effect into the // parser's memory state. diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/opto/library_call.cpp --- a/hotspot/src/share/vm/opto/library_call.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/opto/library_call.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -2631,7 +2631,9 @@ if (!is_store) { MemNode::MemOrd mo = is_volatile ? MemNode::acquire : MemNode::unordered; - Node* p = make_load(control(), adr, value_type, type, adr_type, mo, is_volatile); + // To be valid, unsafe loads may depend on other conditions than + // the one that guards them: pin the Load node + Node* p = make_load(control(), adr, value_type, type, adr_type, mo, LoadNode::Pinned, is_volatile); // load value switch (type) { case T_BOOLEAN: @@ -5488,7 +5490,7 @@ } // Build the load. MemNode::MemOrd mo = is_vol ? MemNode::acquire : MemNode::unordered; - Node* loadedField = make_load(NULL, adr, type, bt, adr_type, mo, is_vol); + Node* loadedField = make_load(NULL, adr, type, bt, adr_type, mo, LoadNode::DependsOnlyOnTest, is_vol); // If reference is volatile, prevent following memory ops from // floating up past the volatile read. Also prevents commoning // another volatile read. diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/opto/loopPredicate.cpp --- a/hotspot/src/share/vm/opto/loopPredicate.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/opto/loopPredicate.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -437,7 +437,13 @@ } } if (all_inputs_invariant) { - _invariant.set(n->_idx); // I am a invariant too + // If n's control is a predicate that was moved out of the + // loop, it was marked invariant but n is only invariant if + // it depends only on that test. Otherwise, unless that test + // is out of the loop, it's not invariant. + if (n->is_CFG() || n->depends_only_on_test() || n->in(0) == NULL || !_phase->is_member(_lpt, n->in(0))) { + _invariant.set(n->_idx); // I am a invariant too + } } } else { // process next input _stack.set_index(idx + 1); diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/opto/loopTransform.cpp --- a/hotspot/src/share/vm/opto/loopTransform.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/opto/loopTransform.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -1582,13 +1582,36 @@ if (opc != ReductionNode::opcode(opc, def_node->bottom_type()->basic_type())) { if (!def_node->is_reduction()) { // Not marked yet // To be a reduction, the arithmetic node must have the phi as input and provide a def to it + bool ok = false; for (unsigned j = 1; j < def_node->req(); j++) { Node* in = def_node->in(j); if (in == phi) { - def_node->add_flag(Node::Flag_is_reduction); + ok = true; break; } } + + // do nothing if we did not match the initial criteria + if (ok == false) { + continue; + } + + // The result of the reduction must not be used in the loop + for (DUIterator_Fast imax, i = def_node->fast_outs(imax); i < imax && ok; i++) { + Node* u = def_node->fast_out(i); + if (has_ctrl(u) && !loop->is_member(get_loop(get_ctrl(u)))) { + continue; + } + if (u == phi) { + continue; + } + ok = false; + } + + // iff the uses conform + if (ok) { + def_node->add_flag(Node::Flag_is_reduction); + } } } } diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/opto/loopopts.cpp --- a/hotspot/src/share/vm/opto/loopopts.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/opto/loopopts.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -718,7 +718,7 @@ } // Use same limit as split_if_with_blocks_post - if( C->unique() > 35000 ) return n; // Method too big + if( C->live_nodes() > 35000 ) return n; // Method too big // Split 'n' through the merge point if it is profitable Node *phi = split_thru_phi( n, n_blk, policy ); @@ -802,7 +802,7 @@ // Cloning Cmp through Phi's involves the split-if transform. // FastLock is not used by an If if( n->is_Cmp() && !n->is_FastLock() ) { - if( C->unique() > 35000 ) return; // Method too big + if( C->live_nodes() > 35000 ) return; // Method too big // Do not do 'split-if' if irreducible loops are present. if( _has_irreducible_loops ) diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/opto/matcher.cpp --- a/hotspot/src/share/vm/opto/matcher.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/opto/matcher.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -844,7 +844,7 @@ MachNode *spillCP = match_tree(new LoadNNode(NULL,mem,fp,atp,TypeInstPtr::BOTTOM,MemNode::unordered)); #endif MachNode *spillI = match_tree(new LoadINode(NULL,mem,fp,atp,TypeInt::INT,MemNode::unordered)); - MachNode *spillL = match_tree(new LoadLNode(NULL,mem,fp,atp,TypeLong::LONG,MemNode::unordered,false)); + MachNode *spillL = match_tree(new LoadLNode(NULL,mem,fp,atp,TypeLong::LONG,MemNode::unordered, LoadNode::DependsOnlyOnTest, false)); MachNode *spillF = match_tree(new LoadFNode(NULL,mem,fp,atp,Type::FLOAT,MemNode::unordered)); MachNode *spillD = match_tree(new LoadDNode(NULL,mem,fp,atp,Type::DOUBLE,MemNode::unordered)); MachNode *spillP = match_tree(new LoadPNode(NULL,mem,fp,atp,TypeInstPtr::BOTTOM,MemNode::unordered)); diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/opto/memnode.cpp --- a/hotspot/src/share/vm/opto/memnode.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/opto/memnode.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -784,6 +784,9 @@ // standard dump does this in Verbose and WizardMode st->print(" #"); _type->dump_on(st); } + if (!_depends_only_on_test) { + st->print(" (does not depend only on test)"); + } } #endif @@ -800,7 +803,7 @@ //----------------------------LoadNode::make----------------------------------- // Polymorphic factory method: -Node *LoadNode::make(PhaseGVN& gvn, Node *ctl, Node *mem, Node *adr, const TypePtr* adr_type, const Type *rt, BasicType bt, MemOrd mo) { +Node *LoadNode::make(PhaseGVN& gvn, Node *ctl, Node *mem, Node *adr, const TypePtr* adr_type, const Type *rt, BasicType bt, MemOrd mo, ControlDependency control_dependency) { Compile* C = gvn.C; // sanity check the alias category against the created node type @@ -816,39 +819,39 @@ rt->isa_oopptr() || is_immutable_value(adr), "raw memory operations should have control edge"); switch (bt) { - case T_BOOLEAN: return new LoadUBNode(ctl, mem, adr, adr_type, rt->is_int(), mo); - case T_BYTE: return new LoadBNode (ctl, mem, adr, adr_type, rt->is_int(), mo); - case T_INT: return new LoadINode (ctl, mem, adr, adr_type, rt->is_int(), mo); - case T_CHAR: return new LoadUSNode(ctl, mem, adr, adr_type, rt->is_int(), mo); - case T_SHORT: return new LoadSNode (ctl, mem, adr, adr_type, rt->is_int(), mo); - case T_LONG: return new LoadLNode (ctl, mem, adr, adr_type, rt->is_long(), mo); - case T_FLOAT: return new LoadFNode (ctl, mem, adr, adr_type, rt, mo); - case T_DOUBLE: return new LoadDNode (ctl, mem, adr, adr_type, rt, mo); - case T_ADDRESS: return new LoadPNode (ctl, mem, adr, adr_type, rt->is_ptr(), mo); + case T_BOOLEAN: return new LoadUBNode(ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); + case T_BYTE: return new LoadBNode (ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); + case T_INT: return new LoadINode (ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); + case T_CHAR: return new LoadUSNode(ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); + case T_SHORT: return new LoadSNode (ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); + case T_LONG: return new LoadLNode (ctl, mem, adr, adr_type, rt->is_long(), mo, control_dependency); + case T_FLOAT: return new LoadFNode (ctl, mem, adr, adr_type, rt, mo, control_dependency); + case T_DOUBLE: return new LoadDNode (ctl, mem, adr, adr_type, rt, mo, control_dependency); + case T_ADDRESS: return new LoadPNode (ctl, mem, adr, adr_type, rt->is_ptr(), mo, control_dependency); case T_OBJECT: #ifdef _LP64 if (adr->bottom_type()->is_ptr_to_narrowoop()) { - Node* load = gvn.transform(new LoadNNode(ctl, mem, adr, adr_type, rt->make_narrowoop(), mo)); + Node* load = gvn.transform(new LoadNNode(ctl, mem, adr, adr_type, rt->make_narrowoop(), mo, control_dependency)); return new DecodeNNode(load, load->bottom_type()->make_ptr()); } else #endif { assert(!adr->bottom_type()->is_ptr_to_narrowoop() && !adr->bottom_type()->is_ptr_to_narrowklass(), "should have got back a narrow oop"); - return new LoadPNode(ctl, mem, adr, adr_type, rt->is_oopptr(), mo); + return new LoadPNode(ctl, mem, adr, adr_type, rt->is_oopptr(), mo, control_dependency); } } ShouldNotReachHere(); return (LoadNode*)NULL; } -LoadLNode* LoadLNode::make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo) { +LoadLNode* LoadLNode::make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo, ControlDependency control_dependency) { bool require_atomic = true; - return new LoadLNode(ctl, mem, adr, adr_type, rt->is_long(), mo, require_atomic); + return new LoadLNode(ctl, mem, adr, adr_type, rt->is_long(), mo, control_dependency, require_atomic); } -LoadDNode* LoadDNode::make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo) { +LoadDNode* LoadDNode::make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo, ControlDependency control_dependency) { bool require_atomic = true; - return new LoadDNode(ctl, mem, adr, adr_type, rt, mo, require_atomic); + return new LoadDNode(ctl, mem, adr, adr_type, rt, mo, control_dependency, require_atomic); } diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/opto/memnode.hpp --- a/hotspot/src/share/vm/opto/memnode.hpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/opto/memnode.hpp Mon Jun 08 11:11:47 2015 -0700 @@ -137,7 +137,33 @@ //------------------------------LoadNode--------------------------------------- // Load value; requires Memory and Address class LoadNode : public MemNode { +public: + // Some loads (from unsafe) should be pinned: they don't depend only + // on the dominating test. The boolean field _depends_only_on_test + // below records whether that node depends only on the dominating + // test. + // Methods used to build LoadNodes pass an argument of type enum + // ControlDependency instead of a boolean because those methods + // typically have multiple boolean parameters with default values: + // passing the wrong boolean to one of these parameters by mistake + // goes easily unnoticed. Using an enum, the compiler can check that + // the type of a value and the type of the parameter match. + enum ControlDependency { + Pinned, + DependsOnlyOnTest + }; private: + // LoadNode::hash() doesn't take the _depends_only_on_test field + // into account: If the graph already has a non-pinned LoadNode and + // we add a pinned LoadNode with the same inputs, it's safe for GVN + // to replace the pinned LoadNode with the non-pinned LoadNode, + // otherwise it wouldn't be safe to have a non pinned LoadNode with + // those inputs in the first place. If the graph already has a + // pinned LoadNode and we add a non pinned LoadNode with the same + // inputs, it's safe (but suboptimal) for GVN to replace the + // non-pinned LoadNode by the pinned LoadNode. + bool _depends_only_on_test; + // On platforms with weak memory ordering (e.g., PPC, Ia64) we distinguish // loads that can be reordered, and such requiring acquire semantics to // adhere to the Java specification. The required behaviour is stored in @@ -154,8 +180,8 @@ virtual Node* find_previous_arraycopy(PhaseTransform* phase, Node* ld_alloc, Node*& mem, bool can_see_stored_value) const; public: - LoadNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const Type *rt, MemOrd mo) - : MemNode(c,mem,adr,at), _type(rt), _mo(mo) { + LoadNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const Type *rt, MemOrd mo, ControlDependency control_dependency) + : MemNode(c,mem,adr,at), _type(rt), _mo(mo), _depends_only_on_test(control_dependency == DependsOnlyOnTest) { init_class_id(Class_Load); } inline bool is_unordered() const { return !is_acquire(); } @@ -166,7 +192,8 @@ // Polymorphic factory method: static Node* make(PhaseGVN& gvn, Node *c, Node *mem, Node *adr, - const TypePtr* at, const Type *rt, BasicType bt, MemOrd mo); + const TypePtr* at, const Type *rt, BasicType bt, + MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest); virtual uint hash() const; // Check the type @@ -234,16 +261,15 @@ // which produce results (new raw memory state) inside of loops preventing all // manner of other optimizations). Basically, it's ugly but so is the alternative. // See comment in macro.cpp, around line 125 expand_allocate_common(). - virtual bool depends_only_on_test() const { return adr_type() != TypeRawPtr::BOTTOM; } - + virtual bool depends_only_on_test() const { return adr_type() != TypeRawPtr::BOTTOM && _depends_only_on_test; } }; //------------------------------LoadBNode-------------------------------------- // Load a byte (8bits signed) from memory class LoadBNode : public LoadNode { public: - LoadBNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo) - : LoadNode(c, mem, adr, at, ti, mo) {} + LoadBNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, ti, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegI; } virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); @@ -256,8 +282,8 @@ // Load a unsigned byte (8bits unsigned) from memory class LoadUBNode : public LoadNode { public: - LoadUBNode(Node* c, Node* mem, Node* adr, const TypePtr* at, const TypeInt* ti, MemOrd mo) - : LoadNode(c, mem, adr, at, ti, mo) {} + LoadUBNode(Node* c, Node* mem, Node* adr, const TypePtr* at, const TypeInt* ti, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, ti, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegI; } virtual Node* Ideal(PhaseGVN *phase, bool can_reshape); @@ -270,8 +296,8 @@ // Load an unsigned short/char (16bits unsigned) from memory class LoadUSNode : public LoadNode { public: - LoadUSNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo) - : LoadNode(c, mem, adr, at, ti, mo) {} + LoadUSNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, ti, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegI; } virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); @@ -284,8 +310,8 @@ // Load a short (16bits signed) from memory class LoadSNode : public LoadNode { public: - LoadSNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo) - : LoadNode(c, mem, adr, at, ti, mo) {} + LoadSNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, ti, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegI; } virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); @@ -298,8 +324,8 @@ // Load an integer from memory class LoadINode : public LoadNode { public: - LoadINode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo) - : LoadNode(c, mem, adr, at, ti, mo) {} + LoadINode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, ti, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegI; } virtual int store_Opcode() const { return Op_StoreI; } @@ -331,15 +357,15 @@ public: LoadLNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeLong *tl, - MemOrd mo, bool require_atomic_access = false) - : LoadNode(c, mem, adr, at, tl, mo), _require_atomic_access(require_atomic_access) {} + MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest, bool require_atomic_access = false) + : LoadNode(c, mem, adr, at, tl, mo, control_dependency), _require_atomic_access(require_atomic_access) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegL; } virtual int store_Opcode() const { return Op_StoreL; } virtual BasicType memory_type() const { return T_LONG; } bool require_atomic_access() const { return _require_atomic_access; } static LoadLNode* make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, - const Type* rt, MemOrd mo); + const Type* rt, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest); #ifndef PRODUCT virtual void dump_spec(outputStream *st) const { LoadNode::dump_spec(st); @@ -352,8 +378,8 @@ // Load a long from unaligned memory class LoadL_unalignedNode : public LoadLNode { public: - LoadL_unalignedNode(Node *c, Node *mem, Node *adr, const TypePtr* at, MemOrd mo) - : LoadLNode(c, mem, adr, at, TypeLong::LONG, mo) {} + LoadL_unalignedNode(Node *c, Node *mem, Node *adr, const TypePtr* at, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadLNode(c, mem, adr, at, TypeLong::LONG, mo, control_dependency) {} virtual int Opcode() const; }; @@ -361,8 +387,8 @@ // Load a float (64 bits) from memory class LoadFNode : public LoadNode { public: - LoadFNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const Type *t, MemOrd mo) - : LoadNode(c, mem, adr, at, t, mo) {} + LoadFNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const Type *t, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, t, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegF; } virtual int store_Opcode() const { return Op_StoreF; } @@ -382,15 +408,15 @@ public: LoadDNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const Type *t, - MemOrd mo, bool require_atomic_access = false) - : LoadNode(c, mem, adr, at, t, mo), _require_atomic_access(require_atomic_access) {} + MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest, bool require_atomic_access = false) + : LoadNode(c, mem, adr, at, t, mo, control_dependency), _require_atomic_access(require_atomic_access) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegD; } virtual int store_Opcode() const { return Op_StoreD; } virtual BasicType memory_type() const { return T_DOUBLE; } bool require_atomic_access() const { return _require_atomic_access; } static LoadDNode* make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, - const Type* rt, MemOrd mo); + const Type* rt, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest); #ifndef PRODUCT virtual void dump_spec(outputStream *st) const { LoadNode::dump_spec(st); @@ -403,8 +429,8 @@ // Load a double from unaligned memory class LoadD_unalignedNode : public LoadDNode { public: - LoadD_unalignedNode(Node *c, Node *mem, Node *adr, const TypePtr* at, MemOrd mo) - : LoadDNode(c, mem, adr, at, Type::DOUBLE, mo) {} + LoadD_unalignedNode(Node *c, Node *mem, Node *adr, const TypePtr* at, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadDNode(c, mem, adr, at, Type::DOUBLE, mo, control_dependency) {} virtual int Opcode() const; }; @@ -412,8 +438,8 @@ // Load a pointer from memory (either object or array) class LoadPNode : public LoadNode { public: - LoadPNode(Node *c, Node *mem, Node *adr, const TypePtr *at, const TypePtr* t, MemOrd mo) - : LoadNode(c, mem, adr, at, t, mo) {} + LoadPNode(Node *c, Node *mem, Node *adr, const TypePtr *at, const TypePtr* t, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, t, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegP; } virtual int store_Opcode() const { return Op_StoreP; } @@ -425,8 +451,8 @@ // Load a narrow oop from memory (either object or array) class LoadNNode : public LoadNode { public: - LoadNNode(Node *c, Node *mem, Node *adr, const TypePtr *at, const Type* t, MemOrd mo) - : LoadNode(c, mem, adr, at, t, mo) {} + LoadNNode(Node *c, Node *mem, Node *adr, const TypePtr *at, const Type* t, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, t, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegN; } virtual int store_Opcode() const { return Op_StoreN; } diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/opto/parse3.cpp --- a/hotspot/src/share/vm/opto/parse3.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/opto/parse3.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -235,7 +235,7 @@ // MemNode::MemOrd mo = is_vol ? MemNode::acquire : MemNode::unordered; bool needs_atomic_access = is_vol || AlwaysAtomicAccesses; - Node* ld = make_load(NULL, adr, type, bt, adr_type, mo, needs_atomic_access); + Node* ld = make_load(NULL, adr, type, bt, adr_type, mo, LoadNode::DependsOnlyOnTest, needs_atomic_access); // Adjust Java stack if (type2size[bt] == 1) diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/opto/phaseX.cpp --- a/hotspot/src/share/vm/opto/phaseX.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/opto/phaseX.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -1573,11 +1573,12 @@ set_type(n, t); for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { Node* m = n->fast_out(i); // Get user - if( m->is_Region() ) { // New path to Region? Must recheck Phis too + if (m->is_Region()) { // New path to Region? Must recheck Phis too for (DUIterator_Fast i2max, i2 = m->fast_outs(i2max); i2 < i2max; i2++) { Node* p = m->fast_out(i2); // Propagate changes to uses - if( p->bottom_type() != type(p) ) // If not already bottomed out + if (p->bottom_type() != type(p)) { // If not already bottomed out worklist.push(p); // Propagate change to user + } } } // If we changed the receiver type to a call, we need to revisit @@ -1587,12 +1588,31 @@ if (m->is_Call()) { for (DUIterator_Fast i2max, i2 = m->fast_outs(i2max); i2 < i2max; i2++) { Node* p = m->fast_out(i2); // Propagate changes to uses - if (p->is_Proj() && p->as_Proj()->_con == TypeFunc::Control && p->outcnt() == 1) + if (p->is_Proj() && p->as_Proj()->_con == TypeFunc::Control && p->outcnt() == 1) { worklist.push(p->unique_out()); + } } } - if( m->bottom_type() != type(m) ) // If not already bottomed out + if (m->bottom_type() != type(m)) { // If not already bottomed out worklist.push(m); // Propagate change to user + } + + // CmpU nodes can get their type information from two nodes up in the + // graph (instead of from the nodes immediately above). Make sure they + // are added to the worklist if nodes they depend on are updated, since + // they could be missed and get wrong types otherwise. + uint m_op = m->Opcode(); + if (m_op == Op_AddI || m_op == Op_SubI) { + for (DUIterator_Fast i2max, i2 = m->fast_outs(i2max); i2 < i2max; i2++) { + Node* p = m->fast_out(i2); // Propagate changes to uses + if (p->Opcode() == Op_CmpU) { + // Got a CmpU which might need the new type information from node n. + if(p->bottom_type() != type(p)) { // If not already bottomed out + worklist.push(p); // Propagate change to user + } + } + } + } } } } diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/opto/superword.cpp --- a/hotspot/src/share/vm/opto/superword.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/opto/superword.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -1631,7 +1631,7 @@ } Node* adr = low_adr->in(MemNode::Address); const TypePtr* atyp = n->adr_type(); - vn = LoadVectorNode::make(opc, ctl, mem, adr, atyp, vlen, velt_basic_type(n)); + vn = LoadVectorNode::make(opc, ctl, mem, adr, atyp, vlen, velt_basic_type(n), control_dependency(p)); vlen_in_bytes = vn->as_LoadVector()->memory_size(); } else if (n->is_Store()) { // Promote value to be stored to vector @@ -2280,6 +2280,19 @@ return n; } +LoadNode::ControlDependency SuperWord::control_dependency(Node_List* p) { + LoadNode::ControlDependency dep = LoadNode::DependsOnlyOnTest; + for (uint i = 0; i < p->size(); i++) { + Node* n = p->at(i); + assert(n->is_Load(), "only meaningful for loads"); + if (!n->depends_only_on_test()) { + dep = LoadNode::Pinned; + } + } + return dep; +} + + //----------------------------align_initial_loop_index--------------------------- // Adjust pre-loop limit so that in main loop, a load/store reference // to align_to_ref will be a position zero in the vector. diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/opto/superword.hpp --- a/hotspot/src/share/vm/opto/superword.hpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/opto/superword.hpp Mon Jun 08 11:11:47 2015 -0700 @@ -428,6 +428,7 @@ Node* executed_first(Node_List* p); // Return the node executed last in pack p. Node* executed_last(Node_List* p); + static LoadNode::ControlDependency control_dependency(Node_List* p); // Alignment within a vector memory reference int memory_alignment(MemNode* s, int iv_adjust); // (Start, end] half-open range defining which operands are vector diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/opto/vectornode.cpp --- a/hotspot/src/share/vm/opto/vectornode.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/opto/vectornode.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -406,9 +406,11 @@ // Return the vector version of a scalar load node. LoadVectorNode* LoadVectorNode::make(int opc, Node* ctl, Node* mem, - Node* adr, const TypePtr* atyp, uint vlen, BasicType bt) { + Node* adr, const TypePtr* atyp, + uint vlen, BasicType bt, + ControlDependency control_dependency) { const TypeVect* vt = TypeVect::make(bt, vlen); - return new LoadVectorNode(ctl, mem, adr, atyp, vt); + return new LoadVectorNode(ctl, mem, adr, atyp, vt, control_dependency); } // Return the vector version of a scalar store node. diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/opto/vectornode.hpp --- a/hotspot/src/share/vm/opto/vectornode.hpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/opto/vectornode.hpp Mon Jun 08 11:11:47 2015 -0700 @@ -454,8 +454,8 @@ // Load Vector from memory class LoadVectorNode : public LoadNode { public: - LoadVectorNode(Node* c, Node* mem, Node* adr, const TypePtr* at, const TypeVect* vt) - : LoadNode(c, mem, adr, at, vt, MemNode::unordered) { + LoadVectorNode(Node* c, Node* mem, Node* adr, const TypePtr* at, const TypeVect* vt, ControlDependency control_dependency = LoadNode::DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, vt, MemNode::unordered, control_dependency) { init_class_id(Class_LoadVector); } @@ -471,7 +471,9 @@ virtual int store_Opcode() const { return Op_StoreVector; } static LoadVectorNode* make(int opc, Node* ctl, Node* mem, - Node* adr, const TypePtr* atyp, uint vlen, BasicType bt); + Node* adr, const TypePtr* atyp, + uint vlen, BasicType bt, + ControlDependency control_dependency = LoadNode::DependsOnlyOnTest); }; //------------------------------StoreVectorNode-------------------------------- diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/prims/jni.cpp --- a/hotspot/src/share/vm/prims/jni.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/prims/jni.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -1126,39 +1126,32 @@ Method* m = Method::resolve_jmethod_id(method_id); number_of_parameters = m->size_of_parameters(); Klass* holder = m->method_holder(); - if (!(holder)->is_interface()) { + if (call_type != JNI_VIRTUAL) { + selected_method = m; + } else if (!m->has_itable_index()) { // non-interface call -- for that little speed boost, don't handlize debug_only(No_Safepoint_Verifier nosafepoint;) - if (call_type == JNI_VIRTUAL) { - // jni_GetMethodID makes sure class is linked and initialized - // so m should have a valid vtable index. - assert(!m->has_itable_index(), ""); - int vtbl_index = m->vtable_index(); - if (vtbl_index != Method::nonvirtual_vtable_index) { - Klass* k = h_recv->klass(); - // k might be an arrayKlassOop but all vtables start at - // the same place. The cast is to avoid virtual call and assertion. - InstanceKlass *ik = (InstanceKlass*)k; - selected_method = ik->method_at_vtable(vtbl_index); - } else { - // final method - selected_method = m; - } + // jni_GetMethodID makes sure class is linked and initialized + // so m should have a valid vtable index. + assert(m->valid_vtable_index(), "no valid vtable index"); + int vtbl_index = m->vtable_index(); + if (vtbl_index != Method::nonvirtual_vtable_index) { + Klass* k = h_recv->klass(); + // k might be an arrayKlassOop but all vtables start at + // the same place. The cast is to avoid virtual call and assertion. + InstanceKlass *ik = (InstanceKlass*)k; + selected_method = ik->method_at_vtable(vtbl_index); } else { - // JNI_NONVIRTUAL call + // final method selected_method = m; } } else { // interface call KlassHandle h_holder(THREAD, holder); - if (call_type == JNI_VIRTUAL) { - int itbl_index = m->itable_index(); - Klass* k = h_recv->klass(); - selected_method = InstanceKlass::cast(k)->method_at_itable(h_holder(), itbl_index, CHECK); - } else { - selected_method = m; - } + int itbl_index = m->itable_index(); + Klass* k = h_recv->klass(); + selected_method = InstanceKlass::cast(k)->method_at_itable(h_holder(), itbl_index, CHECK); } } diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/prims/jvmtiEnvBase.cpp --- a/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -842,7 +842,7 @@ // optimize to limit the number of times that java_sender() is called javaVFrame *jvf_cursor = jvf; javaVFrame *jvf_prev = NULL; - javaVFrame *jvf_prev_prev; + javaVFrame *jvf_prev_prev = NULL; int j = 0; while (jvf_cursor != NULL) { jvf_prev_prev = jvf_prev; diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/prims/methodHandles.cpp --- a/hotspot/src/share/vm/prims/methodHandles.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/prims/methodHandles.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -677,24 +677,24 @@ case IS_METHOD: { CallInfo result; + LinkInfo link_info(defc, name, type, caller, caller.not_null()); { assert(!HAS_PENDING_EXCEPTION, ""); if (ref_kind == JVM_REF_invokeStatic) { LinkResolver::resolve_static_call(result, - defc, name, type, caller, caller.not_null(), false, THREAD); + link_info, false, THREAD); } else if (ref_kind == JVM_REF_invokeInterface) { LinkResolver::resolve_interface_call(result, Handle(), defc, - defc, name, type, caller, caller.not_null(), false, THREAD); + link_info, false, THREAD); } else if (mh_invoke_id != vmIntrinsics::_none) { assert(!is_signature_polymorphic_static(mh_invoke_id), ""); - LinkResolver::resolve_handle_call(result, - defc, name, type, caller, THREAD); + LinkResolver::resolve_handle_call(result, link_info, THREAD); } else if (ref_kind == JVM_REF_invokeSpecial) { LinkResolver::resolve_special_call(result, - defc, name, type, caller, caller.not_null(), THREAD); + link_info, THREAD); } else if (ref_kind == JVM_REF_invokeVirtual) { LinkResolver::resolve_virtual_call(result, Handle(), defc, - defc, name, type, caller, caller.not_null(), false, THREAD); + link_info, false, THREAD); } else { assert(false, err_msg("ref_kind=%d", ref_kind)); } @@ -714,11 +714,11 @@ case IS_CONSTRUCTOR: { CallInfo result; + LinkInfo link_info(defc, name, type, caller, caller.not_null()); { assert(!HAS_PENDING_EXCEPTION, ""); if (name == vmSymbols::object_initializer_name()) { - LinkResolver::resolve_special_call(result, - defc, name, type, caller, caller.not_null(), THREAD); + LinkResolver::resolve_special_call(result, link_info, THREAD); } else { break; // will throw after end of switch } @@ -735,7 +735,8 @@ fieldDescriptor result; // find_field initializes fd if found { assert(!HAS_PENDING_EXCEPTION, ""); - LinkResolver::resolve_field(result, defc, name, type, caller, Bytecodes::_nop, false, false, THREAD); + LinkInfo link_info(defc, name, type, caller, /*check_access*/false); + LinkResolver::resolve_field(result, link_info, Bytecodes::_nop, false, THREAD); if (HAS_PENDING_EXCEPTION) { return empty; } @@ -942,22 +943,56 @@ return rfill + overflow; } -// Get context class for a CallSite instance: either extract existing context or use default one. -InstanceKlass* MethodHandles::get_call_site_context(oop call_site) { - // In order to extract a context the following traversal is performed: - // CallSite.context => Cleaner.referent => Class._klass => Klass - assert(java_lang_invoke_CallSite::is_instance(call_site), ""); - oop context_oop = java_lang_invoke_CallSite::context_volatile(call_site); - if (oopDesc::is_null(context_oop)) { - return NULL; // The context hasn't been initialized yet. +void MethodHandles::add_dependent_nmethod(oop call_site, nmethod* nm) { + assert_locked_or_safepoint(CodeCache_lock); + + oop context = java_lang_invoke_CallSite::context(call_site); + nmethodBucket* deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context); + + nmethodBucket* new_deps = nmethodBucket::add_dependent_nmethod(deps, nm); + if (deps != new_deps) { + java_lang_invoke_MethodHandleNatives_CallSiteContext::set_vmdependencies(context, new_deps); + } +} + +void MethodHandles::remove_dependent_nmethod(oop call_site, nmethod* nm) { + assert_locked_or_safepoint(CodeCache_lock); + + oop context = java_lang_invoke_CallSite::context(call_site); + nmethodBucket* deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context); + + if (nmethodBucket::remove_dependent_nmethod(deps, nm)) { + nmethodBucket* new_deps = nmethodBucket::clean_dependent_nmethods(deps); + if (deps != new_deps) { + java_lang_invoke_MethodHandleNatives_CallSiteContext::set_vmdependencies(context, new_deps); + } } - oop context_class_oop = java_lang_ref_Reference::referent(context_oop); - if (oopDesc::is_null(context_class_oop)) { - // The context reference was cleared by GC, so current dependency context - // isn't usable anymore. Context should be fetched from CallSite again. - return NULL; +} + +void MethodHandles::flush_dependent_nmethods(Handle call_site, Handle target) { + assert_lock_strong(Compile_lock); + + int marked = 0; + CallSiteDepChange changes(call_site(), target()); + { + MutexLockerEx mu2(CodeCache_lock, Mutex::_no_safepoint_check_flag); + + oop context = java_lang_invoke_CallSite::context(call_site()); + nmethodBucket* deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context); + + marked = nmethodBucket::mark_dependent_nmethods(deps, changes); + if (marked > 0) { + nmethodBucket* new_deps = nmethodBucket::clean_dependent_nmethods(deps); + if (deps != new_deps) { + java_lang_invoke_MethodHandleNatives_CallSiteContext::set_vmdependencies(context, new_deps); + } + } } - return InstanceKlass::cast(java_lang_Class::as_Klass(context_class_oop)); + if (marked > 0) { + // At least one nmethod has been marked for deoptimization + VM_Deoptimize op; + VMThread::execute(&op); + } } //------------------------------------------------------------------------------ @@ -1276,7 +1311,7 @@ { // Walk all nmethods depending on this call site. MutexLocker mu(Compile_lock, thread); - CodeCache::flush_dependents_on(call_site, target); + MethodHandles::flush_dependent_nmethods(call_site, target); java_lang_invoke_CallSite::set_target(call_site(), target()); } } @@ -1288,30 +1323,34 @@ { // Walk all nmethods depending on this call site. MutexLocker mu(Compile_lock, thread); - CodeCache::flush_dependents_on(call_site, target); + MethodHandles::flush_dependent_nmethods(call_site, target); java_lang_invoke_CallSite::set_target_volatile(call_site(), target()); } } JVM_END -JVM_ENTRY(void, MHN_invalidateDependentNMethods(JNIEnv* env, jobject igcls, jobject call_site_jh)) { - Handle call_site(THREAD, JNIHandles::resolve_non_null(call_site_jh)); +JVM_ENTRY(void, MHN_clearCallSiteContext(JNIEnv* env, jobject igcls, jobject context_jh)) { + Handle context(THREAD, JNIHandles::resolve_non_null(context_jh)); { // Walk all nmethods depending on this call site. MutexLocker mu1(Compile_lock, thread); - CallSiteDepChange changes(call_site(), Handle()); - - InstanceKlass* ctxk = MethodHandles::get_call_site_context(call_site()); - if (ctxk == NULL) { - return; // No dependencies to invalidate yet. - } int marked = 0; { MutexLockerEx mu2(CodeCache_lock, Mutex::_no_safepoint_check_flag); - marked = ctxk->mark_dependent_nmethods(changes); + nmethodBucket* b = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context()); + while(b != NULL) { + nmethod* nm = b->get_nmethod(); + if (b->count() > 0 && nm->is_alive() && !nm->is_marked_for_deoptimization()) { + nm->mark_for_deoptimization(); + marked++; + } + nmethodBucket* next = b->next(); + delete b; + b = next; + } + java_lang_invoke_MethodHandleNatives_CallSiteContext::set_vmdependencies(context(), NULL); // reset context } - java_lang_invoke_CallSite::set_context_volatile(call_site(), NULL); // Reset call site to initial state if (marked > 0) { // At least one nmethod has been marked for deoptimization VM_Deoptimize op; @@ -1357,6 +1396,7 @@ #define MT JLINV"MethodType;" #define MH JLINV"MethodHandle;" #define MEM JLINV"MemberName;" +#define CTX JLINV"MethodHandleNatives$CallSiteContext;" #define CC (char*) /*cast a literal from (const char*)*/ #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f) @@ -1374,7 +1414,7 @@ {CC"objectFieldOffset", CC"("MEM")J", FN_PTR(MHN_objectFieldOffset)}, {CC"setCallSiteTargetNormal", CC"("CS""MH")V", FN_PTR(MHN_setCallSiteTargetNormal)}, {CC"setCallSiteTargetVolatile", CC"("CS""MH")V", FN_PTR(MHN_setCallSiteTargetVolatile)}, - {CC"invalidateDependentNMethods", CC"("CS")V", FN_PTR(MHN_invalidateDependentNMethods)}, + {CC"clearCallSiteContext", CC"("CTX")V", FN_PTR(MHN_clearCallSiteContext)}, {CC"staticFieldOffset", CC"("MEM")J", FN_PTR(MHN_staticFieldOffset)}, {CC"staticFieldBase", CC"("MEM")"OBJ, FN_PTR(MHN_staticFieldBase)}, {CC"getMemberVMInfo", CC"("MEM")"OBJ, FN_PTR(MHN_getMemberVMInfo)} diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/prims/methodHandles.hpp --- a/hotspot/src/share/vm/prims/methodHandles.hpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/prims/methodHandles.hpp Mon Jun 08 11:11:47 2015 -0700 @@ -69,7 +69,10 @@ enum { _suppress_defc = 1, _suppress_name = 2, _suppress_type = 4 }; // CallSite support - static InstanceKlass* get_call_site_context(oop call_site); + static void add_dependent_nmethod(oop call_site, nmethod* nm); + static void remove_dependent_nmethod(oop call_site, nmethod* nm); + + static void flush_dependent_nmethods(Handle call_site, Handle target); // Generate MethodHandles adapters. static bool generate_adapters(); diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/runtime/javaCalls.cpp --- a/hotspot/src/share/vm/runtime/javaCalls.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/runtime/javaCalls.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, 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 @@ -179,9 +179,9 @@ CallInfo callinfo; Handle receiver = args->receiver(); KlassHandle recvrKlass(THREAD, receiver.is_null() ? (Klass*)NULL : receiver->klass()); + LinkInfo link_info(spec_klass, name, signature, KlassHandle(), /*check_access*/false); LinkResolver::resolve_virtual_call( - callinfo, receiver, recvrKlass, spec_klass, name, signature, - KlassHandle(), false, true, CHECK); + callinfo, receiver, recvrKlass, link_info, true, CHECK); methodHandle method = callinfo.selected_method(); assert(method.not_null(), "should have thrown exception"); @@ -216,7 +216,8 @@ void JavaCalls::call_special(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) { CallInfo callinfo; - LinkResolver::resolve_special_call(callinfo, klass, name, signature, KlassHandle(), false, CHECK); + LinkInfo link_info(klass, name, signature, KlassHandle(), /*check_access*/false); + LinkResolver::resolve_special_call(callinfo, link_info, CHECK); methodHandle method = callinfo.selected_method(); assert(method.not_null(), "should have thrown exception"); @@ -250,7 +251,8 @@ void JavaCalls::call_static(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) { CallInfo callinfo; - LinkResolver::resolve_static_call(callinfo, klass, name, signature, KlassHandle(), false, true, CHECK); + LinkInfo link_info(klass, name, signature, KlassHandle(), /*check_access*/false); + LinkResolver::resolve_static_call(callinfo, link_info, true, CHECK); methodHandle method = callinfo.selected_method(); assert(method.not_null(), "should have thrown exception"); diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/runtime/os.cpp --- a/hotspot/src/share/vm/runtime/os.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/runtime/os.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -775,6 +775,10 @@ pd_start_thread(thread); } +void os::abort(bool dump_core) { + abort(dump_core && CreateCoredumpOnCrash, NULL, NULL); +} + //--------------------------------------------------------------------------- // Helper functions for fatal error handler diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/runtime/reflection.cpp --- a/hotspot/src/share/vm/runtime/reflection.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/runtime/reflection.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -831,9 +831,9 @@ CallInfo info; Symbol* signature = method->signature(); Symbol* name = method->name(); - LinkResolver::resolve_interface_call(info, receiver, recv_klass, klass, - name, signature, - KlassHandle(), false, true, + LinkResolver::resolve_interface_call(info, receiver, recv_klass, + LinkInfo(klass, name, signature, KlassHandle(), false), + true, CHECK_(methodHandle())); return info.selected_method(); } diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/runtime/vmStructs.cpp diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/services/diagnosticCommand.cpp --- a/hotspot/src/share/vm/services/diagnosticCommand.cpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp Mon Jun 08 11:11:47 2015 -0700 @@ -315,7 +315,7 @@ void SystemGCDCmd::execute(DCmdSource source, TRAPS) { if (!DisableExplicitGC) { - Universe::heap()->collect(GCCause::_java_lang_system_gc); + Universe::heap()->collect(GCCause::_dcmd_gc_run); } else { output()->print_cr("Explicit GC is disabled, no GC has been performed."); } diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/src/share/vm/utilities/fakeRttiSupport.hpp --- a/hotspot/src/share/vm/utilities/fakeRttiSupport.hpp Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/src/share/vm/utilities/fakeRttiSupport.hpp Mon Jun 08 11:11:47 2015 -0700 @@ -89,11 +89,11 @@ return ((uintx)1) << validate_tag(tag); } - static TagType validate_tag(uintx tag) { - // Type of tag is not TagType to dodge useless MacOSX compiler warning. - assert(tag < (sizeof(uintx) * BitsPerByte), - err_msg("Tag " UINTX_FORMAT " is too large", tag)); - return static_cast(tag); + static TagType validate_tag(TagType tag) { + assert(0 <= tag, err_msg("Tag " INTX_FORMAT " is negative", (intx)tag)); + assert(tag < BitsPerWord, + err_msg("Tag " UINTX_FORMAT " is too large", (uintx)tag)); + return tag; } }; diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/test/compiler/arraycopy/TestDeadArrayCopyOnMemChain.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/arraycopy/TestDeadArrayCopyOnMemChain.java Mon Jun 08 11:11:47 2015 -0700 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015, 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 + * @bug 8080699 + * @summary eliminated arraycopy node still reachable through exception edges + * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation TestDeadArrayCopyOnMemChain + * + */ + +public class TestDeadArrayCopyOnMemChain { + static class A { + int f; + } + + static void test_helper(Object o) { + } + + static void test(int src_off, boolean flag) { + // dst is eliminated first. Eliminating dst causes src to be + // eliminated. When working on the safepoint at the uncommon + // trap in the exception handler, the eliminated ArrayCopyNode + // is reached through the exception edges. + Object[] dst = new Object[10]; + Object[] src = new Object[10]; + + // src_off causes the exception handler to be run sometimes + try { + System.arraycopy(src, src_off, dst, 0, 10); + } catch (IndexOutOfBoundsException ioobe) { + // flag always false so test becomes uncommon trap. Make + // sure src is live at the unc. + if (flag) { + test_helper(src); + } + } + } + + static public void main(String[] args) { + for (int i = 0; i < 20000; i++) { + test((i%2) == 0 ? 0 : -1, false); + } + } +} diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/test/compiler/jsr292/CallSiteDepContextTest.java --- a/hotspot/test/compiler/jsr292/CallSiteDepContextTest.java Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/test/compiler/jsr292/CallSiteDepContextTest.java Mon Jun 08 11:11:47 2015 -0700 @@ -24,12 +24,15 @@ /** * @test * @bug 8057967 - * @ignore 8079205 - * @run main/bootclasspath -Xbatch java.lang.invoke.CallSiteDepContextTest + * @run main/bootclasspath -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+TraceClassUnloading + * -XX:+PrintCompilation -XX:+TraceDependencies -XX:+TraceReferenceGC + * -verbose:gc java.lang.invoke.CallSiteDepContextTest */ package java.lang.invoke; import java.lang.ref.*; +import java.lang.reflect.Field; + import jdk.internal.org.objectweb.asm.*; import sun.misc.Unsafe; @@ -96,6 +99,13 @@ } } + public static void testHiddenDepField() throws Exception { + try { + Field f = MethodHandleNatives.CallSiteContext.class.getDeclaredField("vmdependencies"); + throw new AssertionError("Context.dependencies field should be hidden"); + } catch(NoSuchFieldException e) { /* expected */ } + } + public static void testSharedCallSite() throws Throwable { Class cls1 = UNSAFE.defineAnonymousClass(Object.class, getClassFile("CS_1"), null); Class cls2 = UNSAFE.defineAnonymousClass(Object.class, getClassFile("CS_2"), null); @@ -132,12 +142,14 @@ static ReferenceQueue rq = new ReferenceQueue(); static PhantomReference ref; - public static void testGC() throws Throwable { + public static void testGC(boolean clear, boolean precompile) throws Throwable { + String id = "_" + clear + "_" + precompile; + mcs = new MutableCallSite(LOOKUP.findStatic(T.class, "f1", TYPE)); Class[] cls = new Class[] { - UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_1"), null), - UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_2"), null), + UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_1" + id), null), + UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_2" + id), null), }; MethodHandle[] mhs = new MethodHandle[] { @@ -151,30 +163,38 @@ execute(1, mhs); ref = new PhantomReference<>(cls[0], rq); - cls[0] = UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_3"), null); + cls[0] = UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_3" + id), null); mhs[0] = LOOKUP.findStatic(cls[0], METHOD_NAME, TYPE); do { System.gc(); try { - Reference ref1 = rq.remove(1000); + Reference ref1 = rq.remove(100); if (ref1 == ref) { - ref1.clear(); - System.gc(); // Ensure that the stale context is cleared break; } } catch(InterruptedException e) { /* ignore */ } } while (true); - execute(1, mhs); + if (clear) { + ref.clear(); + System.gc(); // Ensure that the stale context is unloaded + } + if (precompile) { + execute(1, mhs); + } mcs.setTarget(LOOKUP.findStatic(T.class, "f2", TYPE)); execute(2, mhs); } public static void main(String[] args) throws Throwable { + testHiddenDepField(); testSharedCallSite(); testNonBoundCallSite(); - testGC(); + testGC(false, false); + testGC(false, true); + testGC( true, false); + testGC( true, true); System.out.println("TEST PASSED"); } } diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/test/compiler/loopopts/superword/TestReductionWithLoopVariantUse.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/loopopts/superword/TestReductionWithLoopVariantUse.java Mon Jun 08 11:11:47 2015 -0700 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, 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 + * @bug 8080976 + * @summary Loop variant use in reduction should prevent vectorization + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestReductionWithLoopVariantUse + * + */ + +public class TestReductionWithLoopVariantUse { + static int m(int[] array) { + int c = 0; + for (int i = 0; i < 256; i++) { + c += array[i]; + array[i] = c; + } + return c; + } + + static public void main(String[] args) { + int[] array = new int[256]; + int[] array2 = new int[256]; + for (int j = 0; j < 256; j++) { + array2[j] = j; + } + for (int i = 0; i < 20000; i++) { + System.arraycopy(array2, 0, array, 0, 256); + int res = m(array); + boolean success = true; + int c = 0; + for (int j = 0; j < 256; j++) { + c += array2[j]; + if (array[j] != c) { + System.out.println("Failed for " + j + " : " + array[j] + " != " + c); + success = false; + } + } + if (c != res) { + System.out.println("Failed for sum: " + c + " != " + res); + } + if (!success) { + throw new RuntimeException("Test failed"); + } + } + } +} diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/test/compiler/types/TestTypePropagationToCmpU.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/types/TestTypePropagationToCmpU.java Mon Jun 08 11:11:47 2015 -0700 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015, 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 + * @bug 8080156 8060036 + * @summary Test correctness of type propagation to CmpUNodes. + * @run main TestTypePropagationToCmpU + */ +public class TestTypePropagationToCmpU { + public static void main(String[] args) { + try { + // Trigger compilation + for (int i = 0; i < 100_000; ++i) { + test(); + } + } catch (NullPointerException e) { + // Test should never throw a NullPointerException + throw new RuntimeException("Test failed"); + } + } + + static int global = 42; + + public static void test() { + int a = Integer.MIN_VALUE; + int b = global; + char[] buf = { 0 }; + for (int i = 0; i <= b; ++i) { + a = i - b; + } + // C2 adds a range check and an uncommon trap here to ensure that the array index + // is in bounds. If type information is not propagated correctly to the corresponding + // CmpUNode, this trap may be always taken. Because C2 also removes the unnecessary + // allocation of 'buf', a NullPointerException is thrown in this case. + char c = buf[(a * 11) / 2 - a]; // a is 0 here if global >= 0 + buf[0] = 0; + } +} diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/test/compiler/unsafe/TestUnsafeLoadControl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/unsafe/TestUnsafeLoadControl.java Mon Jun 08 11:11:47 2015 -0700 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2015, 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 + * @bug 8077504 + * @summary Unsafe load can loose control dependency and cause crash + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestUnsafeLoadControl + * + */ + +import java.lang.reflect.Field; +import sun.misc.Unsafe; + +public class TestUnsafeLoadControl { + + private static final Unsafe UNSAFE; + + static { + try { + Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); + unsafeField.setAccessible(true); + UNSAFE = (Unsafe) unsafeField.get(null); + } catch(Exception e) { + throw new RuntimeException(e); + } + } + + static int val; + static void test1(int[] a, boolean[] flags, boolean flag, long j) { + for (int i = 0; i < 10; i++) { + if (flags[i]) { + if (flag) { + long address = (j << 2) + UNSAFE.ARRAY_INT_BASE_OFFSET; + int v = UNSAFE.getInt(a, address); + val = v; + } + } + } + } + + static int test2(int[] a, boolean[] flags, boolean flag, long j) { + int sum = 0; + for (int i = 0; i < 10; i++) { + if (flags[i]) { + if (flag) { + long address = (j << 2) + UNSAFE.ARRAY_INT_BASE_OFFSET; + int v = UNSAFE.getInt(a, address); + if (v == 0) { + sum++; + } + } + } + } + return sum; + } + + static public void main(String[] args) { + boolean[] flags = new boolean[10]; + for (int i = 0; i < flags.length; i++) { + flags[i] = true; + } + int[] array = new int[10]; + for (int i = 0; i < 20000; i++) { + test1(array, flags, true, 0); + } + for (int i = 0; i < flags.length; i++) { + flags[i] = false; + } + test1(array, flags, true, Long.MAX_VALUE/4); + + for (int i = 0; i < flags.length; i++) { + flags[i] = true; + } + for (int i = 0; i < 20000; i++) { + test2(array, flags, true, 0); + } + for (int i = 0; i < flags.length; i++) { + flags[i] = false; + } + test2(array, flags, true, Long.MAX_VALUE/4); + } +} diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/test/gc/TestSmallHeap.java --- a/hotspot/test/gc/TestSmallHeap.java Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/test/gc/TestSmallHeap.java Mon Jun 08 11:11:47 2015 -0700 @@ -27,6 +27,7 @@ * @requires vm.gc=="null" * @requires (vm.opt.AggressiveOpts=="null") | (vm.opt.AggressiveOpts=="false") * @requires vm.compMode != "Xcomp" + * @requires vm.opt.UseCompressedOops != false * @summary Verify that starting the VM with a small heap works * @library /testlibrary /../../test/lib * @modules java.management/sun.management diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/test/runtime/jni/ToStringInInterfaceTest/ImplementationOfWithToString.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/jni/ToStringInInterfaceTest/ImplementationOfWithToString.java Mon Jun 08 11:11:47 2015 -0700 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015, 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. + */ + +/** + * Implementation of InterfaceWithToString. + */ +public class ImplementationOfWithToString implements InterfaceWithToString { + + /** + * @see InterfaceWithToString#someMethod() + * {@inheritDoc} + */ + @Override + public void someMethod() { + // May do something here. + } + + /** + * @see java.lang.Object#toString() + * {@inheritDoc} + */ + @Override + public String toString() { + return "toString() from " + getClass().getName(); + } +} diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/test/runtime/jni/ToStringInInterfaceTest/InterfaceWithToString.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/jni/ToStringInInterfaceTest/InterfaceWithToString.java Mon Jun 08 11:11:47 2015 -0700 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, 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 with toString declared. + */ +public interface InterfaceWithToString { + + void someMethod(); + + /** + * Same as Object.toString(). + * + * @return some custom string. + */ + String toString(); +} diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/test/runtime/jni/ToStringInInterfaceTest/ToStringTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/jni/ToStringInInterfaceTest/ToStringTest.java Mon Jun 08 11:11:47 2015 -0700 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, 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 + * @bug 8072588 + * @build InterfaceWithToString + * @build ImplementationOfWithToString + * @run main/native ToStringTest + */ +public final class ToStringTest { + + static { + System.loadLibrary("ToStringTest"); + } + + native static void nTest(); + + public static void main(String[] args) throws Exception { + nTest(); + } +} diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/test/runtime/jni/ToStringInInterfaceTest/libToStringTest.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/jni/ToStringInInterfaceTest/libToStringTest.c Mon Jun 08 11:11:47 2015 -0700 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015, 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. + */ + +/* + * Native test for ToStringInInterfaceTest. + */ + +#include "jni.h" + +#define checkException(env) if ((*env)->ExceptionCheck(env)) { return; } + +jstring callStringMethod(JNIEnv* env, jobject jobj, jmethodID id, ...) +{ + jstring value; + + va_list ap; + va_start(ap, id); + value = (jstring)(*env)->CallObjectMethodV(env, jobj, id, ap); + va_end(ap); + return value; +} + +JNIEXPORT void JNICALL Java_ToStringTest_nTest(JNIEnv* env, jclass jclazz) +{ + jclass classOfInterfaceWithToString; + jclass classOfImplementationOfWithToString; + jmethodID constructorOfImplementationOfWithToString; + jobject instanceOfImplementationOfWithToString; + jmethodID toStringOfInterfaceWithToString; + jmethodID toStringOfImplementationOfWithToString; + jstring jstr; + const char *chars; + + classOfInterfaceWithToString = (*env)->FindClass(env, "InterfaceWithToString"); + checkException(env); + classOfImplementationOfWithToString = (*env)->FindClass(env, "ImplementationOfWithToString"); + checkException(env); + + constructorOfImplementationOfWithToString = (*env)->GetMethodID(env, classOfImplementationOfWithToString, "", "()V"); + checkException(env); + + instanceOfImplementationOfWithToString = (*env)->NewObject(env, classOfImplementationOfWithToString, constructorOfImplementationOfWithToString); + checkException(env); + + toStringOfInterfaceWithToString = (*env)->GetMethodID(env, classOfInterfaceWithToString, "toString", "()Ljava/lang/String;"); + checkException(env); + + toStringOfImplementationOfWithToString = (*env)->GetMethodID(env, classOfImplementationOfWithToString, "toString", "()Ljava/lang/String;"); + checkException(env); + + jstr = callStringMethod(env, instanceOfImplementationOfWithToString, toStringOfImplementationOfWithToString); + checkException(env); + + chars = (*env)->GetStringUTFChars(env, jstr, NULL); + (*env)->ReleaseStringUTFChars(env, jstr, chars); + + jstr = callStringMethod(env, instanceOfImplementationOfWithToString, toStringOfInterfaceWithToString); + checkException(env); + + chars = (*env)->GetStringUTFChars(env, jstr, NULL); + (*env)->ReleaseStringUTFChars(env, jstr, chars); +} diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/test/serviceability/dcmd/gc/RunGCTest.java --- a/hotspot/test/serviceability/dcmd/gc/RunGCTest.java Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/test/serviceability/dcmd/gc/RunGCTest.java Mon Jun 08 11:11:47 2015 -0700 @@ -59,7 +59,7 @@ } OutputAnalyzer output = new OutputAnalyzer(gcLog, ""); - output.shouldMatch(".*\\[Full GC \\(System(\\.gc\\(\\))?.*"); + output.shouldContain("[Full GC (Diagnostic Command)"); } @Test diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/test/serviceability/sa/TestClassLoaderStats.java --- a/hotspot/test/serviceability/sa/TestClassLoaderStats.java Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/test/serviceability/sa/TestClassLoaderStats.java Mon Jun 08 11:11:47 2015 -0700 @@ -24,11 +24,14 @@ import jdk.test.lib.Platform; import jdk.test.lib.ProcessTools; import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.apps.LingeredApp; /* * @test + * @library /../../test/lib/share/classes * @library /testlibrary * @build jdk.test.lib.* + * @build jdk.test.lib.apps.* * @run main TestClassLoaderStats */ public class TestClassLoaderStats { @@ -39,19 +42,27 @@ return; } - ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder( - "-XX:+UsePerfData", - "sun.jvm.hotspot.tools.ClassLoaderStats", - Integer.toString(ProcessTools.getProcessId())); - OutputAnalyzer output = ProcessTools.executeProcess(processBuilder); - System.out.println(output.getOutput()); + LingeredApp app = null; + try { + app = LingeredApp.startApp(); - output.shouldHaveExitValue(0); - output.shouldContain("Debugger attached successfully."); - // The class loader stats header needs to be presented in the output: - output.shouldMatch("class_loader\\W+classes\\W+bytes\\W+parent_loader\\W+alive?\\W+type"); - output.stderrShouldNotMatch("[E|e]xception"); - output.stderrShouldNotMatch("[E|e]rror"); + System.out.println("Attaching sun.jvm.hotspot.tools.ClassLoaderStats to " + app.getPid()); + ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder( + "-XX:+UsePerfData", + "sun.jvm.hotspot.tools.ClassLoaderStats", + Long.toString(app.getPid())); + OutputAnalyzer output = ProcessTools.executeProcess(processBuilder); + System.out.println(output.getOutput()); + + output.shouldHaveExitValue(0); + output.shouldContain("Debugger attached successfully."); + // The class loader stats header needs to be presented in the output: + output.shouldMatch("class_loader\\W+classes\\W+bytes\\W+parent_loader\\W+alive?\\W+type"); + output.stderrShouldNotMatch("[E|e]xception"); + output.stderrShouldNotMatch("[E|e]rror"); + } finally { + app.stopApp(); + } } } diff -r 5b500c93ce48 -r 4c45af8f8225 hotspot/test/serviceability/sa/TestStackTrace.java --- a/hotspot/test/serviceability/sa/TestStackTrace.java Wed Jul 05 20:37:12 2017 +0200 +++ b/hotspot/test/serviceability/sa/TestStackTrace.java Mon Jun 08 11:11:47 2015 -0700 @@ -24,11 +24,14 @@ import jdk.test.lib.OutputAnalyzer; import jdk.test.lib.Platform; import jdk.test.lib.ProcessTools; +import jdk.test.lib.apps.LingeredApp; /* * @test + * @library /../../test/lib/share/classes * @library /testlibrary * @build jdk.test.lib.* + * @build jdk.test.lib.apps.* * @run main TestStackTrace */ public class TestStackTrace { @@ -39,17 +42,25 @@ return; } - ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder( - "-XX:+UsePerfData", - "sun.jvm.hotspot.tools.StackTrace", - Integer.toString(ProcessTools.getProcessId())); - OutputAnalyzer output = ProcessTools.executeProcess(processBuilder); - System.out.println(output.getOutput()); + LingeredApp app = null; + try { + app = LingeredApp.startApp(); - output.shouldHaveExitValue(0); - output.shouldContain("Debugger attached successfully."); - output.stderrShouldNotMatch("[E|e]xception"); - output.stderrShouldNotMatch("[E|e]rror"); + System.out.println("Attaching sun.jvm.hotspot.tools.StackTrace to " + app.getPid()); + ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder( + "-XX:+UsePerfData", + "sun.jvm.hotspot.tools.StackTrace", + Long.toString(app.getPid())); + OutputAnalyzer output = ProcessTools.executeProcess(processBuilder); + System.out.println(output.getOutput()); + + output.shouldHaveExitValue(0); + output.shouldContain("Debugger attached successfully."); + output.stderrShouldNotMatch("[E|e]xception"); + output.stderrShouldNotMatch("[E|e]rror"); + } finally { + app.stopApp(); + } } }