# HG changeset patch # User amurillo # Date 1438362902 25200 # Node ID a9f423dbab9e5b8a4cd5b900685478f371dd4a4d # Parent eeea9adfd1e3d075ef82148c00a4847a1aab4d26# Parent 6c23ab90cbaac0d89d853de6deb67084553ccbf5 Merge diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/agent/src/share/classes/sun/jvm/hotspot/SAGetopt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/SAGetopt.java Fri Jul 31 10:15:02 2015 -0700 @@ -0,0 +1,162 @@ +/* + * 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. + * + */ + +package sun.jvm.hotspot; + +import java.util.Arrays; +import java.util.List; + +public class SAGetopt { + + private String[] _argv; + + private int _optind; // index in arguments array + private int _optopt; // index within an argument + private String _optarg; // last option argument + private boolean _optreset; // special handling of first call + + public SAGetopt(String[] args) { + _argv = args; + _optind = 0; + _optopt = 1; + _optarg = null; + _optreset = true; + } + + public String getOptarg() { + return _optarg; + } + + public int getOptind() { + return _optind; + } + + private void extractOptarg(String opt) { + // Argument expected + if (_optind > _argv.length) { + throw new RuntimeException("Not enough arguments for '" + opt + "'"); + } + + if (! _argv[_optind].isEmpty() && _argv[_optind].charAt(0) == '-') { + throw new RuntimeException("Argument is expected for '" + opt + "'"); + } + + _optarg = _argv[_optind]; + _optind += 1; + } + + private String processLongOptions(String carg, String[] longOptStr) { + List los = Arrays.asList(longOptStr); + String[] ca = carg.split("=", 2); + + if (los.contains(ca[0])) { + if (ca.length > 1) { + throw new RuntimeException("Argument is not expected for '" + ca[0] + "'"); + } + return carg; + } + + if (los.contains(ca[0] + "=")) { + if (ca.length > 1) { + // GNU style options --file=name + _optarg = ca[1]; + } + else { + // Mixed style options --file name + extractOptarg(ca[0]); + } + + return ca[0]; + } + + throw new RuntimeException("Invalid option '" + ca[0] + "'"); + } + + public String next(String optStr, String[] longOptStr) { + + if (_optind >= _argv.length || _argv[_optind] == null) { + // All arguments processed + return null; + } + + String carg = _argv[_optind]; + _optarg = null; + + if (_optreset) { + // End of option batch like '-abc' reached, expect option to start from '-' + + if (carg.isEmpty() || carg.charAt(0) != '-' || carg.equals("--")) { + // Stop processing on -- or first non-option argument; + return null; + } + + if (carg.startsWith("--")) { + // Handle long options, it can't be combined so it's simple + if (longOptStr == null || longOptStr.length == 0) { + // No long options expected, stop options processing + return null; + } + ++ _optind; + + // at this point carg contains at least one character besides -- + carg = carg.substring(2); + return processLongOptions(carg, longOptStr); + } + + if (optStr == null || optStr.length() == 0) { + // No short options + return null; + } + + // At this point carg[0] contains '-' + _optreset = false; + _optopt = 1; + } + + char ch = carg.charAt(_optopt); + + // adjust pointer to next character + _optopt += 1; + + // Okay, ready to process options like + // -abc -d bla -ef + + int chIndex = optStr.indexOf(ch); + if (chIndex == -1) { + throw new RuntimeException("Invalid option '" + ch + "'"); + } + + if (_optopt >= carg.length()) { + _optind += 1; + _optreset = true; + } + + if (chIndex < optStr.length()-1 && optStr.charAt(chIndex+1) == ':') { + // Argument expected + extractOptarg(String.valueOf(ch)); + } + + return String.valueOf(ch); + } +} diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/agent/src/share/classes/sun/jvm/hotspot/SALauncher.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/SALauncher.java Fri Jul 31 10:15:02 2015 -0700 @@ -0,0 +1,359 @@ +/* + * 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. + * + */ + +package sun.jvm.hotspot; + +import java.util.ArrayList; +import java.util.Arrays; + +import sun.jvm.hotspot.tools.JStack; +import sun.jvm.hotspot.tools.JMap; +import sun.jvm.hotspot.tools.JInfo; + +public class SALauncher { + + private static boolean launcherHelp() { + System.out.println(" clhsdb \tcommand line debugger"); + System.out.println(" hsdb \tui debugger"); + System.out.println(" jstack --help\tto get more information"); + System.out.println(" jmap --help\tto get more information"); + System.out.println(" jinfo --help\tto get more information"); + return false; + } + + private static boolean commonHelp() { + // --pid + // --exe + // --core + System.out.println(" --exe\texecutable image name"); + System.out.println(" --core\tpath to coredump"); + System.out.println(" --pid\tpid of process to attach"); + return false; + } + + private static boolean jinfoHelp() { + // --flags -> -flags + // --sysprops -> -sysprops + System.out.println(" --flags\tto print VM flags"); + System.out.println(" --sysprops\tto print Java System properties"); + System.out.println(" \tto print both of the above"); + return commonHelp(); + } + + private static boolean jmapHelp() { + // --heap -> -heap + // --binaryheap -> -heap:format=b + // --histo -> -histo + // --clstats -> -clstats + // --finalizerinfo -> -finalizerinfo + + System.out.println(" \tto print same info as Solaris pmap"); + System.out.println(" --heap\tto print java heap summary"); + System.out.println(" --binaryheap\tto dump java heap in hprof binary format"); + System.out.println(" --histo\tto print histogram of java object heap"); + System.out.println(" --clstats\tto print class loader statistics"); + System.out.println(" --finalizerinfo\tto print information on objects awaiting finalization"); + return commonHelp(); + } + + private static boolean jstackHelp() { + // --locks -> -l + // --mixed -> -m + System.out.println(" --locks\tto print java.util.concurrent locks"); + System.out.println(" --mixed\tto print both java and native frames (mixed mode)"); + return commonHelp(); + } + + private static boolean toolHelp(String toolName) { + if (toolName.equals("jstack")) { + return jstackHelp(); + } + if (toolName.equals("jinfo")) { + return jinfoHelp(); + } + if (toolName.equals("jmap")) { + return jmapHelp(); + } + if (toolName.equals("hsdb") || toolName.equals("clhsdb")) { + return commonHelp(); + } + return launcherHelp(); + } + + private static void runCLHSDB(String[] oldArgs) { + SAGetopt sg = new SAGetopt(oldArgs); + String[] longOpts = {"exe=", "core=", "pid="}; + + ArrayList newArgs = new ArrayList(); + String exeORpid = null; + String core = null; + String s = null; + + while((s = sg.next(null, longOpts)) != null) { + if (s.equals("exe")) { + exeORpid = sg.getOptarg(); + continue; + } + if (s.equals("core")) { + core = sg.getOptarg(); + continue; + } + if (s.equals("pid")) { + exeORpid = sg.getOptarg(); + continue; + } + } + + if (exeORpid != null) { + newArgs.add(exeORpid); + if (core != null) { + newArgs.add(core); + } + } + CLHSDB.main(newArgs.toArray(new String[newArgs.size()])); + } + + private static void runHSDB(String[] oldArgs) { + SAGetopt sg = new SAGetopt(oldArgs); + String[] longOpts = {"exe=", "core=", "pid="}; + + ArrayList newArgs = new ArrayList(); + String exeORpid = null; + String core = null; + String s = null; + + while((s = sg.next(null, longOpts)) != null) { + if (s.equals("exe")) { + exeORpid = sg.getOptarg(); + continue; + } + if (s.equals("core")) { + core = sg.getOptarg(); + continue; + } + if (s.equals("pid")) { + exeORpid = sg.getOptarg(); + continue; + } + } + + if (exeORpid != null) { + newArgs.add(exeORpid); + if (core != null) { + newArgs.add(core); + } + } + HSDB.main(newArgs.toArray(new String[newArgs.size()])); + } + + private static void runJSTACK(String[] oldArgs) { + SAGetopt sg = new SAGetopt(oldArgs); + String[] longOpts = {"exe=", "core=", "pid=", + "mixed", "locks"}; + + ArrayList newArgs = new ArrayList(); + String exeORpid = null; + String core = null; + String s = null; + + while((s = sg.next(null, longOpts)) != null) { + if (s.equals("exe")) { + exeORpid = sg.getOptarg(); + continue; + } + if (s.equals("core")) { + core = sg.getOptarg(); + continue; + } + if (s.equals("pid")) { + exeORpid = sg.getOptarg(); + continue; + } + if (s.equals("mixed")) { + newArgs.add("-m"); + continue; + } + if (s.equals("locks")) { + newArgs.add("-l"); + continue; + } + } + + if (exeORpid != null) { + newArgs.add(exeORpid); + if (core != null) { + newArgs.add(core); + } + } + + JStack.main(newArgs.toArray(new String[newArgs.size()])); + } + + private static void runJMAP(String[] oldArgs) { + SAGetopt sg = new SAGetopt(oldArgs); + String[] longOpts = {"exe=", "core=", "pid=", + "heap", "binaryheap", "histo", "clstats", "finalizerinfo"}; + + ArrayList newArgs = new ArrayList(); + String exeORpid = null; + String core = null; + String s = null; + + while((s = sg.next(null, longOpts)) != null) { + if (s.equals("exe")) { + exeORpid = sg.getOptarg(); + continue; + } + if (s.equals("core")) { + core = sg.getOptarg(); + continue; + } + if (s.equals("pid")) { + exeORpid = sg.getOptarg(); + continue; + } + if (s.equals("heap")) { + newArgs.add("-heap"); + continue; + } + if (s.equals("binaryheap")) { + newArgs.add("-heap:format=b"); + continue; + } + if (s.equals("histo")) { + newArgs.add("-histo"); + continue; + } + if (s.equals("clstats")) { + newArgs.add("-clstats"); + continue; + } + if (s.equals("finalizerinfo")) { + newArgs.add("-finalizerinfo"); + continue; + } + } + + if (exeORpid != null) { + newArgs.add(exeORpid); + if (core != null) { + newArgs.add(core); + } + } + + JMap.main(newArgs.toArray(new String[newArgs.size()])); + } + + private static void runJINFO(String[] oldArgs) { + SAGetopt sg = new SAGetopt(oldArgs); + String[] longOpts = {"exe=", "core=", "pid=", + "flags", "sysprops"}; + + ArrayList newArgs = new ArrayList(); + String exeORpid = null; + String core = null; + String s = null; + + while((s = sg.next(null, longOpts)) != null) { + if (s.equals("exe")) { + exeORpid = sg.getOptarg(); + continue; + } + if (s.equals("core")) { + core = sg.getOptarg(); + continue; + } + if (s.equals("pid")) { + exeORpid = sg.getOptarg(); + continue; + } + if (s.equals("flags")) { + newArgs.add("-flags"); + continue; + } + if (s.equals("sysprops")) { + newArgs.add("-sysprops"); + continue; + } + } + + if (exeORpid != null) { + newArgs.add(exeORpid); + if (core != null) { + newArgs.add(core); + } + } + + JInfo.main(newArgs.toArray(new String[newArgs.size()])); + } + + public static void main(String[] args) { + // Provide a help + if (args.length == 0) { + launcherHelp(); + return; + } + // No arguments imply help for jstack, jmap, jinfo but launch clhsdb and hsdb + if (args.length == 1 && !args[0].equals("clhsdb") && !args[0].equals("hsdb")) { + toolHelp(args[0]); + return; + } + + for (String arg : args) { + if (arg.equals("-h") || arg.equals("-help") || arg.equals("--help")) { + toolHelp(args[0]); + return; + } + } + + String[] oldArgs = Arrays.copyOfRange(args, 1, args.length); + + // Run SA interactive mode + if (args[0].equals("clhsdb")) { + runCLHSDB(oldArgs); + return; + } + + if (args[0].equals("hsdb")) { + runHSDB(oldArgs); + return; + } + + // Run SA tmtools mode + if (args[0].equals("jstack")) { + runJSTACK(oldArgs); + return; + } + + if (args[0].equals("jmap")) { + runJMAP(oldArgs); + return; + } + + if (args[0].equals("jinfo")) { + runJINFO(oldArgs); + return; + } + } +} diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/aarch64/AARCH64ThreadContext.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/aarch64/AARCH64ThreadContext.java Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/aarch64/AARCH64ThreadContext.java Fri Jul 31 10:15:02 2015 -0700 @@ -37,6 +37,21 @@ public abstract class AARCH64ThreadContext implements ThreadContext { // Taken from /usr/include/asm/sigcontext.h on Linux/AARCH64. + // /* + // * Signal context structure - contains all info to do with the state + // * before the signal handler was invoked. + // */ + // struct sigcontext { + // __u64 fault_address; + // /* AArch64 registers */ + // __u64 regs[31]; + // __u64 sp; + // __u64 pc; + // __u64 pstate; + // /* 4K reserved for FP/SIMD state and future expansion */ + // __u8 __reserved[4096] __attribute__((__aligned__(16))); + // }; + // NOTE: the indices for the various registers must be maintained as // listed across various operating systems. However, only a small // subset of the registers' values are guaranteed to be present (and @@ -78,8 +93,9 @@ public static final int LR = 30; public static final int SP = 31; public static final int PC = 32; + public static final int PSTATE = 33; - public static final int NPRGREG = 33; + public static final int NPRGREG = 34; private long[] data; diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/g1/G1Allocator.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/g1/G1Allocator.java Wed Jul 05 20:44:11 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -package sun.jvm.hotspot.gc.g1; - -import java.util.Observable; -import java.util.Observer; - -import sun.jvm.hotspot.debugger.Address; -import sun.jvm.hotspot.runtime.VM; -import sun.jvm.hotspot.runtime.VMObject; -import sun.jvm.hotspot.types.CIntegerField; -import sun.jvm.hotspot.types.Type; -import sun.jvm.hotspot.types.TypeDataBase; - -public class G1Allocator extends VMObject { - - //size_t _summary_bytes_used; - static private CIntegerField summaryBytesUsedField; - - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - static private synchronized void initialize(TypeDataBase db) { - Type type = db.lookupType("G1Allocator"); - - summaryBytesUsedField = type.getCIntegerField("_summary_bytes_used"); - } - - public long getSummaryBytes() { - return summaryBytesUsedField.getValue(addr); - } - - public G1Allocator(Address addr) { - super(addr); - - } -} diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/g1/G1CollectedHeap.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/g1/G1CollectedHeap.java Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/g1/G1CollectedHeap.java Fri Jul 31 10:15:02 2015 -0700 @@ -36,6 +36,7 @@ import sun.jvm.hotspot.runtime.VM; import sun.jvm.hotspot.runtime.VMObjectFactory; import sun.jvm.hotspot.types.AddressField; +import sun.jvm.hotspot.types.CIntegerField; import sun.jvm.hotspot.types.Type; import sun.jvm.hotspot.types.TypeDataBase; @@ -46,8 +47,8 @@ static private long hrmFieldOffset; // MemRegion _g1_reserved; static private long g1ReservedFieldOffset; - // G1Allocator* _allocator - static private AddressField g1Allocator; + // size_t _summary_bytes_used; + static private CIntegerField summaryBytesUsedField; // G1MonitoringSupport* _g1mm; static private AddressField g1mmField; // HeapRegionSet _old_set; @@ -67,7 +68,7 @@ Type type = db.lookupType("G1CollectedHeap"); hrmFieldOffset = type.getField("_hrm").getOffset(); - g1Allocator = type.getAddressField("_allocator"); + summaryBytesUsedField = type.getCIntegerField("_summary_bytes_used"); g1mmField = type.getAddressField("_g1mm"); oldSetFieldOffset = type.getField("_old_set").getOffset(); humongousSetFieldOffset = type.getField("_humongous_set").getOffset(); @@ -78,7 +79,7 @@ } public long used() { - return allocator().getSummaryBytes(); + return summaryBytesUsedField.getValue(addr); } public long n_regions() { @@ -96,11 +97,6 @@ return (G1MonitoringSupport) VMObjectFactory.newObject(G1MonitoringSupport.class, g1mmAddr); } - public G1Allocator allocator() { - Address g1AllocatorAddr = g1Allocator.getValue(addr); - return (G1Allocator) VMObjectFactory.newObject(G1Allocator.class, g1AllocatorAddr); - } - public HeapRegionSetBase oldSet() { Address oldSetAddr = addr.addOffsetTo(oldSetFieldOffset); return (HeapRegionSetBase) VMObjectFactory.newObject(HeapRegionSetBase.class, diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/cpu/aarch64/vm/aarch64.ad --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad Fri Jul 31 10:15:02 2015 -0700 @@ -2167,8 +2167,12 @@ return 0; // Self copy, no move. } + bool is64 = (src_lo & 1) == 0 && src_lo + 1 == src_hi && + (dst_lo & 1) == 0 && dst_lo + 1 == dst_hi; + int src_offset = ra_->reg2offset(src_lo); + int dst_offset = ra_->reg2offset(dst_lo); + if (bottom_type()->isa_vect() != NULL) { - uint len = 4; uint ireg = ideal_reg(); assert(ireg == Op_VecD || ireg == Op_VecX, "must be 64 bit or 128 bit vector"); if (cbuf) { @@ -2176,334 +2180,115 @@ assert((src_lo_rc != rc_int && dst_lo_rc != rc_int), "sanity"); if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) { // stack->stack - int src_offset = ra_->reg2offset(src_lo); - int dst_offset = ra_->reg2offset(dst_lo); assert((src_offset & 7) && (dst_offset & 7), "unaligned stack offset"); - len = 8; if (ireg == Op_VecD) { - __ ldr(rscratch1, Address(sp, src_offset)); - __ str(rscratch1, Address(sp, dst_offset)); + __ unspill(rscratch1, true, src_offset); + __ spill(rscratch1, true, dst_offset); } else { - if (src_offset < 512) { - __ ldp(rscratch1, rscratch2, Address(sp, src_offset)); - } else { - __ ldr(rscratch1, Address(sp, src_offset)); - __ ldr(rscratch2, Address(sp, src_offset+4)); - len += 4; - } - if (dst_offset < 512) { - __ stp(rscratch1, rscratch2, Address(sp, dst_offset)); - } else { - __ str(rscratch1, Address(sp, dst_offset)); - __ str(rscratch2, Address(sp, dst_offset+4)); - len += 4; - } + __ spill_copy128(src_offset, dst_offset); } } else if (src_lo_rc == rc_float && dst_lo_rc == rc_float) { - __ orr(as_FloatRegister(Matcher::_regEncode[dst_lo]), + __ mov(as_FloatRegister(Matcher::_regEncode[dst_lo]), ireg == Op_VecD ? __ T8B : __ T16B, - as_FloatRegister(Matcher::_regEncode[src_lo]), as_FloatRegister(Matcher::_regEncode[src_lo])); } else if (src_lo_rc == rc_float && dst_lo_rc == rc_stack) { - __ str(as_FloatRegister(Matcher::_regEncode[src_lo]), - ireg == Op_VecD ? __ D : __ Q, - Address(sp, ra_->reg2offset(dst_lo))); + __ spill(as_FloatRegister(Matcher::_regEncode[src_lo]), + ireg == Op_VecD ? __ D : __ Q, + ra_->reg2offset(dst_lo)); } else if (src_lo_rc == rc_stack && dst_lo_rc == rc_float) { - __ ldr(as_FloatRegister(Matcher::_regEncode[dst_lo]), - ireg == Op_VecD ? __ D : __ Q, - Address(sp, ra_->reg2offset(src_lo))); + __ unspill(as_FloatRegister(Matcher::_regEncode[dst_lo]), + ireg == Op_VecD ? __ D : __ Q, + ra_->reg2offset(src_lo)); } else { ShouldNotReachHere(); } - } else if (st) { - if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) { - // stack->stack - int src_offset = ra_->reg2offset(src_lo); - int dst_offset = ra_->reg2offset(dst_lo); - if (ireg == Op_VecD) { - st->print("ldr rscratch1, [sp, #%d]", src_offset); - st->print("str rscratch1, [sp, #%d]", dst_offset); + } + } else if (cbuf) { + MacroAssembler _masm(cbuf); + switch (src_lo_rc) { + case rc_int: + if (dst_lo_rc == rc_int) { // gpr --> gpr copy + if (is64) { + __ mov(as_Register(Matcher::_regEncode[dst_lo]), + as_Register(Matcher::_regEncode[src_lo])); } else { - if (src_offset < 512) { - st->print("ldp rscratch1, rscratch2, [sp, #%d]", src_offset); - } else { - st->print("ldr rscratch1, [sp, #%d]", src_offset); - st->print("\nldr rscratch2, [sp, #%d]", src_offset+4); - } - if (dst_offset < 512) { - st->print("\nstp rscratch1, rscratch2, [sp, #%d]", dst_offset); - } else { - st->print("\nstr rscratch1, [sp, #%d]", dst_offset); - st->print("\nstr rscratch2, [sp, #%d]", dst_offset+4); - } - } - st->print("\t# vector spill, stack to stack"); - } else if (src_lo_rc == rc_float && dst_lo_rc == rc_float) { - st->print("mov %s, %s\t# vector spill, reg to reg", - Matcher::regName[dst_lo], Matcher::regName[src_lo]); - } else if (src_lo_rc == rc_float && dst_lo_rc == rc_stack) { - st->print("str %s, [sp, #%d]\t# vector spill, reg to stack", - Matcher::regName[src_lo], ra_->reg2offset(dst_lo)); - } else if (src_lo_rc == rc_stack && dst_lo_rc == rc_float) { - st->print("ldr %s, [sp, #%d]\t# vector spill, stack to reg", - Matcher::regName[dst_lo], ra_->reg2offset(src_lo)); - } - } - return len; - } - - switch (src_lo_rc) { - case rc_int: - if (dst_lo_rc == rc_int) { // gpr --> gpr copy - if (((src_lo & 1) == 0 && src_lo + 1 == src_hi) && - (dst_lo & 1) == 0 && dst_lo + 1 == dst_hi) { - // 64 bit - if (cbuf) { - MacroAssembler _masm(cbuf); - __ mov(as_Register(Matcher::_regEncode[dst_lo]), - as_Register(Matcher::_regEncode[src_lo])); - } else if (st) { - st->print("mov %s, %s\t# shuffle", - Matcher::regName[dst_lo], - Matcher::regName[src_lo]); - } - } else { - // 32 bit - if (cbuf) { - MacroAssembler _masm(cbuf); - __ movw(as_Register(Matcher::_regEncode[dst_lo]), - as_Register(Matcher::_regEncode[src_lo])); - } else if (st) { - st->print("movw %s, %s\t# shuffle", - Matcher::regName[dst_lo], - Matcher::regName[src_lo]); + MacroAssembler _masm(cbuf); + __ movw(as_Register(Matcher::_regEncode[dst_lo]), + as_Register(Matcher::_regEncode[src_lo])); } - } - } else if (dst_lo_rc == rc_float) { // gpr --> fpr copy - if (((src_lo & 1) == 0 && src_lo + 1 == src_hi) && - (dst_lo & 1) == 0 && dst_lo + 1 == dst_hi) { - // 64 bit - if (cbuf) { - MacroAssembler _masm(cbuf); - __ fmovd(as_FloatRegister(Matcher::_regEncode[dst_lo]), - as_Register(Matcher::_regEncode[src_lo])); - } else if (st) { - st->print("fmovd %s, %s\t# shuffle", - Matcher::regName[dst_lo], - Matcher::regName[src_lo]); - } - } else { - // 32 bit - if (cbuf) { - MacroAssembler _masm(cbuf); - __ fmovs(as_FloatRegister(Matcher::_regEncode[dst_lo]), - as_Register(Matcher::_regEncode[src_lo])); - } else if (st) { - st->print("fmovs %s, %s\t# shuffle", - Matcher::regName[dst_lo], - Matcher::regName[src_lo]); - } - } - } else { // gpr --> stack spill - assert(dst_lo_rc == rc_stack, "spill to bad register class"); - int dst_offset = ra_->reg2offset(dst_lo); - if (((src_lo & 1) == 0 && src_lo + 1 == src_hi) && - (dst_lo & 1) == 0 && dst_lo + 1 == dst_hi) { - // 64 bit - if (cbuf) { - MacroAssembler _masm(cbuf); - __ str(as_Register(Matcher::_regEncode[src_lo]), - Address(sp, dst_offset)); - } else if (st) { - st->print("str %s, [sp, #%d]\t# spill", - Matcher::regName[src_lo], - dst_offset); - } - } else { - // 32 bit - if (cbuf) { - MacroAssembler _masm(cbuf); - __ strw(as_Register(Matcher::_regEncode[src_lo]), - Address(sp, dst_offset)); - } else if (st) { - st->print("strw %s, [sp, #%d]\t# spill", - Matcher::regName[src_lo], - dst_offset); - } - } - } - return 4; - case rc_float: - if (dst_lo_rc == rc_int) { // fpr --> gpr copy - if (((src_lo & 1) == 0 && src_lo + 1 == src_hi) && - (dst_lo & 1) == 0 && dst_lo + 1 == dst_hi) { - // 64 bit - if (cbuf) { - MacroAssembler _masm(cbuf); - __ fmovd(as_Register(Matcher::_regEncode[dst_lo]), - as_FloatRegister(Matcher::_regEncode[src_lo])); - } else if (st) { - st->print("fmovd %s, %s\t# shuffle", - Matcher::regName[dst_lo], - Matcher::regName[src_lo]); + } else if (dst_lo_rc == rc_float) { // gpr --> fpr copy + if (is64) { + __ fmovd(as_FloatRegister(Matcher::_regEncode[dst_lo]), + as_Register(Matcher::_regEncode[src_lo])); + } else { + __ fmovs(as_FloatRegister(Matcher::_regEncode[dst_lo]), + as_Register(Matcher::_regEncode[src_lo])); } - } else { - // 32 bit - if (cbuf) { - MacroAssembler _masm(cbuf); - __ fmovs(as_Register(Matcher::_regEncode[dst_lo]), - as_FloatRegister(Matcher::_regEncode[src_lo])); - } else if (st) { - st->print("fmovs %s, %s\t# shuffle", - Matcher::regName[dst_lo], - Matcher::regName[src_lo]); - } - } - } else if (dst_lo_rc == rc_float) { // fpr --> fpr copy - if (((src_lo & 1) == 0 && src_lo + 1 == src_hi) && - (dst_lo & 1) == 0 && dst_lo + 1 == dst_hi) { - // 64 bit - if (cbuf) { - MacroAssembler _masm(cbuf); - __ fmovd(as_FloatRegister(Matcher::_regEncode[dst_lo]), - as_FloatRegister(Matcher::_regEncode[src_lo])); - } else if (st) { - st->print("fmovd %s, %s\t# shuffle", - Matcher::regName[dst_lo], - Matcher::regName[src_lo]); - } - } else { - // 32 bit - if (cbuf) { - MacroAssembler _masm(cbuf); - __ fmovs(as_FloatRegister(Matcher::_regEncode[dst_lo]), - as_FloatRegister(Matcher::_regEncode[src_lo])); - } else if (st) { - st->print("fmovs %s, %s\t# shuffle", - Matcher::regName[dst_lo], - Matcher::regName[src_lo]); - } - } - } else { // fpr --> stack spill - assert(dst_lo_rc == rc_stack, "spill to bad register class"); - int dst_offset = ra_->reg2offset(dst_lo); - if (((src_lo & 1) == 0 && src_lo + 1 == src_hi) && - (dst_lo & 1) == 0 && dst_lo + 1 == dst_hi) { - // 64 bit - if (cbuf) { - MacroAssembler _masm(cbuf); - __ strd(as_FloatRegister(Matcher::_regEncode[src_lo]), - Address(sp, dst_offset)); - } else if (st) { - st->print("strd %s, [sp, #%d]\t# spill", - Matcher::regName[src_lo], - dst_offset); - } - } else { - // 32 bit - if (cbuf) { - MacroAssembler _masm(cbuf); - __ strs(as_FloatRegister(Matcher::_regEncode[src_lo]), - Address(sp, dst_offset)); - } else if (st) { - st->print("strs %s, [sp, #%d]\t# spill", - Matcher::regName[src_lo], - dst_offset); - } + } else { // gpr --> stack spill + assert(dst_lo_rc == rc_stack, "spill to bad register class"); + __ spill(as_Register(Matcher::_regEncode[src_lo]), is64, dst_offset); } - } - return 4; - case rc_stack: - int src_offset = ra_->reg2offset(src_lo); - if (dst_lo_rc == rc_int) { // stack --> gpr load - if (((src_lo & 1) == 0 && src_lo + 1 == src_hi) && - (dst_lo & 1) == 0 && dst_lo + 1 == dst_hi) { - // 64 bit - if (cbuf) { - MacroAssembler _masm(cbuf); - __ ldr(as_Register(Matcher::_regEncode[dst_lo]), - Address(sp, src_offset)); - } else if (st) { - st->print("ldr %s, [sp, %d]\t# restore", - Matcher::regName[dst_lo], - src_offset); + break; + case rc_float: + if (dst_lo_rc == rc_int) { // fpr --> gpr copy + if (is64) { + __ fmovd(as_Register(Matcher::_regEncode[dst_lo]), + as_FloatRegister(Matcher::_regEncode[src_lo])); + } else { + __ fmovs(as_Register(Matcher::_regEncode[dst_lo]), + as_FloatRegister(Matcher::_regEncode[src_lo])); } - } else { - // 32 bit - if (cbuf) { - MacroAssembler _masm(cbuf); - __ ldrw(as_Register(Matcher::_regEncode[dst_lo]), - Address(sp, src_offset)); - } else if (st) { - st->print("ldr %s, [sp, %d]\t# restore", - Matcher::regName[dst_lo], - src_offset); - } - } - return 4; - } else if (dst_lo_rc == rc_float) { // stack --> fpr load - if (((src_lo & 1) == 0 && src_lo + 1 == src_hi) && - (dst_lo & 1) == 0 && dst_lo + 1 == dst_hi) { - // 64 bit - if (cbuf) { - MacroAssembler _masm(cbuf); - __ ldrd(as_FloatRegister(Matcher::_regEncode[dst_lo]), - Address(sp, src_offset)); - } else if (st) { - st->print("ldrd %s, [sp, %d]\t# restore", - Matcher::regName[dst_lo], - src_offset); + } else if (dst_lo_rc == rc_float) { // fpr --> fpr copy + if (cbuf) { + __ fmovd(as_FloatRegister(Matcher::_regEncode[dst_lo]), + as_FloatRegister(Matcher::_regEncode[src_lo])); + } else { + __ fmovs(as_FloatRegister(Matcher::_regEncode[dst_lo]), + as_FloatRegister(Matcher::_regEncode[src_lo])); } - } else { - // 32 bit - if (cbuf) { - MacroAssembler _masm(cbuf); - __ ldrs(as_FloatRegister(Matcher::_regEncode[dst_lo]), - Address(sp, src_offset)); - } else if (st) { - st->print("ldrs %s, [sp, %d]\t# restore", - Matcher::regName[dst_lo], - src_offset); - } + } else { // fpr --> stack spill + assert(dst_lo_rc == rc_stack, "spill to bad register class"); + __ spill(as_FloatRegister(Matcher::_regEncode[src_lo]), + is64 ? __ D : __ S, dst_offset); } - return 4; - } else { // stack --> stack copy - assert(dst_lo_rc == rc_stack, "spill to bad register class"); - int dst_offset = ra_->reg2offset(dst_lo); - if (((src_lo & 1) == 0 && src_lo + 1 == src_hi) && - (dst_lo & 1) == 0 && dst_lo + 1 == dst_hi) { - // 64 bit - if (cbuf) { - MacroAssembler _masm(cbuf); - __ ldr(rscratch1, Address(sp, src_offset)); - __ str(rscratch1, Address(sp, dst_offset)); - } else if (st) { - st->print("ldr rscratch1, [sp, %d]\t# mem-mem spill", - src_offset); - st->print("\n\t"); - st->print("str rscratch1, [sp, %d]", - dst_offset); - } - } else { - // 32 bit - if (cbuf) { - MacroAssembler _masm(cbuf); - __ ldrw(rscratch1, Address(sp, src_offset)); - __ strw(rscratch1, Address(sp, dst_offset)); - } else if (st) { - st->print("ldrw rscratch1, [sp, %d]\t# mem-mem spill", - src_offset); - st->print("\n\t"); - st->print("strw rscratch1, [sp, %d]", - dst_offset); - } + break; + case rc_stack: + if (dst_lo_rc == rc_int) { // stack --> gpr load + __ unspill(as_Register(Matcher::_regEncode[dst_lo]), is64, src_offset); + } else if (dst_lo_rc == rc_float) { // stack --> fpr load + __ unspill(as_FloatRegister(Matcher::_regEncode[dst_lo]), + is64 ? __ D : __ S, src_offset); + } else { // stack --> stack copy + assert(dst_lo_rc == rc_stack, "spill to bad register class"); + __ unspill(rscratch1, is64, src_offset); + __ spill(rscratch1, is64, dst_offset); } - return 8; + break; + default: + assert(false, "bad rc_class for spill"); + ShouldNotReachHere(); } } - assert(false," bad rc_class for spill "); - Unimplemented(); + if (st) { + st->print("spill "); + if (src_lo_rc == rc_stack) { + st->print("[sp, #%d] -> ", ra_->reg2offset(src_lo)); + } else { + st->print("%s -> ", Matcher::regName[src_lo]); + } + if (dst_lo_rc == rc_stack) { + st->print("[sp, #%d]", ra_->reg2offset(dst_lo)); + } else { + st->print("%s", Matcher::regName[dst_lo]); + } + if (bottom_type()->isa_vect() != NULL) { + st->print("\t# vector spill size = %d", ideal_reg()==Op_VecD ? 64:128); + } else { + st->print("\t# spill size = %d", is64 ? 64:32); + } + } + return 0; } @@ -2522,7 +2307,7 @@ } uint MachSpillCopyNode::size(PhaseRegAlloc *ra_) const { - return implementation(NULL, ra_, true, NULL); + return MachNode::size(ra_); } //============================================================================= diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp --- a/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -1896,7 +1896,7 @@ public: enum SIMD_Arrangement { - T8B, T16B, T4H, T8H, T2S, T4S, T1D, T2D + T8B, T16B, T4H, T8H, T2S, T4S, T1D, T2D, T1Q }; enum SIMD_RegVariant { @@ -2225,14 +2225,16 @@ f(0b001111, 15, 10), rf(Vn, 5), rf(Xd, 0); } - // We do not handle the 1Q arrangement. void pmull(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, FloatRegister Vm, SIMD_Arrangement Tb) { starti; - assert(Ta == T8H && (Tb == T8B || Tb == T16B), "Invalid Size specifier"); - f(0, 31), f(Tb & 1, 30), f(0b001110001, 29, 21), rf(Vm, 16), f(0b111000, 15, 10); - rf(Vn, 5), rf(Vd, 0); + assert((Ta == T1Q && (Tb == T1D || Tb == T2D)) || + (Ta == T8H && (Tb == T8B || Tb == T16B)), "Invalid Size specifier"); + int size = (Ta == T1Q) ? 0b11 : 0b00; + f(0, 31), f(Tb & 1, 30), f(0b001110, 29, 24), f(size, 23, 22); + f(1, 21), rf(Vm, 16), f(0b111000, 15, 10), rf(Vn, 5), rf(Vd, 0); } void pmull2(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, FloatRegister Vm, SIMD_Arrangement Tb) { + assert(Tb == T2D || Tb == T16B, "pmull2 assumes T2D or T16B as the second size specifier"); pmull(Vd, Ta, Vn, Vm, Tb); } @@ -2245,15 +2247,6 @@ f(0b100001010010, 21, 10), rf(Vn, 5), rf(Vd, 0); } - void rev32(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn) - { - starti; - assert(T <= T8H, "must be one of T8B, T16B, T4H, T8H"); - f(0, 31), f((int)T & 1, 30), f(0b101110, 29, 24); - f(T <= T16B ? 0b00 : 0b01, 23, 22), f(0b100000000010, 21, 10); - rf(Vn, 5), rf(Vd, 0); - } - void dup(FloatRegister Vd, SIMD_Arrangement T, Register Xs) { starti; @@ -2290,6 +2283,57 @@ #undef INSN + // Table vector lookup +#define INSN(NAME, op) \ + void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, unsigned registers, FloatRegister Vm) { \ + starti; \ + assert(T == T8B || T == T16B, "invalid arrangement"); \ + assert(0 < registers && registers <= 4, "invalid number of registers"); \ + f(0, 31), f((int)T & 1, 30), f(0b001110000, 29, 21), rf(Vm, 16), f(0, 15); \ + f(registers - 1, 14, 13), f(op, 12),f(0b00, 11, 10), rf(Vn, 5), rf(Vd, 0); \ + } + + INSN(tbl, 0); + INSN(tbx, 1); + +#undef INSN + +#define INSN(NAME, U, opcode) \ + void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn) { \ + starti; \ + assert((ASSERTION), MSG); \ + f(0, 31), f((int)T & 1, 30), f(U, 29), f(0b01110, 28, 24); \ + f((int)(T >> 1), 23, 22), f(0b10000, 21, 17), f(opcode, 16, 12); \ + f(0b10, 11, 10), rf(Vn, 5), rf(Vd, 0); \ + } + +#define MSG "invalid arrangement" + +#define ASSERTION (T == T8B || T == T16B || T == T4H || T == T8H || T == T2S || T == T4S) + INSN(rev64, 0, 0b00000); +#undef ASSERTION + +#define ASSERTION (T == T8B || T == T16B || T == T4H || T == T8H) + INSN(rev32, 1, 0b00000); +#undef ASSERTION + +#define ASSERTION (T == T8B || T == T16B) + INSN(rev16, 0, 0b00001); +#undef ASSERTION + +#undef MSG + +#undef INSN + +void ext(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm, int index) + { + starti; + assert(T == T8B || T == T16B, "invalid arrangement"); + assert((T == T8B && index <= 0b0111) || (T == T16B && index <= 0b1111), "Invalid index value"); + f(0, 31), f((int)T & 1, 30), f(0b101110000, 29, 21); + rf(Vm, 16), f(0, 15), f(index, 14, 11); + f(0, 10), rf(Vn, 5), rf(Vd, 0); + } /* Simulator extensions to the ISA diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -2009,6 +2009,14 @@ } } +void MacroAssembler::sub(Register Rd, Register Rn, RegisterOrConstant decrement) { + if (decrement.is_register()) { + sub(Rd, Rn, decrement.as_register()); + } else { + sub(Rd, Rn, decrement.as_constant()); + } +} + void MacroAssembler::reinit_heapbase() { if (UseCompressedOops) { @@ -2307,6 +2315,28 @@ } } +Address MacroAssembler::spill_address(int size, int offset, Register tmp) +{ + assert(offset >= 0, "spill to negative address?"); + // Offset reachable ? + // Not aligned - 9 bits signed offset + // Aligned - 12 bits unsigned offset shifted + Register base = sp; + if ((offset & (size-1)) && offset >= (1<<8)) { + add(tmp, base, offset & ((1<<12)-1)); + base = tmp; + offset &= -1<<12; + } + + if (offset >= (1<<12) * size) { + add(tmp, base, offset & (((1<<12)-1)<<12)); + base = tmp; + offset &= ~(((1<<12)-1)<<12); + } + + return Address(base, offset); +} + /** * Multiply 64 bit by 64 bit first loop. */ diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -464,10 +464,21 @@ mov(dst, (long)i); } + void mov(Register dst, RegisterOrConstant src) { + if (src.is_register()) + mov(dst, src.as_register()); + else + mov(dst, src.as_constant()); + } + void movptr(Register r, uintptr_t imm64); void mov(FloatRegister Vd, SIMD_Arrangement T, u_int32_t imm32); + void mov(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn) { + orr(Vd, T, Vn, Vn); + } + // macro instructions for accessing and updating floating point // status register // @@ -1045,6 +1056,7 @@ void add(Register Rd, Register Rn, RegisterOrConstant increment); void addw(Register Rd, Register Rn, RegisterOrConstant increment); + void sub(Register Rd, Register Rn, RegisterOrConstant decrement); void adrp(Register reg1, const Address &dest, unsigned long &byte_offset); @@ -1161,6 +1173,46 @@ // Uses rscratch2. Address offsetted_address(Register r, Register r1, Address::extend ext, int offset, int size); + +private: + // Returns an address on the stack which is reachable with a ldr/str of size + // Uses rscratch2 if the address is not directly reachable + Address spill_address(int size, int offset, Register tmp=rscratch2); + +public: + void spill(Register Rx, bool is64, int offset) { + if (is64) { + str(Rx, spill_address(8, offset)); + } else { + strw(Rx, spill_address(4, offset)); + } + } + void spill(FloatRegister Vx, SIMD_RegVariant T, int offset) { + str(Vx, T, spill_address(1 << (int)T, offset)); + } + void unspill(Register Rx, bool is64, int offset) { + if (is64) { + ldr(Rx, spill_address(8, offset)); + } else { + ldrw(Rx, spill_address(4, offset)); + } + } + void unspill(FloatRegister Vx, SIMD_RegVariant T, int offset) { + ldr(Vx, T, spill_address(1 << (int)T, offset)); + } + void spill_copy128(int src_offset, int dst_offset, + Register tmp1=rscratch1, Register tmp2=rscratch2) { + if (src_offset < 512 && (src_offset & 7) == 0 && + dst_offset < 512 && (dst_offset & 7) == 0) { + ldp(tmp1, tmp2, Address(sp, src_offset)); + stp(tmp1, tmp2, Address(sp, dst_offset)); + } else { + unspill(tmp1, true, src_offset); + spill(tmp1, true, dst_offset); + unspill(tmp1, true, src_offset+8); + spill(tmp1, true, dst_offset+8); + } + } }; #ifdef ASSERT diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -120,10 +120,8 @@ // we save r19-r28 which Java uses as scratch registers and C // expects to be callee-save // - // we don't save any FP registers since only v8-v15 are callee-save - // (strictly only the f and d components) and Java uses them as - // callee-save. v0-v7 are arg registers and C treats v16-v31 as - // volatile (as does Java?) + // we save the bottom 64 bits of each value stored in v8-v15; it is + // the responsibility of the caller to preserve larger values. // // so the stub frame looks like this when we enter Java code // @@ -131,14 +129,14 @@ // [ argument word n ] // ... // -27 [ argument word 1 ] - // -26 [ saved d15 ] <--- sp_after_call - // -25 [ saved d14 ] - // -24 [ saved d13 ] - // -23 [ saved d12 ] - // -22 [ saved d11 ] - // -21 [ saved d10 ] - // -20 [ saved d9 ] - // -19 [ saved d8 ] + // -26 [ saved v15 ] <--- sp_after_call + // -25 [ saved v14 ] + // -24 [ saved v13 ] + // -23 [ saved v12 ] + // -22 [ saved v11 ] + // -21 [ saved v10 ] + // -20 [ saved v9 ] + // -19 [ saved v8 ] // -18 [ saved r28 ] // -17 [ saved r27 ] // -16 [ saved r26 ] @@ -2437,6 +2435,137 @@ return start; } + /** + * Arguments: + * + * Input: + * c_rarg0 - current state address + * c_rarg1 - H key address + * c_rarg2 - data address + * c_rarg3 - number of blocks + * + * Output: + * Updated state at c_rarg0 + */ + address generate_ghash_processBlocks() { + __ align(CodeEntryAlignment); + Label L_ghash_loop, L_exit; + + StubCodeMark mark(this, "StubRoutines", "ghash_processBlocks"); + address start = __ pc(); + + Register state = c_rarg0; + Register subkeyH = c_rarg1; + Register data = c_rarg2; + Register blocks = c_rarg3; + + FloatRegister vzr = v30; + __ eor(vzr, __ T16B, vzr, vzr); // zero register + + __ mov(v26, __ T16B, 1); + __ mov(v27, __ T16B, 63); + __ mov(v28, __ T16B, 62); + __ mov(v29, __ T16B, 57); + + __ ldrq(v6, Address(state)); + __ ldrq(v16, Address(subkeyH)); + + __ ext(v0, __ T16B, v6, v6, 0x08); + __ ext(v1, __ T16B, v16, v16, 0x08); + __ eor(v16, __ T16B, v16, v1); + + __ bind(L_ghash_loop); + + __ ldrq(v2, Address(__ post(data, 0x10))); + __ rev64(v2, __ T16B, v2); // swap data + + __ ext(v6, __ T16B, v0, v0, 0x08); + __ eor(v6, __ T16B, v6, v2); + __ ext(v2, __ T16B, v6, v6, 0x08); + + __ pmull2(v7, __ T1Q, v2, v1, __ T2D); // A1*B1 + __ eor(v6, __ T16B, v6, v2); + __ pmull(v5, __ T1Q, v2, v1, __ T1D); // A0*B0 + __ pmull(v20, __ T1Q, v6, v16, __ T1D); // (A1 + A0)(B1 + B0) + + __ ext(v21, __ T16B, v5, v7, 0x08); + __ eor(v18, __ T16B, v7, v5); // A1*B1 xor A0*B0 + __ eor(v20, __ T16B, v20, v21); + __ eor(v20, __ T16B, v20, v18); + + // Registers pair holds the result of carry-less multiplication + __ ins(v7, __ D, v20, 0, 1); + __ ins(v5, __ D, v20, 1, 0); + + // Result of the multiplication is shifted by one bit position + // [X3:X2:X1:X0] = [X3:X2:X1:X0] << 1 + __ ushr(v18, __ T2D, v5, -63 & 63); + __ ins(v25, __ D, v18, 1, 0); + __ ins(v25, __ D, vzr, 0, 0); + __ ushl(v5, __ T2D, v5, v26); + __ orr(v5, __ T16B, v5, v25); + + __ ushr(v19, __ T2D, v7, -63 & 63); + __ ins(v19, __ D, v19, 1, 0); + __ ins(v19, __ D, v18, 0, 1); + __ ushl(v7, __ T2D, v7, v26); + __ orr(v6, __ T16B, v7, v19); + + __ ins(v24, __ D, v5, 0, 1); + + // A = X0 << 63 + __ ushl(v21, __ T2D, v5, v27); + + // A = X0 << 62 + __ ushl(v22, __ T2D, v5, v28); + + // A = X0 << 57 + __ ushl(v23, __ T2D, v5, v29); + + // D = X1^A^B^C + __ eor(v21, __ T16B, v21, v22); + __ eor(v21, __ T16B, v21, v23); + __ eor(v21, __ T16B, v21, v24); + __ ins(v5, __ D, v21, 1, 0); + + // [E1:E0] = [D:X0] >> 1 + __ ushr(v20, __ T2D, v5, -1 & 63); + __ ushl(v18, __ T2D, v5, v27); + __ ext(v25, __ T16B, v18, vzr, 0x08); + __ orr(v19, __ T16B, v20, v25); + + __ eor(v7, __ T16B, v5, v19); + + // [F1:F0] = [D:X0] >> 2 + __ ushr(v20, __ T2D, v5, -2 & 63); + __ ushl(v18, __ T2D, v5, v28); + __ ins(v25, __ D, v18, 0, 1); + __ orr(v19, __ T16B, v20, v25); + + __ eor(v7, __ T16B, v7, v19); + + // [G1:G0] = [D:X0] >> 7 + __ ushr(v20, __ T2D, v5, -7 & 63); + __ ushl(v18, __ T2D, v5, v29); + __ ins(v25, __ D, v18, 0, 1); + __ orr(v19, __ T16B, v20, v25); + + // [H1:H0] = [D^E1^F1^G1:X0^E0^F0^G0] + __ eor(v7, __ T16B, v7, v19); + + // Result = [H1:H0]^[X3:X2] + __ eor(v0, __ T16B, v7, v6); + + __ subs(blocks, blocks, 1); + __ cbnz(blocks, L_ghash_loop); + + __ ext(v1, __ T16B, v0, v0, 0x08); + __ st1(v1, __ T16B, state); + __ ret(lr); + + return start; + } + // Continuation point for throwing of implicit exceptions that are // not handled in the current activation. Fabricates an exception // oop and initiates normal exception dispatching in this @@ -2544,6 +2673,828 @@ return stub->entry_point(); } + class MontgomeryMultiplyGenerator : public MacroAssembler { + + Register Pa_base, Pb_base, Pn_base, Pm_base, inv, Rlen, Ra, Rb, Rm, Rn, + Pa, Pb, Pn, Pm, Rhi_ab, Rlo_ab, Rhi_mn, Rlo_mn, t0, t1, t2, Ri, Rj; + + RegSet _toSave; + bool _squaring; + + public: + MontgomeryMultiplyGenerator (Assembler *as, bool squaring) + : MacroAssembler(as->code()), _squaring(squaring) { + + // Register allocation + + Register reg = c_rarg0; + Pa_base = reg; // Argument registers + if (squaring) + Pb_base = Pa_base; + else + Pb_base = ++reg; + Pn_base = ++reg; + Rlen= ++reg; + inv = ++reg; + Pm_base = ++reg; + + // Working registers: + Ra = ++reg; // The current digit of a, b, n, and m. + Rb = ++reg; + Rm = ++reg; + Rn = ++reg; + + Pa = ++reg; // Pointers to the current/next digit of a, b, n, and m. + Pb = ++reg; + Pm = ++reg; + Pn = ++reg; + + t0 = ++reg; // Three registers which form a + t1 = ++reg; // triple-precision accumuator. + t2 = ++reg; + + Ri = ++reg; // Inner and outer loop indexes. + Rj = ++reg; + + Rhi_ab = ++reg; // Product registers: low and high parts + Rlo_ab = ++reg; // of a*b and m*n. + Rhi_mn = ++reg; + Rlo_mn = ++reg; + + // r19 and up are callee-saved. + _toSave = RegSet::range(r19, reg) + Pm_base; + } + + private: + void save_regs() { + push(_toSave, sp); + } + + void restore_regs() { + pop(_toSave, sp); + } + + template + void unroll_2(Register count, T block) { + Label loop, end, odd; + tbnz(count, 0, odd); + cbz(count, end); + align(16); + bind(loop); + (this->*block)(); + bind(odd); + (this->*block)(); + subs(count, count, 2); + br(Assembler::GT, loop); + bind(end); + } + + template + void unroll_2(Register count, T block, Register d, Register s, Register tmp) { + Label loop, end, odd; + tbnz(count, 0, odd); + cbz(count, end); + align(16); + bind(loop); + (this->*block)(d, s, tmp); + bind(odd); + (this->*block)(d, s, tmp); + subs(count, count, 2); + br(Assembler::GT, loop); + bind(end); + } + + void pre1(RegisterOrConstant i) { + block_comment("pre1"); + // Pa = Pa_base; + // Pb = Pb_base + i; + // Pm = Pm_base; + // Pn = Pn_base + i; + // Ra = *Pa; + // Rb = *Pb; + // Rm = *Pm; + // Rn = *Pn; + ldr(Ra, Address(Pa_base)); + ldr(Rb, Address(Pb_base, i, Address::uxtw(LogBytesPerWord))); + ldr(Rm, Address(Pm_base)); + ldr(Rn, Address(Pn_base, i, Address::uxtw(LogBytesPerWord))); + lea(Pa, Address(Pa_base)); + lea(Pb, Address(Pb_base, i, Address::uxtw(LogBytesPerWord))); + lea(Pm, Address(Pm_base)); + lea(Pn, Address(Pn_base, i, Address::uxtw(LogBytesPerWord))); + + // Zero the m*n result. + mov(Rhi_mn, zr); + mov(Rlo_mn, zr); + } + + // The core multiply-accumulate step of a Montgomery + // multiplication. The idea is to schedule operations as a + // pipeline so that instructions with long latencies (loads and + // multiplies) have time to complete before their results are + // used. This most benefits in-order implementations of the + // architecture but out-of-order ones also benefit. + void step() { + block_comment("step"); + // MACC(Ra, Rb, t0, t1, t2); + // Ra = *++Pa; + // Rb = *--Pb; + umulh(Rhi_ab, Ra, Rb); + mul(Rlo_ab, Ra, Rb); + ldr(Ra, pre(Pa, wordSize)); + ldr(Rb, pre(Pb, -wordSize)); + acc(Rhi_mn, Rlo_mn, t0, t1, t2); // The pending m*n from the + // previous iteration. + // MACC(Rm, Rn, t0, t1, t2); + // Rm = *++Pm; + // Rn = *--Pn; + umulh(Rhi_mn, Rm, Rn); + mul(Rlo_mn, Rm, Rn); + ldr(Rm, pre(Pm, wordSize)); + ldr(Rn, pre(Pn, -wordSize)); + acc(Rhi_ab, Rlo_ab, t0, t1, t2); + } + + void post1() { + block_comment("post1"); + + // MACC(Ra, Rb, t0, t1, t2); + // Ra = *++Pa; + // Rb = *--Pb; + umulh(Rhi_ab, Ra, Rb); + mul(Rlo_ab, Ra, Rb); + acc(Rhi_mn, Rlo_mn, t0, t1, t2); // The pending m*n + acc(Rhi_ab, Rlo_ab, t0, t1, t2); + + // *Pm = Rm = t0 * inv; + mul(Rm, t0, inv); + str(Rm, Address(Pm)); + + // MACC(Rm, Rn, t0, t1, t2); + // t0 = t1; t1 = t2; t2 = 0; + umulh(Rhi_mn, Rm, Rn); + +#ifndef PRODUCT + // assert(m[i] * n[0] + t0 == 0, "broken Montgomery multiply"); + { + mul(Rlo_mn, Rm, Rn); + add(Rlo_mn, t0, Rlo_mn); + Label ok; + cbz(Rlo_mn, ok); { + stop("broken Montgomery multiply"); + } bind(ok); + } +#endif + // We have very carefully set things up so that + // m[i]*n[0] + t0 == 0 (mod b), so we don't have to calculate + // the lower half of Rm * Rn because we know the result already: + // it must be -t0. t0 + (-t0) must generate a carry iff + // t0 != 0. So, rather than do a mul and an adds we just set + // the carry flag iff t0 is nonzero. + // + // mul(Rlo_mn, Rm, Rn); + // adds(zr, t0, Rlo_mn); + subs(zr, t0, 1); // Set carry iff t0 is nonzero + adcs(t0, t1, Rhi_mn); + adc(t1, t2, zr); + mov(t2, zr); + } + + void pre2(RegisterOrConstant i, RegisterOrConstant len) { + block_comment("pre2"); + // Pa = Pa_base + i-len; + // Pb = Pb_base + len; + // Pm = Pm_base + i-len; + // Pn = Pn_base + len; + + if (i.is_register()) { + sub(Rj, i.as_register(), len); + } else { + mov(Rj, i.as_constant()); + sub(Rj, Rj, len); + } + // Rj == i-len + + lea(Pa, Address(Pa_base, Rj, Address::uxtw(LogBytesPerWord))); + lea(Pb, Address(Pb_base, len, Address::uxtw(LogBytesPerWord))); + lea(Pm, Address(Pm_base, Rj, Address::uxtw(LogBytesPerWord))); + lea(Pn, Address(Pn_base, len, Address::uxtw(LogBytesPerWord))); + + // Ra = *++Pa; + // Rb = *--Pb; + // Rm = *++Pm; + // Rn = *--Pn; + ldr(Ra, pre(Pa, wordSize)); + ldr(Rb, pre(Pb, -wordSize)); + ldr(Rm, pre(Pm, wordSize)); + ldr(Rn, pre(Pn, -wordSize)); + + mov(Rhi_mn, zr); + mov(Rlo_mn, zr); + } + + void post2(RegisterOrConstant i, RegisterOrConstant len) { + block_comment("post2"); + if (i.is_constant()) { + mov(Rj, i.as_constant()-len.as_constant()); + } else { + sub(Rj, i.as_register(), len); + } + + adds(t0, t0, Rlo_mn); // The pending m*n, low part + + // As soon as we know the least significant digit of our result, + // store it. + // Pm_base[i-len] = t0; + str(t0, Address(Pm_base, Rj, Address::uxtw(LogBytesPerWord))); + + // t0 = t1; t1 = t2; t2 = 0; + adcs(t0, t1, Rhi_mn); // The pending m*n, high part + adc(t1, t2, zr); + mov(t2, zr); + } + + // A carry in t0 after Montgomery multiplication means that we + // should subtract multiples of n from our result in m. We'll + // keep doing that until there is no carry. + void normalize(RegisterOrConstant len) { + block_comment("normalize"); + // while (t0) + // t0 = sub(Pm_base, Pn_base, t0, len); + Label loop, post, again; + Register cnt = t1, i = t2; // Re-use registers; we're done with them now + cbz(t0, post); { + bind(again); { + mov(i, zr); + mov(cnt, len); + ldr(Rm, Address(Pm_base, i, Address::uxtw(LogBytesPerWord))); + ldr(Rn, Address(Pn_base, i, Address::uxtw(LogBytesPerWord))); + subs(zr, zr, zr); // set carry flag, i.e. no borrow + align(16); + bind(loop); { + sbcs(Rm, Rm, Rn); + str(Rm, Address(Pm_base, i, Address::uxtw(LogBytesPerWord))); + add(i, i, 1); + ldr(Rm, Address(Pm_base, i, Address::uxtw(LogBytesPerWord))); + ldr(Rn, Address(Pn_base, i, Address::uxtw(LogBytesPerWord))); + sub(cnt, cnt, 1); + } cbnz(cnt, loop); + sbc(t0, t0, zr); + } cbnz(t0, again); + } bind(post); + } + + // Move memory at s to d, reversing words. + // Increments d to end of copied memory + // Destroys tmp1, tmp2 + // Preserves len + // Leaves s pointing to the address which was in d at start + void reverse(Register d, Register s, Register len, Register tmp1, Register tmp2) { + assert(tmp1 < r19 && tmp2 < r19, "register corruption"); + + lea(s, Address(s, len, Address::uxtw(LogBytesPerWord))); + mov(tmp1, len); + unroll_2(tmp1, &MontgomeryMultiplyGenerator::reverse1, d, s, tmp2); + sub(s, d, len, ext::uxtw, LogBytesPerWord); + } + // where + void reverse1(Register d, Register s, Register tmp) { + ldr(tmp, pre(s, -wordSize)); + ror(tmp, tmp, 32); + str(tmp, post(d, wordSize)); + } + + void step_squaring() { + // An extra ACC + step(); + acc(Rhi_ab, Rlo_ab, t0, t1, t2); + } + + void last_squaring(RegisterOrConstant i) { + Label dont; + // if ((i & 1) == 0) { + tbnz(i.as_register(), 0, dont); { + // MACC(Ra, Rb, t0, t1, t2); + // Ra = *++Pa; + // Rb = *--Pb; + umulh(Rhi_ab, Ra, Rb); + mul(Rlo_ab, Ra, Rb); + acc(Rhi_ab, Rlo_ab, t0, t1, t2); + } bind(dont); + } + + void extra_step_squaring() { + acc(Rhi_mn, Rlo_mn, t0, t1, t2); // The pending m*n + + // MACC(Rm, Rn, t0, t1, t2); + // Rm = *++Pm; + // Rn = *--Pn; + umulh(Rhi_mn, Rm, Rn); + mul(Rlo_mn, Rm, Rn); + ldr(Rm, pre(Pm, wordSize)); + ldr(Rn, pre(Pn, -wordSize)); + } + + void post1_squaring() { + acc(Rhi_mn, Rlo_mn, t0, t1, t2); // The pending m*n + + // *Pm = Rm = t0 * inv; + mul(Rm, t0, inv); + str(Rm, Address(Pm)); + + // MACC(Rm, Rn, t0, t1, t2); + // t0 = t1; t1 = t2; t2 = 0; + umulh(Rhi_mn, Rm, Rn); + +#ifndef PRODUCT + // assert(m[i] * n[0] + t0 == 0, "broken Montgomery multiply"); + { + mul(Rlo_mn, Rm, Rn); + add(Rlo_mn, t0, Rlo_mn); + Label ok; + cbz(Rlo_mn, ok); { + stop("broken Montgomery multiply"); + } bind(ok); + } +#endif + // We have very carefully set things up so that + // m[i]*n[0] + t0 == 0 (mod b), so we don't have to calculate + // the lower half of Rm * Rn because we know the result already: + // it must be -t0. t0 + (-t0) must generate a carry iff + // t0 != 0. So, rather than do a mul and an adds we just set + // the carry flag iff t0 is nonzero. + // + // mul(Rlo_mn, Rm, Rn); + // adds(zr, t0, Rlo_mn); + subs(zr, t0, 1); // Set carry iff t0 is nonzero + adcs(t0, t1, Rhi_mn); + adc(t1, t2, zr); + mov(t2, zr); + } + + void acc(Register Rhi, Register Rlo, + Register t0, Register t1, Register t2) { + adds(t0, t0, Rlo); + adcs(t1, t1, Rhi); + adc(t2, t2, zr); + } + + public: + /** + * Fast Montgomery multiplication. The derivation of the + * algorithm is in A Cryptographic Library for the Motorola + * DSP56000, Dusse and Kaliski, Proc. EUROCRYPT 90, pp. 230-237. + * + * Arguments: + * + * Inputs for multiplication: + * c_rarg0 - int array elements a + * c_rarg1 - int array elements b + * c_rarg2 - int array elements n (the modulus) + * c_rarg3 - int length + * c_rarg4 - int inv + * c_rarg5 - int array elements m (the result) + * + * Inputs for squaring: + * c_rarg0 - int array elements a + * c_rarg1 - int array elements n (the modulus) + * c_rarg2 - int length + * c_rarg3 - int inv + * c_rarg4 - int array elements m (the result) + * + */ + address generate_multiply() { + Label argh, nothing; + bind(argh); + stop("MontgomeryMultiply total_allocation must be <= 8192"); + + align(CodeEntryAlignment); + address entry = pc(); + + cbzw(Rlen, nothing); + + enter(); + + // Make room. + cmpw(Rlen, 512); + br(Assembler::HI, argh); + sub(Ra, sp, Rlen, ext::uxtw, exact_log2(4 * sizeof (jint))); + andr(sp, Ra, -2 * wordSize); + + lsrw(Rlen, Rlen, 1); // length in longwords = len/2 + + { + // Copy input args, reversing as we go. We use Ra as a + // temporary variable. + reverse(Ra, Pa_base, Rlen, t0, t1); + if (!_squaring) + reverse(Ra, Pb_base, Rlen, t0, t1); + reverse(Ra, Pn_base, Rlen, t0, t1); + } + + // Push all call-saved registers and also Pm_base which we'll need + // at the end. + save_regs(); + +#ifndef PRODUCT + // assert(inv * n[0] == -1UL, "broken inverse in Montgomery multiply"); + { + ldr(Rn, Address(Pn_base, 0)); + mul(Rlo_mn, Rn, inv); + cmp(Rlo_mn, -1); + Label ok; + br(EQ, ok); { + stop("broken inverse in Montgomery multiply"); + } bind(ok); + } +#endif + + mov(Pm_base, Ra); + + mov(t0, zr); + mov(t1, zr); + mov(t2, zr); + + block_comment("for (int i = 0; i < len; i++) {"); + mov(Ri, zr); { + Label loop, end; + cmpw(Ri, Rlen); + br(Assembler::GE, end); + + bind(loop); + pre1(Ri); + + block_comment(" for (j = i; j; j--) {"); { + movw(Rj, Ri); + unroll_2(Rj, &MontgomeryMultiplyGenerator::step); + } block_comment(" } // j"); + + post1(); + addw(Ri, Ri, 1); + cmpw(Ri, Rlen); + br(Assembler::LT, loop); + bind(end); + block_comment("} // i"); + } + + block_comment("for (int i = len; i < 2*len; i++) {"); + mov(Ri, Rlen); { + Label loop, end; + cmpw(Ri, Rlen, Assembler::LSL, 1); + br(Assembler::GE, end); + + bind(loop); + pre2(Ri, Rlen); + + block_comment(" for (j = len*2-i-1; j; j--) {"); { + lslw(Rj, Rlen, 1); + subw(Rj, Rj, Ri); + subw(Rj, Rj, 1); + unroll_2(Rj, &MontgomeryMultiplyGenerator::step); + } block_comment(" } // j"); + + post2(Ri, Rlen); + addw(Ri, Ri, 1); + cmpw(Ri, Rlen, Assembler::LSL, 1); + br(Assembler::LT, loop); + bind(end); + } + block_comment("} // i"); + + normalize(Rlen); + + mov(Ra, Pm_base); // Save Pm_base in Ra + restore_regs(); // Restore caller's Pm_base + + // Copy our result into caller's Pm_base + reverse(Pm_base, Ra, Rlen, t0, t1); + + leave(); + bind(nothing); + ret(lr); + + return entry; + } + // In C, approximately: + + // void + // montgomery_multiply(unsigned long Pa_base[], unsigned long Pb_base[], + // unsigned long Pn_base[], unsigned long Pm_base[], + // unsigned long inv, int len) { + // unsigned long t0 = 0, t1 = 0, t2 = 0; // Triple-precision accumulator + // unsigned long *Pa, *Pb, *Pn, *Pm; + // unsigned long Ra, Rb, Rn, Rm; + + // int i; + + // assert(inv * Pn_base[0] == -1UL, "broken inverse in Montgomery multiply"); + + // for (i = 0; i < len; i++) { + // int j; + + // Pa = Pa_base; + // Pb = Pb_base + i; + // Pm = Pm_base; + // Pn = Pn_base + i; + + // Ra = *Pa; + // Rb = *Pb; + // Rm = *Pm; + // Rn = *Pn; + + // int iters = i; + // for (j = 0; iters--; j++) { + // assert(Ra == Pa_base[j] && Rb == Pb_base[i-j], "must be"); + // MACC(Ra, Rb, t0, t1, t2); + // Ra = *++Pa; + // Rb = *--Pb; + // assert(Rm == Pm_base[j] && Rn == Pn_base[i-j], "must be"); + // MACC(Rm, Rn, t0, t1, t2); + // Rm = *++Pm; + // Rn = *--Pn; + // } + + // assert(Ra == Pa_base[i] && Rb == Pb_base[0], "must be"); + // MACC(Ra, Rb, t0, t1, t2); + // *Pm = Rm = t0 * inv; + // assert(Rm == Pm_base[i] && Rn == Pn_base[0], "must be"); + // MACC(Rm, Rn, t0, t1, t2); + + // assert(t0 == 0, "broken Montgomery multiply"); + + // t0 = t1; t1 = t2; t2 = 0; + // } + + // for (i = len; i < 2*len; i++) { + // int j; + + // Pa = Pa_base + i-len; + // Pb = Pb_base + len; + // Pm = Pm_base + i-len; + // Pn = Pn_base + len; + + // Ra = *++Pa; + // Rb = *--Pb; + // Rm = *++Pm; + // Rn = *--Pn; + + // int iters = len*2-i-1; + // for (j = i-len+1; iters--; j++) { + // assert(Ra == Pa_base[j] && Rb == Pb_base[i-j], "must be"); + // MACC(Ra, Rb, t0, t1, t2); + // Ra = *++Pa; + // Rb = *--Pb; + // assert(Rm == Pm_base[j] && Rn == Pn_base[i-j], "must be"); + // MACC(Rm, Rn, t0, t1, t2); + // Rm = *++Pm; + // Rn = *--Pn; + // } + + // Pm_base[i-len] = t0; + // t0 = t1; t1 = t2; t2 = 0; + // } + + // while (t0) + // t0 = sub(Pm_base, Pn_base, t0, len); + // } + + /** + * Fast Montgomery squaring. This uses asymptotically 25% fewer + * multiplies than Montgomery multiplication so it should be up to + * 25% faster. However, its loop control is more complex and it + * may actually run slower on some machines. + * + * Arguments: + * + * Inputs: + * c_rarg0 - int array elements a + * c_rarg1 - int array elements n (the modulus) + * c_rarg2 - int length + * c_rarg3 - int inv + * c_rarg4 - int array elements m (the result) + * + */ + address generate_square() { + Label argh; + bind(argh); + stop("MontgomeryMultiply total_allocation must be <= 8192"); + + align(CodeEntryAlignment); + address entry = pc(); + + enter(); + + // Make room. + cmpw(Rlen, 512); + br(Assembler::HI, argh); + sub(Ra, sp, Rlen, ext::uxtw, exact_log2(4 * sizeof (jint))); + andr(sp, Ra, -2 * wordSize); + + lsrw(Rlen, Rlen, 1); // length in longwords = len/2 + + { + // Copy input args, reversing as we go. We use Ra as a + // temporary variable. + reverse(Ra, Pa_base, Rlen, t0, t1); + reverse(Ra, Pn_base, Rlen, t0, t1); + } + + // Push all call-saved registers and also Pm_base which we'll need + // at the end. + save_regs(); + + mov(Pm_base, Ra); + + mov(t0, zr); + mov(t1, zr); + mov(t2, zr); + + block_comment("for (int i = 0; i < len; i++) {"); + mov(Ri, zr); { + Label loop, end; + bind(loop); + cmp(Ri, Rlen); + br(Assembler::GE, end); + + pre1(Ri); + + block_comment("for (j = (i+1)/2; j; j--) {"); { + add(Rj, Ri, 1); + lsr(Rj, Rj, 1); + unroll_2(Rj, &MontgomeryMultiplyGenerator::step_squaring); + } block_comment(" } // j"); + + last_squaring(Ri); + + block_comment(" for (j = i/2; j; j--) {"); { + lsr(Rj, Ri, 1); + unroll_2(Rj, &MontgomeryMultiplyGenerator::extra_step_squaring); + } block_comment(" } // j"); + + post1_squaring(); + add(Ri, Ri, 1); + cmp(Ri, Rlen); + br(Assembler::LT, loop); + + bind(end); + block_comment("} // i"); + } + + block_comment("for (int i = len; i < 2*len; i++) {"); + mov(Ri, Rlen); { + Label loop, end; + bind(loop); + cmp(Ri, Rlen, Assembler::LSL, 1); + br(Assembler::GE, end); + + pre2(Ri, Rlen); + + block_comment(" for (j = (2*len-i-1)/2; j; j--) {"); { + lsl(Rj, Rlen, 1); + sub(Rj, Rj, Ri); + sub(Rj, Rj, 1); + lsr(Rj, Rj, 1); + unroll_2(Rj, &MontgomeryMultiplyGenerator::step_squaring); + } block_comment(" } // j"); + + last_squaring(Ri); + + block_comment(" for (j = (2*len-i)/2; j; j--) {"); { + lsl(Rj, Rlen, 1); + sub(Rj, Rj, Ri); + lsr(Rj, Rj, 1); + unroll_2(Rj, &MontgomeryMultiplyGenerator::extra_step_squaring); + } block_comment(" } // j"); + + post2(Ri, Rlen); + add(Ri, Ri, 1); + cmp(Ri, Rlen, Assembler::LSL, 1); + + br(Assembler::LT, loop); + bind(end); + block_comment("} // i"); + } + + normalize(Rlen); + + mov(Ra, Pm_base); // Save Pm_base in Ra + restore_regs(); // Restore caller's Pm_base + + // Copy our result into caller's Pm_base + reverse(Pm_base, Ra, Rlen, t0, t1); + + leave(); + ret(lr); + + return entry; + } + // In C, approximately: + + // void + // montgomery_square(unsigned long Pa_base[], unsigned long Pn_base[], + // unsigned long Pm_base[], unsigned long inv, int len) { + // unsigned long t0 = 0, t1 = 0, t2 = 0; // Triple-precision accumulator + // unsigned long *Pa, *Pb, *Pn, *Pm; + // unsigned long Ra, Rb, Rn, Rm; + + // int i; + + // assert(inv * Pn_base[0] == -1UL, "broken inverse in Montgomery multiply"); + + // for (i = 0; i < len; i++) { + // int j; + + // Pa = Pa_base; + // Pb = Pa_base + i; + // Pm = Pm_base; + // Pn = Pn_base + i; + + // Ra = *Pa; + // Rb = *Pb; + // Rm = *Pm; + // Rn = *Pn; + + // int iters = (i+1)/2; + // for (j = 0; iters--; j++) { + // assert(Ra == Pa_base[j] && Rb == Pa_base[i-j], "must be"); + // MACC2(Ra, Rb, t0, t1, t2); + // Ra = *++Pa; + // Rb = *--Pb; + // assert(Rm == Pm_base[j] && Rn == Pn_base[i-j], "must be"); + // MACC(Rm, Rn, t0, t1, t2); + // Rm = *++Pm; + // Rn = *--Pn; + // } + // if ((i & 1) == 0) { + // assert(Ra == Pa_base[j], "must be"); + // MACC(Ra, Ra, t0, t1, t2); + // } + // iters = i/2; + // assert(iters == i-j, "must be"); + // for (; iters--; j++) { + // assert(Rm == Pm_base[j] && Rn == Pn_base[i-j], "must be"); + // MACC(Rm, Rn, t0, t1, t2); + // Rm = *++Pm; + // Rn = *--Pn; + // } + + // *Pm = Rm = t0 * inv; + // assert(Rm == Pm_base[i] && Rn == Pn_base[0], "must be"); + // MACC(Rm, Rn, t0, t1, t2); + + // assert(t0 == 0, "broken Montgomery multiply"); + + // t0 = t1; t1 = t2; t2 = 0; + // } + + // for (i = len; i < 2*len; i++) { + // int start = i-len+1; + // int end = start + (len - start)/2; + // int j; + + // Pa = Pa_base + i-len; + // Pb = Pa_base + len; + // Pm = Pm_base + i-len; + // Pn = Pn_base + len; + + // Ra = *++Pa; + // Rb = *--Pb; + // Rm = *++Pm; + // Rn = *--Pn; + + // int iters = (2*len-i-1)/2; + // assert(iters == end-start, "must be"); + // for (j = start; iters--; j++) { + // assert(Ra == Pa_base[j] && Rb == Pa_base[i-j], "must be"); + // MACC2(Ra, Rb, t0, t1, t2); + // Ra = *++Pa; + // Rb = *--Pb; + // assert(Rm == Pm_base[j] && Rn == Pn_base[i-j], "must be"); + // MACC(Rm, Rn, t0, t1, t2); + // Rm = *++Pm; + // Rn = *--Pn; + // } + // if ((i & 1) == 0) { + // assert(Ra == Pa_base[j], "must be"); + // MACC(Ra, Ra, t0, t1, t2); + // } + // iters = (2*len-i)/2; + // assert(iters == len-j, "must be"); + // for (; iters--; j++) { + // assert(Rm == Pm_base[j] && Rn == Pn_base[i-j], "must be"); + // MACC(Rm, Rn, t0, t1, t2); + // Rm = *++Pm; + // Rn = *--Pn; + // } + // Pm_base[i-len] = t0; + // t0 = t1; t1 = t2; t2 = 0; + // } + + // while (t0) + // t0 = sub(Pm_base, Pn_base, t0, len); + // } + }; + // Initialization void generate_initial() { // Generate initial stubs and initializes the entry points @@ -2603,7 +3554,26 @@ StubRoutines::_multiplyToLen = generate_multiplyToLen(); } + if (UseMontgomeryMultiplyIntrinsic) { + StubCodeMark mark(this, "StubRoutines", "montgomeryMultiply"); + MontgomeryMultiplyGenerator g(_masm, /*squaring*/false); + StubRoutines::_montgomeryMultiply = g.generate_multiply(); + } + + if (UseMontgomerySquareIntrinsic) { + StubCodeMark mark(this, "StubRoutines", "montgomerySquare"); + MontgomeryMultiplyGenerator g(_masm, /*squaring*/true); + // We use generate_multiply() rather than generate_square() + // because it's faster for the sizes of modulus we care about. + StubRoutines::_montgomerySquare = g.generate_multiply(); + } + #ifndef BUILTIN_SIM + // generate GHASH intrinsics code + if (UseGHASHIntrinsics) { + StubRoutines::_ghash_processBlocks = generate_ghash_processBlocks(); + } + if (UseAESIntrinsics) { StubRoutines::_aescrypt_encryptBlock = generate_aescrypt_encryptBlock(); StubRoutines::_aescrypt_decryptBlock = generate_aescrypt_decryptBlock(); diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -45,6 +45,10 @@ #define HWCAP_AES (1<<3) #endif +#ifndef HWCAP_PMULL +#define HWCAP_PMULL (1<<4) +#endif + #ifndef HWCAP_SHA1 #define HWCAP_SHA1 (1<<5) #endif @@ -190,11 +194,6 @@ } } - if (UseGHASHIntrinsics) { - warning("GHASH intrinsics are not available on this CPU"); - FLAG_SET_DEFAULT(UseGHASHIntrinsics, false); - } - if (FLAG_IS_DEFAULT(UseCRC32Intrinsics)) { UseCRC32Intrinsics = true; } @@ -232,7 +231,7 @@ } } else if (UseSHA256Intrinsics) { warning("Intrinsics for SHA-224 and SHA-256 crypto hash functions not available on this CPU."); - FLAG_SET_DEFAULT(UseSHA1Intrinsics, false); + FLAG_SET_DEFAULT(UseSHA256Intrinsics, false); } if (UseSHA512Intrinsics) { @@ -244,6 +243,15 @@ FLAG_SET_DEFAULT(UseSHA, false); } + if (auxv & HWCAP_PMULL) { + if (FLAG_IS_DEFAULT(UseGHASHIntrinsics)) { + FLAG_SET_DEFAULT(UseGHASHIntrinsics, true); + } + } else if (UseGHASHIntrinsics) { + warning("GHASH intrinsics are not available on this CPU"); + FLAG_SET_DEFAULT(UseGHASHIntrinsics, false); + } + // This machine allows unaligned memory accesses if (FLAG_IS_DEFAULT(UseUnalignedAccesses)) { FLAG_SET_DEFAULT(UseUnalignedAccesses, true); @@ -261,6 +269,13 @@ UsePopCountInstruction = true; } + if (FLAG_IS_DEFAULT(UseMontgomeryMultiplyIntrinsic)) { + UseMontgomeryMultiplyIntrinsic = true; + } + if (FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) { + UseMontgomerySquareIntrinsic = true; + } + #ifdef COMPILER2 if (FLAG_IS_DEFAULT(OptoScheduling)) { OptoScheduling = true; diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/os/aix/vm/os_aix.cpp --- a/hotspot/src/os/aix/vm/os_aix.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/os/aix/vm/os_aix.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -1550,6 +1550,13 @@ LoadedLibraries::print(st); } +void os::get_summary_os_info(char* buf, size_t buflen) { + // There might be something more readable than uname results for AIX. + struct utsname name; + uname(&name); + snprintf(buf, buflen, "%s %s", name.release, name.version); +} + void os::print_os_info(outputStream* st) { st->print("OS:"); @@ -1654,6 +1661,17 @@ } } +// Get a string for the cpuinfo that is a summary of the cpu type +void os::get_summary_cpu_info(char* buf, size_t buflen) { + // This looks good + os::Aix::cpuinfo_t ci; + if (os::Aix::get_cpuinfo(&ci)) { + strncpy(buf, ci.version, buflen); + } else { + strncpy(buf, "AIX", buflen); + } +} + void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) { } diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/os/bsd/vm/os_bsd.cpp --- a/hotspot/src/os/bsd/vm/os_bsd.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -1600,24 +1600,6 @@ return dlsym(handle, name); } - -static bool _print_ascii_file(const char* filename, outputStream* st) { - int fd = ::open(filename, O_RDONLY); - if (fd == -1) { - return false; - } - - char buf[32]; - int bytes; - while ((bytes = ::read(fd, buf, sizeof(buf))) > 0) { - st->print_raw(buf, bytes); - } - - ::close(fd); - - return true; -} - int _print_dll_info_cb(const char * name, address base_address, address top_address, void * param) { outputStream * out = (outputStream *) param; out->print_cr(PTR_FORMAT " \t%s", base_address, name); @@ -1678,15 +1660,38 @@ #endif } +void os::get_summary_os_info(char* buf, size_t buflen) { + // These buffers are small because we want this to be brief + // and not use a lot of stack while generating the hs_err file. + char os[100]; + size_t size = sizeof(os); + int mib_kern[] = { CTL_KERN, KERN_OSTYPE }; + if (sysctl(mib_kern, 2, os, &size, NULL, 0) < 0) { +#ifdef __APPLE__ + strncpy(os, "Darwin", sizeof(os)); +#elif __OpenBSD__ + strncpy(os, "OpenBSD", sizeof(os)); +#else + strncpy(os, "BSD", sizeof(os)); +#endif + } + + char release[100]; + size = sizeof(release); + int mib_release[] = { CTL_KERN, KERN_OSRELEASE }; + if (sysctl(mib_release, 2, release, &size, NULL, 0) < 0) { + // if error, leave blank + strncpy(release, "", sizeof(release)); + } + snprintf(buf, buflen, "%s %s", os, release); +} + void os::print_os_info_brief(outputStream* st) { - st->print("Bsd"); - os::Posix::print_uname_info(st); } void os::print_os_info(outputStream* st) { st->print("OS:"); - st->print("Bsd"); os::Posix::print_uname_info(st); @@ -1699,6 +1704,33 @@ // Nothing to do for now. } +void os::get_summary_cpu_info(char* buf, size_t buflen) { + unsigned int mhz; + size_t size = sizeof(mhz); + int mib[] = { CTL_HW, HW_CPU_FREQ }; + if (sysctl(mib, 2, &mhz, &size, NULL, 0) < 0) { + mhz = 1; // looks like an error but can be divided by + } else { + mhz /= 1000000; // reported in millions + } + + char model[100]; + size = sizeof(model); + int mib_model[] = { CTL_HW, HW_MODEL }; + if (sysctl(mib_model, 2, model, &size, NULL, 0) < 0) { + strncpy(model, cpu_arch, sizeof(model)); + } + + char machine[100]; + size = sizeof(machine); + int mib_machine[] = { CTL_HW, HW_MACHINE }; + if (sysctl(mib_machine, 2, machine, &size, NULL, 0) < 0) { + strncpy(machine, "", sizeof(machine)); + } + + snprintf(buf, buflen, "%s %s %d MHz", model, machine, mhz); +} + void os::print_memory_info(outputStream* st) { st->print("Memory:"); @@ -1709,11 +1741,6 @@ st->print("(" UINT64_FORMAT "k free)", os::available_memory() >> 10); st->cr(); - - // meminfo - st->print("\n/proc/meminfo:\n"); - _print_ascii_file("/proc/meminfo", st); - st->cr(); } void os::print_siginfo(outputStream* st, void* siginfo) { diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/os/linux/vm/os_linux.cpp --- a/hotspot/src/os/linux/vm/os_linux.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/os/linux/vm/os_linux.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -2043,31 +2043,96 @@ // Searching for the debian_version file is the last resort. It contains // an informative string like "6.0.6" or "wheezy/sid". Because of this // "Debian " is printed before the contents of the debian_version file. + +const char* distro_files[] = { + "/etc/oracle-release", + "/etc/mandriva-release", + "/etc/mandrake-release", + "/etc/sun-release", + "/etc/redhat-release", + "/etc/lsb-release", + "/etc/SuSE-release", + "/etc/turbolinux-release", + "/etc/gentoo-release", + "/etc/ltib-release", + "/etc/angstrom-version", + "/etc/system-release", + "/etc/os-release", + NULL }; + void os::Linux::print_distro_info(outputStream* st) { - if (!_print_ascii_file("/etc/oracle-release", st) && - !_print_ascii_file("/etc/mandriva-release", st) && - !_print_ascii_file("/etc/mandrake-release", st) && - !_print_ascii_file("/etc/sun-release", st) && - !_print_ascii_file("/etc/redhat-release", st) && - !_print_ascii_file("/etc/lsb-release", st) && - !_print_ascii_file("/etc/SuSE-release", st) && - !_print_ascii_file("/etc/turbolinux-release", st) && - !_print_ascii_file("/etc/gentoo-release", st) && - !_print_ascii_file("/etc/ltib-release", st) && - !_print_ascii_file("/etc/angstrom-version", st) && - !_print_ascii_file("/etc/system-release", st) && - !_print_ascii_file("/etc/os-release", st)) { - - if (file_exists("/etc/debian_version")) { - st->print("Debian "); - _print_ascii_file("/etc/debian_version", st); - } else { - st->print("Linux"); + for (int i = 0;; i++) { + const char* file = distro_files[i]; + if (file == NULL) { + break; // done } + // If file prints, we found it. + if (_print_ascii_file(file, st)) { + return; + } + } + + if (file_exists("/etc/debian_version")) { + st->print("Debian "); + _print_ascii_file("/etc/debian_version", st); + } else { + st->print("Linux"); } st->cr(); } +static void parse_os_info(char* distro, size_t length, const char* file) { + FILE* fp = fopen(file, "r"); + if (fp != NULL) { + char buf[256]; + // get last line of the file. + while (fgets(buf, sizeof(buf), fp)) { } + // Edit out extra stuff in expected ubuntu format + if (strstr(buf, "DISTRIB_DESCRIPTION=") != NULL) { + char* ptr = strstr(buf, "\""); // the name is in quotes + if (ptr != NULL) { + ptr++; // go beyond first quote + char* nl = strchr(ptr, '\"'); + if (nl != NULL) *nl = '\0'; + strncpy(distro, ptr, length); + } else { + ptr = strstr(buf, "="); + ptr++; // go beyond equals then + char* nl = strchr(ptr, '\n'); + if (nl != NULL) *nl = '\0'; + strncpy(distro, ptr, length); + } + } else { + // if not in expected Ubuntu format, print out whole line minus \n + char* nl = strchr(buf, '\n'); + if (nl != NULL) *nl = '\0'; + strncpy(distro, buf, length); + } + // close distro file + fclose(fp); + } +} + +void os::get_summary_os_info(char* buf, size_t buflen) { + for (int i = 0;; i++) { + const char* file = distro_files[i]; + if (file == NULL) { + break; // ran out of distro_files + } + if (file_exists(file)) { + parse_os_info(buf, buflen, file); + return; + } + } + // special case for debian + if (file_exists("/etc/debian_version")) { + strncpy(buf, "Debian ", buflen); + parse_os_info(&buf[7], buflen-7, "/etc/debian_version"); + } else { + strncpy(buf, "Linux", buflen); + } +} + void os::Linux::print_libversion_info(outputStream* st) { // libc, pthread st->print("libc:"); @@ -2150,6 +2215,48 @@ } } +const char* search_string = IA32_ONLY("model name") AMD64_ONLY("model name") + IA64_ONLY("") SPARC_ONLY("cpu") + ARM32_ONLY("Processor") PPC_ONLY("Processor") AARCH64_ONLY("Processor"); + +// Parses the cpuinfo file for string representing the model name. +void os::get_summary_cpu_info(char* cpuinfo, size_t length) { + FILE* fp = fopen("/proc/cpuinfo", "r"); + if (fp != NULL) { + while (!feof(fp)) { + char buf[256]; + if (fgets(buf, sizeof(buf), fp)) { + char* start = strstr(buf, search_string); + if (start != NULL) { + char *ptr = start + strlen(search_string); + char *end = buf + strlen(buf); + while (ptr != end) { + // skip whitespace and colon for the rest of the name. + if (*ptr != ' ' && *ptr != '\t' && *ptr != ':') { + break; + } + ptr++; + } + if (ptr != end) { + // reasonable string, get rid of newline and keep the rest + char* nl = strchr(buf, '\n'); + if (nl != NULL) *nl = '\0'; + strncpy(cpuinfo, ptr, length); + fclose(fp); + return; + } + } + } + } + fclose(fp); + } + // cpuinfo not found or parsing failed, just print generic string. The entire + // /proc/cpuinfo file will be printed later in the file (or enough of it for x86) + strncpy(cpuinfo, IA32_ONLY("x86_32") AMD64_ONLY("x86_32") + IA64_ONLY("IA64") SPARC_ONLY("sparcv9") + ARM32_ONLY("ARM") PPC_ONLY("PPC64") AARCH64_ONLY("AArch64"), length); +} + void os::print_siginfo(outputStream* st, void* siginfo) { const siginfo_t* si = (const siginfo_t*)siginfo; diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/os/posix/vm/os_posix.cpp --- a/hotspot/src/os/posix/vm/os_posix.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/os/posix/vm/os_posix.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -236,6 +236,15 @@ st->cr(); } +#ifndef PRODUCT +bool os::get_host_name(char* buf, size_t buflen) { + struct utsname name; + uname(&name); + jio_snprintf(buf, buflen, "%s", name.nodename); + return true; +} +#endif // PRODUCT + bool os::has_allocatable_memory_limit(julong* limit) { struct rlimit rlim; int getrlimit_res = getrlimit(RLIMIT_AS, &rlim); @@ -1070,7 +1079,7 @@ return ret == 0; } -bool PosixSemaphore::timedwait(const struct timespec ts) { +bool PosixSemaphore::timedwait(struct timespec ts) { while (true) { int result = sem_timedwait(&_semaphore, &ts); if (result == 0) { diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/os/solaris/vm/os_solaris.cpp --- a/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -1971,6 +1971,26 @@ st->cr(); } +void os::get_summary_os_info(char* buf, size_t buflen) { + strncpy(buf, "Solaris", buflen); // default to plain solaris + FILE* fp = fopen("/etc/release", "r"); + if (fp != NULL) { + char tmp[256]; + // Only get the first line and chop out everything but the os name. + if (fgets(tmp, sizeof(tmp), fp)) { + char* ptr = tmp; + // skip past whitespace characters + while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t' || *ptr == '\n')) ptr++; + if (*ptr != '\0') { + char* nl = strchr(ptr, '\n'); + if (nl != NULL) *nl = '\0'; + strncpy(buf, ptr, buflen); + } + } + fclose(fp); + } +} + void os::Solaris::print_libversion_info(outputStream* st) { st->print(" (T2 libthread)"); st->cr(); @@ -1998,6 +2018,22 @@ return status; } +void os::get_summary_cpu_info(char* buf, size_t buflen) { + // Get MHz with system call. We don't seem to already have this. + processor_info_t stats; + processorid_t id = getcpuid(); + int clock = 0; + if (processor_info(id, &stats) != -1) { + clock = stats.pi_clock; // pi_processor_type isn't more informative than below + } +#ifdef AMD64 + snprintf(buf, buflen, "x86 64 bit %d MHz", clock); +#else + // must be sparc + snprintf(buf, buflen, "Sparcv9 64 bit %d MHz", clock); +#endif +} + void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) { // Nothing to do for now. } diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/os/windows/vm/os_windows.cpp --- a/hotspot/src/os/windows/vm/os_windows.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/os/windows/vm/os_windows.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -1593,6 +1593,21 @@ return result; } +#ifndef PRODUCT +bool os::get_host_name(char* buf, size_t buflen) { + DWORD size = (DWORD)buflen; + return (GetComputerNameEx(ComputerNameDnsHostname, buf, &size) == TRUE); +} +#endif // PRODUCT + +void os::get_summary_os_info(char* buf, size_t buflen) { + stringStream sst(buf, buflen); + os::win32::print_windows_version(&sst); + // chop off newline character + char* nl = strchr(buf, '\n'); + if (nl != NULL) *nl = '\0'; +} + void os::print_os_info_brief(outputStream* st) { os::print_os_info(st); } @@ -1600,15 +1615,14 @@ void os::print_os_info(outputStream* st) { #ifdef ASSERT char buffer[1024]; - DWORD size = sizeof(buffer); - st->print(" HostName: "); - if (GetComputerNameEx(ComputerNameDnsHostname, buffer, &size)) { - st->print("%s", buffer); + st->print("HostName: "); + if (get_host_name(buffer, sizeof(buffer))) { + st->print("%s ", buffer); } else { - st->print("N/A"); + st->print("N/A "); } #endif - st->print(" OS:"); + st->print("OS:"); os::win32::print_windows_version(st); } @@ -1738,6 +1752,23 @@ // Nothing to do for now. } +void os::get_summary_cpu_info(char* buf, size_t buflen) { + HKEY key; + DWORD status = RegOpenKey(HKEY_LOCAL_MACHINE, + "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", &key); + if (status == ERROR_SUCCESS) { + DWORD size = (DWORD)buflen; + status = RegQueryValueEx(key, "ProcessorNameString", NULL, NULL, (byte*)buf, &size); + if (status != ERROR_SUCCESS) { + strncpy(buf, "## __CPU__", buflen); + } + RegCloseKey(key); + } else { + // Put generic cpu info to return + strncpy(buf, "## __CPU__", buflen); + } +} + void os::print_memory_info(outputStream* st) { st->print("Memory:"); st->print(" %dk page", os::vm_page_size()>>10); diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/c1/c1_Compiler.cpp --- a/hotspot/src/share/vm/c1/c1_Compiler.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/c1/c1_Compiler.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -99,6 +99,164 @@ return buffer_blob; } +bool Compiler::is_intrinsic_supported(methodHandle method) { + vmIntrinsics::ID id = method->intrinsic_id(); + assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); + + if (method->is_synchronized()) { + // C1 does not support intrinsification of synchronized methods. + return false; + } + + switch (id) { + case vmIntrinsics::_compareAndSwapLong: + if (!VM_Version::supports_cx8()) return false; + break; + case vmIntrinsics::_getAndAddInt: + if (!VM_Version::supports_atomic_getadd4()) return false; + break; + case vmIntrinsics::_getAndAddLong: + if (!VM_Version::supports_atomic_getadd8()) return false; + break; + case vmIntrinsics::_getAndSetInt: + if (!VM_Version::supports_atomic_getset4()) return false; + break; + case vmIntrinsics::_getAndSetLong: + if (!VM_Version::supports_atomic_getset8()) return false; + break; + case vmIntrinsics::_getAndSetObject: +#ifdef _LP64 + if (!UseCompressedOops && !VM_Version::supports_atomic_getset8()) return false; + if (UseCompressedOops && !VM_Version::supports_atomic_getset4()) return false; +#else + if (!VM_Version::supports_atomic_getset4()) return false; +#endif + break; + case vmIntrinsics::_arraycopy: + case vmIntrinsics::_currentTimeMillis: + case vmIntrinsics::_nanoTime: + case vmIntrinsics::_Reference_get: + // Use the intrinsic version of Reference.get() so that the value in + // the referent field can be registered by the G1 pre-barrier code. + // Also to prevent commoning reads from this field across safepoint + // since GC can change its value. + case vmIntrinsics::_loadFence: + case vmIntrinsics::_storeFence: + case vmIntrinsics::_fullFence: + case vmIntrinsics::_floatToRawIntBits: + case vmIntrinsics::_intBitsToFloat: + case vmIntrinsics::_doubleToRawLongBits: + case vmIntrinsics::_longBitsToDouble: + case vmIntrinsics::_getClass: + case vmIntrinsics::_isInstance: + case vmIntrinsics::_currentThread: + case vmIntrinsics::_dabs: + case vmIntrinsics::_dsqrt: + case vmIntrinsics::_dsin: + case vmIntrinsics::_dcos: + case vmIntrinsics::_dtan: + case vmIntrinsics::_dlog: + case vmIntrinsics::_dlog10: + case vmIntrinsics::_dexp: + case vmIntrinsics::_dpow: + case vmIntrinsics::_getObject: + case vmIntrinsics::_getBoolean: + case vmIntrinsics::_getByte: + case vmIntrinsics::_getShort: + case vmIntrinsics::_getChar: + case vmIntrinsics::_getInt: + case vmIntrinsics::_getLong: + case vmIntrinsics::_getFloat: + case vmIntrinsics::_getDouble: + case vmIntrinsics::_putObject: + case vmIntrinsics::_putBoolean: + case vmIntrinsics::_putByte: + case vmIntrinsics::_putShort: + case vmIntrinsics::_putChar: + case vmIntrinsics::_putInt: + case vmIntrinsics::_putLong: + case vmIntrinsics::_putFloat: + case vmIntrinsics::_putDouble: + case vmIntrinsics::_getObjectVolatile: + case vmIntrinsics::_getBooleanVolatile: + case vmIntrinsics::_getByteVolatile: + case vmIntrinsics::_getShortVolatile: + case vmIntrinsics::_getCharVolatile: + case vmIntrinsics::_getIntVolatile: + case vmIntrinsics::_getLongVolatile: + case vmIntrinsics::_getFloatVolatile: + case vmIntrinsics::_getDoubleVolatile: + case vmIntrinsics::_putObjectVolatile: + case vmIntrinsics::_putBooleanVolatile: + case vmIntrinsics::_putByteVolatile: + case vmIntrinsics::_putShortVolatile: + case vmIntrinsics::_putCharVolatile: + case vmIntrinsics::_putIntVolatile: + case vmIntrinsics::_putLongVolatile: + case vmIntrinsics::_putFloatVolatile: + case vmIntrinsics::_putDoubleVolatile: + case vmIntrinsics::_getByte_raw: + case vmIntrinsics::_getShort_raw: + case vmIntrinsics::_getChar_raw: + case vmIntrinsics::_getInt_raw: + case vmIntrinsics::_getLong_raw: + case vmIntrinsics::_getFloat_raw: + case vmIntrinsics::_getDouble_raw: + case vmIntrinsics::_putByte_raw: + case vmIntrinsics::_putShort_raw: + case vmIntrinsics::_putChar_raw: + case vmIntrinsics::_putInt_raw: + case vmIntrinsics::_putLong_raw: + case vmIntrinsics::_putFloat_raw: + case vmIntrinsics::_putDouble_raw: + case vmIntrinsics::_putOrderedObject: + case vmIntrinsics::_putOrderedInt: + case vmIntrinsics::_putOrderedLong: + case vmIntrinsics::_getShortUnaligned: + case vmIntrinsics::_getCharUnaligned: + case vmIntrinsics::_getIntUnaligned: + case vmIntrinsics::_getLongUnaligned: + case vmIntrinsics::_putShortUnaligned: + case vmIntrinsics::_putCharUnaligned: + case vmIntrinsics::_putIntUnaligned: + case vmIntrinsics::_putLongUnaligned: + case vmIntrinsics::_checkIndex: + case vmIntrinsics::_updateCRC32: + case vmIntrinsics::_updateBytesCRC32: + case vmIntrinsics::_updateByteBufferCRC32: + case vmIntrinsics::_compareAndSwapInt: + case vmIntrinsics::_compareAndSwapObject: +#ifdef TRACE_HAVE_INTRINSICS + case vmIntrinsics::_classID: + case vmIntrinsics::_threadID: + case vmIntrinsics::_counterTime: +#endif + break; + default: + return false; // Intrinsics not on the previous list are not available. + } + + return true; +} + +bool Compiler::is_intrinsic_disabled_by_flag(methodHandle method) { + vmIntrinsics::ID id = method->intrinsic_id(); + assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); + + if (vmIntrinsics::is_disabled_by_flags(id)) { + return true; + } + + if (!InlineNatives && id != vmIntrinsics::_Reference_get) { + return true; + } + + if (!InlineClassNatives && id == vmIntrinsics::_getClass) { + return true; + } + + return false; +} void Compiler::compile_method(ciEnv* env, ciMethod* method, int entry_bci) { BufferBlob* buffer_blob = CompilerThread::current()->get_buffer_blob(); @@ -117,3 +275,7 @@ void Compiler::print_timers() { Compilation::print_timers(); } + +bool Compiler::is_intrinsic_available(methodHandle method, methodHandle compilation_context) { + return is_intrinsic_supported(method) && !is_intrinsic_disabled_by_flag(method); +} diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/c1/c1_Compiler.hpp --- a/hotspot/src/share/vm/c1/c1_Compiler.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/c1/c1_Compiler.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -55,6 +55,18 @@ // Print compilation timers and statistics virtual void print_timers(); + // Check the availability of an intrinsic for 'method' given a compilation context. + // The compilation context is needed to support per-method usage of the + // DisableIntrinsic flag. However, as C1 ignores the DisableIntrinsic flag, it + // ignores the compilation context. + virtual bool is_intrinsic_available(methodHandle method, methodHandle compilation_context); + + // Check if the C1 compiler supports an intrinsic for 'method'. + virtual bool is_intrinsic_supported(methodHandle method); + + // Processing of command-line flags specific to the C1 compiler. + virtual bool is_intrinsic_disabled_by_flag(methodHandle method); + // Size of the code buffer static int code_buffer_size(); }; diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/c1/c1_GraphBuilder.cpp --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -3372,231 +3372,85 @@ return NULL; } - -bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) { - if (callee->is_synchronized()) { - // We don't currently support any synchronized intrinsics - return false; - } - - // callee seems like a good candidate - // determine id +void GraphBuilder::build_graph_for_intrinsic(ciMethod* callee) { vmIntrinsics::ID id = callee->intrinsic_id(); - if (!InlineNatives && id != vmIntrinsics::_Reference_get) { - // InlineNatives does not control Reference.get - INLINE_BAILOUT("intrinsic method inlining disabled"); + assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); + + // Some intrinsics need special IR nodes. + switch(id) { + case vmIntrinsics::_getObject : append_unsafe_get_obj(callee, T_OBJECT, false); return; + case vmIntrinsics::_getBoolean : append_unsafe_get_obj(callee, T_BOOLEAN, false); return; + case vmIntrinsics::_getByte : append_unsafe_get_obj(callee, T_BYTE, false); return; + case vmIntrinsics::_getShort : append_unsafe_get_obj(callee, T_SHORT, false); return; + case vmIntrinsics::_getChar : append_unsafe_get_obj(callee, T_CHAR, false); return; + case vmIntrinsics::_getInt : append_unsafe_get_obj(callee, T_INT, false); return; + case vmIntrinsics::_getLong : append_unsafe_get_obj(callee, T_LONG, false); return; + case vmIntrinsics::_getFloat : append_unsafe_get_obj(callee, T_FLOAT, false); return; + case vmIntrinsics::_getDouble : append_unsafe_get_obj(callee, T_DOUBLE, false); return; + case vmIntrinsics::_putObject : append_unsafe_put_obj(callee, T_OBJECT, false); return; + case vmIntrinsics::_putBoolean : append_unsafe_put_obj(callee, T_BOOLEAN, false); return; + case vmIntrinsics::_putByte : append_unsafe_put_obj(callee, T_BYTE, false); return; + case vmIntrinsics::_putShort : append_unsafe_put_obj(callee, T_SHORT, false); return; + case vmIntrinsics::_putChar : append_unsafe_put_obj(callee, T_CHAR, false); return; + case vmIntrinsics::_putInt : append_unsafe_put_obj(callee, T_INT, false); return; + case vmIntrinsics::_putLong : append_unsafe_put_obj(callee, T_LONG, false); return; + case vmIntrinsics::_putFloat : append_unsafe_put_obj(callee, T_FLOAT, false); return; + case vmIntrinsics::_putDouble : append_unsafe_put_obj(callee, T_DOUBLE, false); return; + case vmIntrinsics::_getShortUnaligned : append_unsafe_get_obj(callee, T_SHORT, false); return; + case vmIntrinsics::_getCharUnaligned : append_unsafe_get_obj(callee, T_CHAR, false); return; + case vmIntrinsics::_getIntUnaligned : append_unsafe_get_obj(callee, T_INT, false); return; + case vmIntrinsics::_getLongUnaligned : append_unsafe_get_obj(callee, T_LONG, false); return; + case vmIntrinsics::_putShortUnaligned : append_unsafe_put_obj(callee, T_SHORT, false); return; + case vmIntrinsics::_putCharUnaligned : append_unsafe_put_obj(callee, T_CHAR, false); return; + case vmIntrinsics::_putIntUnaligned : append_unsafe_put_obj(callee, T_INT, false); return; + case vmIntrinsics::_putLongUnaligned : append_unsafe_put_obj(callee, T_LONG, false); return; + case vmIntrinsics::_getObjectVolatile : append_unsafe_get_obj(callee, T_OBJECT, true); return; + case vmIntrinsics::_getBooleanVolatile : append_unsafe_get_obj(callee, T_BOOLEAN, true); return; + case vmIntrinsics::_getByteVolatile : append_unsafe_get_obj(callee, T_BYTE, true); return; + case vmIntrinsics::_getShortVolatile : append_unsafe_get_obj(callee, T_SHORT, true); return; + case vmIntrinsics::_getCharVolatile : append_unsafe_get_obj(callee, T_CHAR, true); return; + case vmIntrinsics::_getIntVolatile : append_unsafe_get_obj(callee, T_INT, true); return; + case vmIntrinsics::_getLongVolatile : append_unsafe_get_obj(callee, T_LONG, true); return; + case vmIntrinsics::_getFloatVolatile : append_unsafe_get_obj(callee, T_FLOAT, true); return; + case vmIntrinsics::_getDoubleVolatile : append_unsafe_get_obj(callee, T_DOUBLE, true); return; + case vmIntrinsics::_putObjectVolatile : append_unsafe_put_obj(callee, T_OBJECT, true); return; + case vmIntrinsics::_putBooleanVolatile : append_unsafe_put_obj(callee, T_BOOLEAN, true); return; + case vmIntrinsics::_putByteVolatile : append_unsafe_put_obj(callee, T_BYTE, true); return; + case vmIntrinsics::_putShortVolatile : append_unsafe_put_obj(callee, T_SHORT, true); return; + case vmIntrinsics::_putCharVolatile : append_unsafe_put_obj(callee, T_CHAR, true); return; + case vmIntrinsics::_putIntVolatile : append_unsafe_put_obj(callee, T_INT, true); return; + case vmIntrinsics::_putLongVolatile : append_unsafe_put_obj(callee, T_LONG, true); return; + case vmIntrinsics::_putFloatVolatile : append_unsafe_put_obj(callee, T_FLOAT, true); return; + case vmIntrinsics::_putDoubleVolatile : append_unsafe_put_obj(callee, T_DOUBLE, true); return; + case vmIntrinsics::_getByte_raw : append_unsafe_get_raw(callee, T_BYTE ); return; + case vmIntrinsics::_getShort_raw : append_unsafe_get_raw(callee, T_SHORT ); return; + case vmIntrinsics::_getChar_raw : append_unsafe_get_raw(callee, T_CHAR ); return; + case vmIntrinsics::_getInt_raw : append_unsafe_get_raw(callee, T_INT ); return; + case vmIntrinsics::_getLong_raw : append_unsafe_get_raw(callee, T_LONG ); return; + case vmIntrinsics::_getFloat_raw : append_unsafe_get_raw(callee, T_FLOAT ); return; + case vmIntrinsics::_getDouble_raw : append_unsafe_get_raw(callee, T_DOUBLE); return; + case vmIntrinsics::_putByte_raw : append_unsafe_put_raw(callee, T_BYTE ); return; + case vmIntrinsics::_putShort_raw : append_unsafe_put_raw(callee, T_SHORT ); return; + case vmIntrinsics::_putChar_raw : append_unsafe_put_raw(callee, T_CHAR ); return; + case vmIntrinsics::_putInt_raw : append_unsafe_put_raw(callee, T_INT ); return; + case vmIntrinsics::_putLong_raw : append_unsafe_put_raw(callee, T_LONG ); return; + case vmIntrinsics::_putFloat_raw : append_unsafe_put_raw(callee, T_FLOAT ); return; + case vmIntrinsics::_putDouble_raw : append_unsafe_put_raw(callee, T_DOUBLE); return; + case vmIntrinsics::_putOrderedObject : append_unsafe_put_obj(callee, T_OBJECT, true); return; + case vmIntrinsics::_putOrderedInt : append_unsafe_put_obj(callee, T_INT, true); return; + case vmIntrinsics::_putOrderedLong : append_unsafe_put_obj(callee, T_LONG, true); return; + case vmIntrinsics::_compareAndSwapLong: + case vmIntrinsics::_compareAndSwapInt: + case vmIntrinsics::_compareAndSwapObject: append_unsafe_CAS(callee); return; + case vmIntrinsics::_getAndAddInt: + case vmIntrinsics::_getAndAddLong : append_unsafe_get_and_set_obj(callee, true); return; + case vmIntrinsics::_getAndSetInt : + case vmIntrinsics::_getAndSetLong : + case vmIntrinsics::_getAndSetObject : append_unsafe_get_and_set_obj(callee, false); return; + default: + break; } - bool preserves_state = false; - bool cantrap = true; - switch (id) { - case vmIntrinsics::_arraycopy: - if (!InlineArrayCopy) return false; - break; - -#ifdef TRACE_HAVE_INTRINSICS - case vmIntrinsics::_classID: - case vmIntrinsics::_threadID: - preserves_state = true; - cantrap = true; - break; - - case vmIntrinsics::_counterTime: - preserves_state = true; - cantrap = false; - break; -#endif - - case vmIntrinsics::_currentTimeMillis: - case vmIntrinsics::_nanoTime: - preserves_state = true; - cantrap = false; - break; - - case vmIntrinsics::_floatToRawIntBits : - case vmIntrinsics::_intBitsToFloat : - case vmIntrinsics::_doubleToRawLongBits : - case vmIntrinsics::_longBitsToDouble : - if (!InlineMathNatives) return false; - preserves_state = true; - cantrap = false; - break; - - case vmIntrinsics::_getClass : - case vmIntrinsics::_isInstance : - if (!InlineClassNatives) return false; - preserves_state = true; - break; - - case vmIntrinsics::_currentThread : - if (!InlineThreadNatives) return false; - preserves_state = true; - cantrap = false; - break; - - case vmIntrinsics::_dabs : // fall through - case vmIntrinsics::_dsqrt : // fall through - case vmIntrinsics::_dsin : // fall through - case vmIntrinsics::_dcos : // fall through - case vmIntrinsics::_dtan : // fall through - case vmIntrinsics::_dlog : // fall through - case vmIntrinsics::_dlog10 : // fall through - case vmIntrinsics::_dexp : // fall through - case vmIntrinsics::_dpow : // fall through - if (!InlineMathNatives) return false; - cantrap = false; - preserves_state = true; - break; - - // Use special nodes for Unsafe instructions so we can more easily - // perform an address-mode optimization on the raw variants - case vmIntrinsics::_getObject : return append_unsafe_get_obj(callee, T_OBJECT, false); - case vmIntrinsics::_getBoolean: return append_unsafe_get_obj(callee, T_BOOLEAN, false); - case vmIntrinsics::_getByte : return append_unsafe_get_obj(callee, T_BYTE, false); - case vmIntrinsics::_getShort : return append_unsafe_get_obj(callee, T_SHORT, false); - case vmIntrinsics::_getChar : return append_unsafe_get_obj(callee, T_CHAR, false); - case vmIntrinsics::_getInt : return append_unsafe_get_obj(callee, T_INT, false); - case vmIntrinsics::_getLong : return append_unsafe_get_obj(callee, T_LONG, false); - case vmIntrinsics::_getFloat : return append_unsafe_get_obj(callee, T_FLOAT, false); - case vmIntrinsics::_getDouble : return append_unsafe_get_obj(callee, T_DOUBLE, false); - - case vmIntrinsics::_putObject : return append_unsafe_put_obj(callee, T_OBJECT, false); - case vmIntrinsics::_putBoolean: return append_unsafe_put_obj(callee, T_BOOLEAN, false); - case vmIntrinsics::_putByte : return append_unsafe_put_obj(callee, T_BYTE, false); - case vmIntrinsics::_putShort : return append_unsafe_put_obj(callee, T_SHORT, false); - case vmIntrinsics::_putChar : return append_unsafe_put_obj(callee, T_CHAR, false); - case vmIntrinsics::_putInt : return append_unsafe_put_obj(callee, T_INT, false); - case vmIntrinsics::_putLong : return append_unsafe_put_obj(callee, T_LONG, false); - case vmIntrinsics::_putFloat : return append_unsafe_put_obj(callee, T_FLOAT, false); - case vmIntrinsics::_putDouble : return append_unsafe_put_obj(callee, T_DOUBLE, false); - - case vmIntrinsics::_getShortUnaligned : - return UseUnalignedAccesses ? append_unsafe_get_obj(callee, T_SHORT, false) : false; - case vmIntrinsics::_getCharUnaligned : - return UseUnalignedAccesses ? append_unsafe_get_obj(callee, T_CHAR, false) : false; - case vmIntrinsics::_getIntUnaligned : - return UseUnalignedAccesses ? append_unsafe_get_obj(callee, T_INT, false) : false; - case vmIntrinsics::_getLongUnaligned : - return UseUnalignedAccesses ? append_unsafe_get_obj(callee, T_LONG, false) : false; - - case vmIntrinsics::_putShortUnaligned : - return UseUnalignedAccesses ? append_unsafe_put_obj(callee, T_SHORT, false) : false; - case vmIntrinsics::_putCharUnaligned : - return UseUnalignedAccesses ? append_unsafe_put_obj(callee, T_CHAR, false) : false; - case vmIntrinsics::_putIntUnaligned : - return UseUnalignedAccesses ? append_unsafe_put_obj(callee, T_INT, false) : false; - case vmIntrinsics::_putLongUnaligned : - return UseUnalignedAccesses ? append_unsafe_put_obj(callee, T_LONG, false) : false; - - case vmIntrinsics::_getObjectVolatile : return append_unsafe_get_obj(callee, T_OBJECT, true); - case vmIntrinsics::_getBooleanVolatile: return append_unsafe_get_obj(callee, T_BOOLEAN, true); - case vmIntrinsics::_getByteVolatile : return append_unsafe_get_obj(callee, T_BYTE, true); - case vmIntrinsics::_getShortVolatile : return append_unsafe_get_obj(callee, T_SHORT, true); - case vmIntrinsics::_getCharVolatile : return append_unsafe_get_obj(callee, T_CHAR, true); - case vmIntrinsics::_getIntVolatile : return append_unsafe_get_obj(callee, T_INT, true); - case vmIntrinsics::_getLongVolatile : return append_unsafe_get_obj(callee, T_LONG, true); - case vmIntrinsics::_getFloatVolatile : return append_unsafe_get_obj(callee, T_FLOAT, true); - case vmIntrinsics::_getDoubleVolatile : return append_unsafe_get_obj(callee, T_DOUBLE, true); - - case vmIntrinsics::_putObjectVolatile : return append_unsafe_put_obj(callee, T_OBJECT, true); - case vmIntrinsics::_putBooleanVolatile: return append_unsafe_put_obj(callee, T_BOOLEAN, true); - case vmIntrinsics::_putByteVolatile : return append_unsafe_put_obj(callee, T_BYTE, true); - case vmIntrinsics::_putShortVolatile : return append_unsafe_put_obj(callee, T_SHORT, true); - case vmIntrinsics::_putCharVolatile : return append_unsafe_put_obj(callee, T_CHAR, true); - case vmIntrinsics::_putIntVolatile : return append_unsafe_put_obj(callee, T_INT, true); - case vmIntrinsics::_putLongVolatile : return append_unsafe_put_obj(callee, T_LONG, true); - case vmIntrinsics::_putFloatVolatile : return append_unsafe_put_obj(callee, T_FLOAT, true); - case vmIntrinsics::_putDoubleVolatile : return append_unsafe_put_obj(callee, T_DOUBLE, true); - - case vmIntrinsics::_getByte_raw : return append_unsafe_get_raw(callee, T_BYTE); - case vmIntrinsics::_getShort_raw : return append_unsafe_get_raw(callee, T_SHORT); - case vmIntrinsics::_getChar_raw : return append_unsafe_get_raw(callee, T_CHAR); - case vmIntrinsics::_getInt_raw : return append_unsafe_get_raw(callee, T_INT); - case vmIntrinsics::_getLong_raw : return append_unsafe_get_raw(callee, T_LONG); - case vmIntrinsics::_getFloat_raw : return append_unsafe_get_raw(callee, T_FLOAT); - case vmIntrinsics::_getDouble_raw : return append_unsafe_get_raw(callee, T_DOUBLE); - - case vmIntrinsics::_putByte_raw : return append_unsafe_put_raw(callee, T_BYTE); - case vmIntrinsics::_putShort_raw : return append_unsafe_put_raw(callee, T_SHORT); - case vmIntrinsics::_putChar_raw : return append_unsafe_put_raw(callee, T_CHAR); - case vmIntrinsics::_putInt_raw : return append_unsafe_put_raw(callee, T_INT); - case vmIntrinsics::_putLong_raw : return append_unsafe_put_raw(callee, T_LONG); - case vmIntrinsics::_putFloat_raw : return append_unsafe_put_raw(callee, T_FLOAT); - case vmIntrinsics::_putDouble_raw : return append_unsafe_put_raw(callee, T_DOUBLE); - - case vmIntrinsics::_checkIndex : - if (!InlineNIOCheckIndex) return false; - preserves_state = true; - break; - case vmIntrinsics::_putOrderedObject : return append_unsafe_put_obj(callee, T_OBJECT, true); - case vmIntrinsics::_putOrderedInt : return append_unsafe_put_obj(callee, T_INT, true); - case vmIntrinsics::_putOrderedLong : return append_unsafe_put_obj(callee, T_LONG, true); - - case vmIntrinsics::_compareAndSwapLong: - if (!VM_Version::supports_cx8()) return false; - // fall through - case vmIntrinsics::_compareAndSwapInt: - case vmIntrinsics::_compareAndSwapObject: - append_unsafe_CAS(callee); - return true; - - case vmIntrinsics::_getAndAddInt: - if (!VM_Version::supports_atomic_getadd4()) { - return false; - } - return append_unsafe_get_and_set_obj(callee, true); - case vmIntrinsics::_getAndAddLong: - if (!VM_Version::supports_atomic_getadd8()) { - return false; - } - return append_unsafe_get_and_set_obj(callee, true); - case vmIntrinsics::_getAndSetInt: - if (!VM_Version::supports_atomic_getset4()) { - return false; - } - return append_unsafe_get_and_set_obj(callee, false); - case vmIntrinsics::_getAndSetLong: - if (!VM_Version::supports_atomic_getset8()) { - return false; - } - return append_unsafe_get_and_set_obj(callee, false); - case vmIntrinsics::_getAndSetObject: -#ifdef _LP64 - if (!UseCompressedOops && !VM_Version::supports_atomic_getset8()) { - return false; - } - if (UseCompressedOops && !VM_Version::supports_atomic_getset4()) { - return false; - } -#else - if (!VM_Version::supports_atomic_getset4()) { - return false; - } -#endif - return append_unsafe_get_and_set_obj(callee, false); - - case vmIntrinsics::_Reference_get: - // Use the intrinsic version of Reference.get() so that the value in - // the referent field can be registered by the G1 pre-barrier code. - // Also to prevent commoning reads from this field across safepoint - // since GC can change its value. - preserves_state = true; - break; - - case vmIntrinsics::_updateCRC32: - case vmIntrinsics::_updateBytesCRC32: - case vmIntrinsics::_updateByteBufferCRC32: - if (!UseCRC32Intrinsics) return false; - cantrap = false; - preserves_state = true; - break; - - case vmIntrinsics::_loadFence : - case vmIntrinsics::_storeFence: - case vmIntrinsics::_fullFence : - break; - - default : return false; // do not inline - } + // create intrinsic node const bool has_receiver = !callee->is_static(); ValueType* result_type = as_ValueType(callee->return_type()); @@ -3621,8 +3475,10 @@ } } - Intrinsic* result = new Intrinsic(result_type, id, args, has_receiver, state_before, - preserves_state, cantrap); + Intrinsic* result = new Intrinsic(result_type, callee->intrinsic_id(), + args, has_receiver, state_before, + vmIntrinsics::preserves_state(id), + vmIntrinsics::can_trap(id)); // append instruction & push result Value value = append_split(result); if (result_type != voidType) push(result_type, value); @@ -3630,8 +3486,22 @@ if (callee != method() && profile_return() && result_type->is_object_kind()) { profile_return_type(result, callee); } - - // done +} + +bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) { + // For calling is_intrinsic_available we need to transition to + // the '_thread_in_vm' state because is_intrinsic_available() + // does not accesses critical VM-internal data. + if (!_compilation->compiler()->is_intrinsic_available(callee->get_Method(), NULL)) { + if (!InlineNatives) { + // Return false and also set message that the inlining of + // intrinsics has been disabled in general. + INLINE_BAILOUT("intrinsic method inlining disabled"); + } else { + return false; + } + } + build_graph_for_intrinsic(callee); return true; } @@ -4224,58 +4094,46 @@ _scope_data = scope_data()->parent(); } -bool GraphBuilder::append_unsafe_get_obj(ciMethod* callee, BasicType t, bool is_volatile) { - if (InlineUnsafeOps) { - Values* args = state()->pop_arguments(callee->arg_size()); - null_check(args->at(0)); - Instruction* offset = args->at(2); +void GraphBuilder::append_unsafe_get_obj(ciMethod* callee, BasicType t, bool is_volatile) { + Values* args = state()->pop_arguments(callee->arg_size()); + null_check(args->at(0)); + Instruction* offset = args->at(2); #ifndef _LP64 - offset = append(new Convert(Bytecodes::_l2i, offset, as_ValueType(T_INT))); + offset = append(new Convert(Bytecodes::_l2i, offset, as_ValueType(T_INT))); #endif - Instruction* op = append(new UnsafeGetObject(t, args->at(1), offset, is_volatile)); - push(op->type(), op); - compilation()->set_has_unsafe_access(true); - } - return InlineUnsafeOps; + Instruction* op = append(new UnsafeGetObject(t, args->at(1), offset, is_volatile)); + push(op->type(), op); + compilation()->set_has_unsafe_access(true); } -bool GraphBuilder::append_unsafe_put_obj(ciMethod* callee, BasicType t, bool is_volatile) { - if (InlineUnsafeOps) { - Values* args = state()->pop_arguments(callee->arg_size()); - null_check(args->at(0)); - Instruction* offset = args->at(2); +void GraphBuilder::append_unsafe_put_obj(ciMethod* callee, BasicType t, bool is_volatile) { + Values* args = state()->pop_arguments(callee->arg_size()); + null_check(args->at(0)); + Instruction* offset = args->at(2); #ifndef _LP64 - offset = append(new Convert(Bytecodes::_l2i, offset, as_ValueType(T_INT))); + offset = append(new Convert(Bytecodes::_l2i, offset, as_ValueType(T_INT))); #endif - Instruction* op = append(new UnsafePutObject(t, args->at(1), offset, args->at(3), is_volatile)); - compilation()->set_has_unsafe_access(true); - kill_all(); - } - return InlineUnsafeOps; + Instruction* op = append(new UnsafePutObject(t, args->at(1), offset, args->at(3), is_volatile)); + compilation()->set_has_unsafe_access(true); + kill_all(); } -bool GraphBuilder::append_unsafe_get_raw(ciMethod* callee, BasicType t) { - if (InlineUnsafeOps) { - Values* args = state()->pop_arguments(callee->arg_size()); - null_check(args->at(0)); - Instruction* op = append(new UnsafeGetRaw(t, args->at(1), false)); - push(op->type(), op); - compilation()->set_has_unsafe_access(true); - } - return InlineUnsafeOps; +void GraphBuilder::append_unsafe_get_raw(ciMethod* callee, BasicType t) { + Values* args = state()->pop_arguments(callee->arg_size()); + null_check(args->at(0)); + Instruction* op = append(new UnsafeGetRaw(t, args->at(1), false)); + push(op->type(), op); + compilation()->set_has_unsafe_access(true); } -bool GraphBuilder::append_unsafe_put_raw(ciMethod* callee, BasicType t) { - if (InlineUnsafeOps) { - Values* args = state()->pop_arguments(callee->arg_size()); - null_check(args->at(0)); - Instruction* op = append(new UnsafePutRaw(t, args->at(1), args->at(2))); - compilation()->set_has_unsafe_access(true); - } - return InlineUnsafeOps; +void GraphBuilder::append_unsafe_put_raw(ciMethod* callee, BasicType t) { + Values* args = state()->pop_arguments(callee->arg_size()); + null_check(args->at(0)); + Instruction* op = append(new UnsafePutRaw(t, args->at(1), args->at(2))); + compilation()->set_has_unsafe_access(true); } @@ -4352,21 +4210,18 @@ } } -bool GraphBuilder::append_unsafe_get_and_set_obj(ciMethod* callee, bool is_add) { - if (InlineUnsafeOps) { - Values* args = state()->pop_arguments(callee->arg_size()); - BasicType t = callee->return_type()->basic_type(); - null_check(args->at(0)); - Instruction* offset = args->at(2); +void GraphBuilder::append_unsafe_get_and_set_obj(ciMethod* callee, bool is_add) { + Values* args = state()->pop_arguments(callee->arg_size()); + BasicType t = callee->return_type()->basic_type(); + null_check(args->at(0)); + Instruction* offset = args->at(2); #ifndef _LP64 - offset = append(new Convert(Bytecodes::_l2i, offset, as_ValueType(T_INT))); + offset = append(new Convert(Bytecodes::_l2i, offset, as_ValueType(T_INT))); #endif - Instruction* op = append(new UnsafeGetAndSetObject(t, args->at(1), offset, args->at(3), is_add)); - compilation()->set_has_unsafe_access(true); - kill_all(); - push(op->type(), op); - } - return InlineUnsafeOps; + Instruction* op = append(new UnsafeGetAndSetObject(t, args->at(1), offset, args->at(3), is_add)); + compilation()->set_has_unsafe_access(true); + kill_all(); + push(op->type(), op); } #ifndef PRODUCT diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/c1/c1_GraphBuilder.hpp --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -339,6 +339,8 @@ void inline_sync_entry(Value lock, BlockBegin* sync_handler); void fill_sync_handler(Value lock, BlockBegin* sync_handler, bool default_handler = false); + void build_graph_for_intrinsic(ciMethod* callee); + // inliners bool try_inline( ciMethod* callee, bool holder_known, Bytecodes::Code bc = Bytecodes::_illegal, Value receiver = NULL); bool try_inline_intrinsics(ciMethod* callee); @@ -364,12 +366,12 @@ void pop_scope(); void pop_scope_for_jsr(); - bool append_unsafe_get_obj(ciMethod* callee, BasicType t, bool is_volatile); - bool append_unsafe_put_obj(ciMethod* callee, BasicType t, bool is_volatile); - bool append_unsafe_get_raw(ciMethod* callee, BasicType t); - bool append_unsafe_put_raw(ciMethod* callee, BasicType t); + void append_unsafe_get_obj(ciMethod* callee, BasicType t, bool is_volatile); + void append_unsafe_put_obj(ciMethod* callee, BasicType t, bool is_volatile); + void append_unsafe_get_raw(ciMethod* callee, BasicType t); + void append_unsafe_put_raw(ciMethod* callee, BasicType t); void append_unsafe_CAS(ciMethod* callee); - bool append_unsafe_get_and_set_obj(ciMethod* callee, bool is_add); + void append_unsafe_get_and_set_obj(ciMethod* callee, bool is_add); void print_inlining(ciMethod* callee, const char* msg = NULL, bool success = true); diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/c1/c1_ValueType.cpp --- a/hotspot/src/share/vm/c1/c1_ValueType.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/c1/c1_ValueType.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -153,7 +153,19 @@ case T_FLOAT : return new FloatConstant (value.as_float ()); case T_DOUBLE : return new DoubleConstant(value.as_double()); case T_ARRAY : // fall through (ciConstant doesn't have an array accessor) - case T_OBJECT : return new ObjectConstant(value.as_object()); + case T_OBJECT : { + // TODO: Common the code with GraphBuilder::load_constant? + ciObject* obj = value.as_object(); + if (obj->is_null_object()) + return objectNull; + if (obj->is_loaded()) { + if (obj->is_array()) + return new ArrayConstant(obj->as_array()); + else if (obj->is_instance()) + return new InstanceConstant(obj->as_instance()); + } + return new ObjectConstant(obj); + } } ShouldNotReachHere(); return illegalType; diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/classfile/javaClasses.cpp --- a/hotspot/src/share/vm/classfile/javaClasses.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -809,6 +809,22 @@ return name; } +// Returns the Java name for this Java mirror (Resource allocated) +// See Klass::external_name(). +// For primitive type Java mirrors, its type name is returned. +const char* java_lang_Class::as_external_name(oop java_class) { + assert(java_lang_Class::is_instance(java_class), "must be a Class object"); + const char* name = NULL; + if (is_primitive(java_class)) { + name = type2name(primitive_type(java_class)); + } else { + name = as_Klass(java_class)->external_name(); + } + if (name == NULL) { + name = ""; + } + return name; +} Klass* java_lang_Class::array_klass(oop java_class) { Klass* k = ((Klass*)java_class->metadata_field(_array_klass_offset)); @@ -1468,6 +1484,19 @@ }; +Symbol* get_source_file_name(InstanceKlass* holder, int version) { + // Find the specific ik version that contains this source_file_name_index + // via the previous versions list, but use the current version's + // constant pool to look it up. The previous version's index has been + // merged for the current constant pool. + InstanceKlass* ik = holder->get_klass_version(version); + // This version has been cleaned up. + if (ik == NULL) return NULL; + int source_file_name_index = ik->source_file_name_index(); + return (source_file_name_index == 0) ? + (Symbol*)NULL : holder->constants()->symbol_at(source_file_name_index); +} + // Print stack trace element to resource allocated buffer char* java_lang_Throwable::print_stack_element_to_buffer(Handle mirror, int method_id, int version, int bci, int cpref) { @@ -1484,17 +1513,11 @@ char* method_name = sym->as_C_string(); buf_len += (int)strlen(method_name); - // Use specific ik version as a holder since the mirror might - // refer to version that is now obsolete and no longer accessible - // via the previous versions list. - holder = holder->get_klass_version(version); char* source_file_name = NULL; - if (holder != NULL) { - Symbol* source = holder->source_file_name(); - if (source != NULL) { - source_file_name = source->as_C_string(); - buf_len += (int)strlen(source_file_name); - } + Symbol* source = get_source_file_name(holder, version); + if (source != NULL) { + source_file_name = source->as_C_string(); + buf_len += (int)strlen(source_file_name); } // Allocate temporary buffer with extra space for formatting and line number @@ -1909,12 +1932,7 @@ java_lang_StackTraceElement::set_lineNumber(element(), -1); } else { // Fill in source file name and line number. - // Use specific ik version as a holder since the mirror might - // refer to version that is now obsolete and no longer accessible - // via the previous versions list. - holder = holder->get_klass_version(version); - assert(holder != NULL, "sanity check"); - Symbol* source = holder->source_file_name(); + Symbol* source = get_source_file_name(holder, version); if (ShowHiddenFrames && source == NULL) source = vmSymbols::unknown_class_name(); oop filename = StringTable::intern(source, CHECK_0); diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/classfile/javaClasses.hpp --- a/hotspot/src/share/vm/classfile/javaClasses.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -276,6 +276,7 @@ } static Symbol* as_signature(oop java_class, bool intern_if_not_found, TRAPS); static void print_signature(oop java_class, outputStream *st); + static const char* as_external_name(oop java_class); // Testing static bool is_instance(oop obj); diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/classfile/verificationType.cpp --- a/hotspot/src/share/vm/classfile/verificationType.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/classfile/verificationType.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -86,7 +86,7 @@ VerificationType comp_this = get_component(context, CHECK_false); VerificationType comp_from = from.get_component(context, CHECK_false); if (!comp_this.is_bogus() && !comp_from.is_bogus()) { - return comp_this.is_assignable_from(comp_from, context, + return comp_this.is_component_assignable_from(comp_from, context, from_field_is_protected, CHECK_false); } } diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/classfile/verificationType.hpp --- a/hotspot/src/share/vm/classfile/verificationType.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/classfile/verificationType.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -297,6 +297,26 @@ } } + // Check to see if one array component type is assignable to another. + // Same as is_assignable_from() except int primitives must be identical. + bool is_component_assignable_from( + const VerificationType& from, ClassVerifier* context, + bool from_field_is_protected, TRAPS) const { + if (equals(from) || is_bogus()) { + return true; + } else { + switch(_u._data) { + case Boolean: + case Byte: + case Char: + case Short: + return false; + default: + return is_assignable_from(from, context, from_field_is_protected, CHECK_false); + } + } + } + VerificationType get_component(ClassVerifier* context, TRAPS) const; int dimensions() const { diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/classfile/vmSymbols.cpp --- a/hotspot/src/share/vm/classfile/vmSymbols.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/classfile/vmSymbols.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -324,6 +324,319 @@ return vmIntrinsics::_none; } +bool vmIntrinsics::preserves_state(vmIntrinsics::ID id) { + assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); + switch(id) { +#ifdef TRACE_HAVE_INTRINSICS + case vmIntrinsics::_classID: + case vmIntrinsics::_threadID: + case vmIntrinsics::_counterTime: +#endif + case vmIntrinsics::_currentTimeMillis: + case vmIntrinsics::_nanoTime: + case vmIntrinsics::_floatToRawIntBits: + case vmIntrinsics::_intBitsToFloat: + case vmIntrinsics::_doubleToRawLongBits: + case vmIntrinsics::_longBitsToDouble: + case vmIntrinsics::_getClass: + case vmIntrinsics::_isInstance: + case vmIntrinsics::_currentThread: + case vmIntrinsics::_dabs: + case vmIntrinsics::_dsqrt: + case vmIntrinsics::_dsin: + case vmIntrinsics::_dcos: + case vmIntrinsics::_dtan: + case vmIntrinsics::_dlog: + case vmIntrinsics::_dlog10: + case vmIntrinsics::_dexp: + case vmIntrinsics::_dpow: + case vmIntrinsics::_checkIndex: + case vmIntrinsics::_Reference_get: + case vmIntrinsics::_updateCRC32: + case vmIntrinsics::_updateBytesCRC32: + case vmIntrinsics::_updateByteBufferCRC32: + return true; + default: + return false; + } +} + +bool vmIntrinsics::can_trap(vmIntrinsics::ID id) { + assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); + switch(id) { +#ifdef TRACE_HAVE_INTRINSICS + case vmIntrinsics::_counterTime: +#endif + case vmIntrinsics::_currentTimeMillis: + case vmIntrinsics::_nanoTime: + case vmIntrinsics::_floatToRawIntBits: + case vmIntrinsics::_intBitsToFloat: + case vmIntrinsics::_doubleToRawLongBits: + case vmIntrinsics::_longBitsToDouble: + case vmIntrinsics::_currentThread: + case vmIntrinsics::_dabs: + case vmIntrinsics::_dsqrt: + case vmIntrinsics::_dsin: + case vmIntrinsics::_dcos: + case vmIntrinsics::_dtan: + case vmIntrinsics::_dlog: + case vmIntrinsics::_dlog10: + case vmIntrinsics::_dexp: + case vmIntrinsics::_dpow: + case vmIntrinsics::_updateCRC32: + case vmIntrinsics::_updateBytesCRC32: + case vmIntrinsics::_updateByteBufferCRC32: + return false; + default: + return true; + } +} + +bool vmIntrinsics::does_virtual_dispatch(vmIntrinsics::ID id) { + assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); + switch(id) { + case vmIntrinsics::_hashCode: + case vmIntrinsics::_clone: + return true; + break; + default: + return false; + } +} + +int vmIntrinsics::predicates_needed(vmIntrinsics::ID id) { + assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); + switch (id) { + case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt: + case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt: + return 1; + case vmIntrinsics::_digestBase_implCompressMB: + return 3; + default: + return 0; + } +} + +bool vmIntrinsics::is_disabled_by_flags(vmIntrinsics::ID id) { + assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); + switch (id) { + case vmIntrinsics::_isInstance: + case vmIntrinsics::_isAssignableFrom: + case vmIntrinsics::_getModifiers: + case vmIntrinsics::_isInterface: + case vmIntrinsics::_isArray: + case vmIntrinsics::_isPrimitive: + case vmIntrinsics::_getSuperclass: + case vmIntrinsics::_Class_cast: + case vmIntrinsics::_getLength: + case vmIntrinsics::_newArray: + if (!InlineClassNatives) return true; + break; + case vmIntrinsics::_currentThread: + case vmIntrinsics::_isInterrupted: + if (!InlineThreadNatives) return true; + break; + case vmIntrinsics::_floatToRawIntBits: + case vmIntrinsics::_intBitsToFloat: + case vmIntrinsics::_doubleToRawLongBits: + case vmIntrinsics::_longBitsToDouble: + case vmIntrinsics::_dabs: + case vmIntrinsics::_dsqrt: + case vmIntrinsics::_dsin: + case vmIntrinsics::_dcos: + case vmIntrinsics::_dtan: + case vmIntrinsics::_dlog: + case vmIntrinsics::_dexp: + case vmIntrinsics::_dpow: + case vmIntrinsics::_dlog10: + case vmIntrinsics::_datan2: + case vmIntrinsics::_min: + case vmIntrinsics::_max: + case vmIntrinsics::_floatToIntBits: + case vmIntrinsics::_doubleToLongBits: + if (!InlineMathNatives) return true; + break; + case vmIntrinsics::_arraycopy: + if (!InlineArrayCopy) return true; + break; + case vmIntrinsics::_updateCRC32: + case vmIntrinsics::_updateBytesCRC32: + case vmIntrinsics::_updateByteBufferCRC32: + if (!UseCRC32Intrinsics) return true; + break; + case vmIntrinsics::_getObject: + case vmIntrinsics::_getBoolean: + case vmIntrinsics::_getByte: + case vmIntrinsics::_getShort: + case vmIntrinsics::_getChar: + case vmIntrinsics::_getInt: + case vmIntrinsics::_getLong: + case vmIntrinsics::_getFloat: + case vmIntrinsics::_getDouble: + case vmIntrinsics::_putObject: + case vmIntrinsics::_putBoolean: + case vmIntrinsics::_putByte: + case vmIntrinsics::_putShort: + case vmIntrinsics::_putChar: + case vmIntrinsics::_putInt: + case vmIntrinsics::_putLong: + case vmIntrinsics::_putFloat: + case vmIntrinsics::_putDouble: + case vmIntrinsics::_getObjectVolatile: + case vmIntrinsics::_getBooleanVolatile: + case vmIntrinsics::_getByteVolatile: + case vmIntrinsics::_getShortVolatile: + case vmIntrinsics::_getCharVolatile: + case vmIntrinsics::_getIntVolatile: + case vmIntrinsics::_getLongVolatile: + case vmIntrinsics::_getFloatVolatile: + case vmIntrinsics::_getDoubleVolatile: + case vmIntrinsics::_putObjectVolatile: + case vmIntrinsics::_putBooleanVolatile: + case vmIntrinsics::_putByteVolatile: + case vmIntrinsics::_putShortVolatile: + case vmIntrinsics::_putCharVolatile: + case vmIntrinsics::_putIntVolatile: + case vmIntrinsics::_putLongVolatile: + case vmIntrinsics::_putFloatVolatile: + case vmIntrinsics::_putDoubleVolatile: + case vmIntrinsics::_getByte_raw: + case vmIntrinsics::_getShort_raw: + case vmIntrinsics::_getChar_raw: + case vmIntrinsics::_getInt_raw: + case vmIntrinsics::_getLong_raw: + case vmIntrinsics::_getFloat_raw: + case vmIntrinsics::_getDouble_raw: + case vmIntrinsics::_putByte_raw: + case vmIntrinsics::_putShort_raw: + case vmIntrinsics::_putChar_raw: + case vmIntrinsics::_putInt_raw: + case vmIntrinsics::_putLong_raw: + case vmIntrinsics::_putFloat_raw: + case vmIntrinsics::_putDouble_raw: + case vmIntrinsics::_putOrderedObject: + case vmIntrinsics::_putOrderedLong: + case vmIntrinsics::_putOrderedInt: + case vmIntrinsics::_getAndAddInt: + case vmIntrinsics::_getAndAddLong: + case vmIntrinsics::_getAndSetInt: + case vmIntrinsics::_getAndSetLong: + case vmIntrinsics::_getAndSetObject: + if (!InlineUnsafeOps) return true; + break; + case vmIntrinsics::_getShortUnaligned: + case vmIntrinsics::_getCharUnaligned: + case vmIntrinsics::_getIntUnaligned: + case vmIntrinsics::_getLongUnaligned: + case vmIntrinsics::_putShortUnaligned: + case vmIntrinsics::_putCharUnaligned: + case vmIntrinsics::_putIntUnaligned: + case vmIntrinsics::_putLongUnaligned: + case vmIntrinsics::_allocateInstance: + case vmIntrinsics::_getAddress_raw: + case vmIntrinsics::_putAddress_raw: + if (!InlineUnsafeOps || !UseUnalignedAccesses) return true; + break; + case vmIntrinsics::_hashCode: + if (!InlineObjectHash) return true; + break; + case vmIntrinsics::_aescrypt_encryptBlock: + case vmIntrinsics::_aescrypt_decryptBlock: + if (!UseAESIntrinsics) return true; + break; + case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt: + case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt: + if (!UseAESIntrinsics) return true; + break; + case vmIntrinsics::_sha_implCompress: + if (!UseSHA1Intrinsics) return true; + break; + case vmIntrinsics::_sha2_implCompress: + if (!UseSHA256Intrinsics) return true; + break; + case vmIntrinsics::_sha5_implCompress: + if (!UseSHA512Intrinsics) return true; + break; + case vmIntrinsics::_digestBase_implCompressMB: + if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics)) return true; + break; + case vmIntrinsics::_ghash_processBlocks: + if (!UseGHASHIntrinsics) return true; + break; + case vmIntrinsics::_updateBytesCRC32C: + case vmIntrinsics::_updateDirectByteBufferCRC32C: + if (!UseCRC32CIntrinsics) return true; + break; + case vmIntrinsics::_copyMemory: + if (!InlineArrayCopy || !InlineUnsafeOps) return true; + break; +#ifdef COMPILER1 + case vmIntrinsics::_checkIndex: + if (!InlineNIOCheckIndex) return true; + break; +#endif // COMPILER1 +#ifdef COMPILER2 + case vmIntrinsics::_clone: + case vmIntrinsics::_copyOf: + case vmIntrinsics::_copyOfRange: + // These intrinsics use both the objectcopy and the arraycopy + // intrinsic mechanism. + if (!InlineObjectCopy || !InlineArrayCopy) return true; + break; + case vmIntrinsics::_compareTo: + if (!SpecialStringCompareTo) return true; + break; + case vmIntrinsics::_indexOf: + if (!SpecialStringIndexOf) return true; + break; + case vmIntrinsics::_equals: + if (!SpecialStringEquals) return true; + break; + case vmIntrinsics::_equalsC: + if (!SpecialArraysEquals) return true; + break; + case vmIntrinsics::_encodeISOArray: + if (!SpecialEncodeISOArray) return true; + break; + case vmIntrinsics::_getCallerClass: + if (!InlineReflectionGetCallerClass) return true; + break; + case vmIntrinsics::_multiplyToLen: + if (!UseMultiplyToLenIntrinsic) return true; + break; + case vmIntrinsics::_squareToLen: + if (!UseSquareToLenIntrinsic) return true; + break; + case vmIntrinsics::_mulAdd: + if (!UseMulAddIntrinsic) return true; + break; + case vmIntrinsics::_montgomeryMultiply: + if (!UseMontgomeryMultiplyIntrinsic) return true; + break; + case vmIntrinsics::_montgomerySquare: + if (!UseMontgomerySquareIntrinsic) return true; + break; + case vmIntrinsics::_addExactI: + case vmIntrinsics::_addExactL: + case vmIntrinsics::_decrementExactI: + case vmIntrinsics::_decrementExactL: + case vmIntrinsics::_incrementExactI: + case vmIntrinsics::_incrementExactL: + case vmIntrinsics::_multiplyExactI: + case vmIntrinsics::_multiplyExactL: + case vmIntrinsics::_negateExactI: + case vmIntrinsics::_negateExactL: + case vmIntrinsics::_subtractExactI: + case vmIntrinsics::_subtractExactL: + if (!UseMathExactIntrinsics || !InlineMathNatives) return true; + break; +#endif // COMPILER2 + default: + return false; + } + + return false; +} #define VM_INTRINSIC_INITIALIZE(id, klass, name, sig, flags) #id "\0" static const char* vm_intrinsic_name_bodies = diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/classfile/vmSymbols.hpp --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -1368,6 +1368,26 @@ // Raw conversion: static ID for_raw_conversion(BasicType src, BasicType dest); + + // The methods below provide information related to compiling intrinsics. + + // (1) Information needed by the C1 compiler. + + static bool preserves_state(vmIntrinsics::ID id); + static bool can_trap(vmIntrinsics::ID id); + + // (2) Information needed by the C2 compiler. + + // Returns true if the intrinsic for method 'method' will perform a virtual dispatch. + static bool does_virtual_dispatch(vmIntrinsics::ID id); + // A return value larger than 0 indicates that the intrinsic for method + // 'method' requires predicated logic. + static int predicates_needed(vmIntrinsics::ID id); + + // Returns true if an intrinsic is disabled by command-line flags and + // false otherwise. Implements functionality common to the C1 + // and the C2 compiler. + static bool is_disabled_by_flags(vmIntrinsics::ID id); }; #endif // SHARE_VM_CLASSFILE_VMSYMBOLS_HPP diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/compiler/abstractCompiler.hpp --- a/hotspot/src/share/vm/compiler/abstractCompiler.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/compiler/abstractCompiler.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -66,6 +66,58 @@ virtual bool supports_osr () { return true; } virtual bool can_compile_method(methodHandle method) { return true; } + // Determine if the current compiler provides an intrinsic + // for method 'method'. An intrinsic is available if: + // - the intrinsic is enabled (by using the appropriate command-line flag) and + // - the platform on which the VM is running supports the intrinsic + // (i.e., the platform provides the instructions necessary for the compiler + // to generate the intrinsic code). + // + // The second parameter, 'compilation_context', is needed to implement functionality + // related to the DisableIntrinsic command-line flag. The DisableIntrinsic flag can + // be used to prohibit the C2 compiler (but not the C1 compiler) to use an intrinsic. + // There are three ways to disable an intrinsic using the DisableIntrinsic flag: + // + // (1) -XX:DisableIntrinsic=_hashCode,_getClass + // Disables intrinsification of _hashCode and _getClass globally + // (i.e., the intrinsified version the methods will not be used at all). + // (2) -XX:CompileCommand=option,aClass::aMethod,ccstr,DisableIntrinsic,_hashCode + // Disables intrinsification of _hashCode if it is called from + // aClass::aMethod (but not for any other call site of _hashCode) + // (3) -XX:CompileCommand=option,java.lang.ref.Reference::get,ccstr,DisableIntrinsic,_Reference_get + // Some methods are not compiled by C2. Instead, the C2 compiler + // returns directly the intrinsified version of these methods. + // The command above forces C2 to compile _Reference_get, but + // allows using the intrinsified version of _Reference_get at all + // other call sites. + // + // From the modes above, (1) disable intrinsics globally, (2) and (3) + // disable intrinsics on a per-method basis. In cases (2) and (3) the + // compilation context is aClass::aMethod and java.lang.ref.Reference::get, + // respectively. + virtual bool is_intrinsic_available(methodHandle method, methodHandle compilation_context) { + return false; + } + + // Determines if an intrinsic is supported by the compiler, that is, + // the compiler provides the instructions necessary to generate + // the intrinsic code for method 'method'. + // + // The 'is_intrinsic_supported' method is a white list, that is, + // by default no intrinsics are supported by a compiler except + // the ones listed in the method. Overriding methods should conform + // to this behavior. + virtual bool is_intrinsic_supported(methodHandle method) { + return false; + } + + // Implements compiler-specific processing of command-line flags. + // Processing of command-line flags common to all compilers is implemented + // in vmIntrinsicss::is_disabled_by_flag. + virtual bool is_intrinsic_disabled_by_flag(methodHandle method) { + return false; + } + // Compiler type queries. bool is_c1() { return _type == c1; } bool is_c2() { return _type == c2; } diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/compiler/compileBroker.cpp --- a/hotspot/src/share/vm/compiler/compileBroker.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, 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 @@ -345,6 +345,14 @@ } } +// RedefineClasses support +void CompileTask::metadata_do(void f(Metadata*)) { + f(method()); + if (hot_method() != NULL && hot_method() != method()) { + f(hot_method()); + } +} + // ------------------------------------------------------------------ // CompileTask::print_line_on_error // @@ -660,6 +668,11 @@ * Get the next CompileTask from a CompileQueue */ CompileTask* CompileQueue::get() { + // save methods from RedefineClasses across safepoint + // across MethodCompileQueue_lock below. + methodHandle save_method; + methodHandle save_hot_method; + MutexLocker locker(MethodCompileQueue_lock); // If _first is NULL we have no more compile jobs. There are two reasons for // having no compile jobs: First, we compiled everything we wanted. Second, @@ -693,6 +706,12 @@ No_Safepoint_Verifier nsv; task = CompilationPolicy::policy()->select_task(this); } + + // Save method pointers across unlock safepoint. The task is removed from + // the compilation queue, which is walked during RedefineClasses. + save_method = methodHandle(task->method()); + save_hot_method = methodHandle(task->hot_method()); + remove(task); purge_stale_tasks(); // may temporarily release MCQ lock return task; diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/compiler/compileBroker.hpp --- a/hotspot/src/share/vm/compiler/compileBroker.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/compiler/compileBroker.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, 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 @@ -80,6 +80,7 @@ int compile_id() const { return _compile_id; } Method* method() const { return _method; } + Method* hot_method() const { return _hot_method; } int osr_bci() const { return _osr_bci; } bool is_complete() const { return _is_complete; } bool is_blocking() const { return _is_blocking; } @@ -108,6 +109,9 @@ bool is_free() const { return _is_free; } void set_is_free(bool val) { _is_free = val; } + // RedefineClasses support + void metadata_do(void f(Metadata*)); + private: static void print_compilation_impl(outputStream* st, Method* method, int compile_id, int comp_level, bool is_osr_method = false, int osr_bci = -1, bool is_blocking = false, diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp --- a/hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -36,10 +36,11 @@ #include "runtime/orderAccess.inline.hpp" #include "runtime/vmThread.hpp" -void CardTableModRefBS::non_clean_card_iterate_parallel_work(Space* sp, MemRegion mr, - OopsInGenClosure* cl, - CardTableRS* ct, - uint n_threads) { +void CardTableModRefBSForCTRS:: +non_clean_card_iterate_parallel_work(Space* sp, MemRegion mr, + OopsInGenClosure* cl, + CardTableRS* ct, + uint n_threads) { assert(n_threads > 0, "expected n_threads > 0"); assert(n_threads <= ParallelGCThreads, err_msg("n_threads: %u > ParallelGCThreads: %u", n_threads, ParallelGCThreads)); @@ -81,7 +82,7 @@ } void -CardTableModRefBS:: +CardTableModRefBSForCTRS:: process_stride(Space* sp, MemRegion used, jint stride, int n_strides, @@ -170,7 +171,7 @@ #endif void -CardTableModRefBS:: +CardTableModRefBSForCTRS:: process_chunk_boundaries(Space* sp, DirtyCardToOopClosure* dcto_cl, MemRegion chunk_mr, @@ -426,7 +427,7 @@ #undef NOISY void -CardTableModRefBS:: +CardTableModRefBSForCTRS:: get_LNC_array_for_space(Space* sp, jbyte**& lowest_non_clean, uintptr_t& lowest_non_clean_base_chunk_index, diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/gc/g1/concurrentMark.cpp --- a/hotspot/src/share/vm/gc/g1/concurrentMark.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/gc/g1/concurrentMark.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -403,14 +403,6 @@ _saved_index = -1; } -void CMMarkStack::oops_do(OopClosure* f) { - assert(_saved_index == _index, - err_msg("saved index: %d index: %d", _saved_index, _index)); - for (int i = 0; i < _index; i += 1) { - f->do_oop(&_base[i]); - } -} - CMRootRegions::CMRootRegions() : _young_list(NULL), _cm(NULL), _scan_in_progress(false), _should_abort(false), _next_survivor(NULL) { } @@ -2717,53 +2709,26 @@ } #ifndef PRODUCT -enum VerifyNoCSetOopsPhase { - VerifyNoCSetOopsStack, - VerifyNoCSetOopsQueues -}; - -class VerifyNoCSetOopsClosure : public OopClosure, public ObjectClosure { +class VerifyNoCSetOops VALUE_OBJ_CLASS_SPEC { private: G1CollectedHeap* _g1h; - VerifyNoCSetOopsPhase _phase; + const char* _phase; int _info; - const char* phase_str() { - switch (_phase) { - case VerifyNoCSetOopsStack: return "Stack"; - case VerifyNoCSetOopsQueues: return "Queue"; - default: ShouldNotReachHere(); - } - return NULL; - } - - void do_object_work(oop obj) { +public: + VerifyNoCSetOops(const char* phase, int info = -1) : + _g1h(G1CollectedHeap::heap()), + _phase(phase), + _info(info) + { } + + void operator()(oop obj) const { + guarantee(obj->is_oop(), + err_msg("Non-oop " PTR_FORMAT ", phase: %s, info: %d", + p2i(obj), _phase, _info)); guarantee(!_g1h->obj_in_cs(obj), err_msg("obj: " PTR_FORMAT " in CSet, phase: %s, info: %d", - p2i((void*) obj), phase_str(), _info)); - } - -public: - VerifyNoCSetOopsClosure() : _g1h(G1CollectedHeap::heap()) { } - - void set_phase(VerifyNoCSetOopsPhase phase, int info = -1) { - _phase = phase; - _info = info; - } - - virtual void do_oop(oop* p) { - oop obj = oopDesc::load_decode_heap_oop(p); - do_object_work(obj); - } - - virtual void do_oop(narrowOop* p) { - // We should not come across narrow oops while scanning marking - // stacks - ShouldNotReachHere(); - } - - virtual void do_object(oop obj) { - do_object_work(obj); + p2i(obj), _phase, _info)); } }; @@ -2773,17 +2738,13 @@ return; } - VerifyNoCSetOopsClosure cl; - // Verify entries on the global mark stack - cl.set_phase(VerifyNoCSetOopsStack); - _markStack.oops_do(&cl); + _markStack.iterate(VerifyNoCSetOops("Stack")); // Verify entries on the task queues - for (uint i = 0; i < _max_worker_id; i += 1) { - cl.set_phase(VerifyNoCSetOopsQueues, i); + for (uint i = 0; i < _max_worker_id; ++i) { CMTaskQueue* queue = _task_queues->queue(i); - queue->oops_do(&cl); + queue->iterate(VerifyNoCSetOops("Queue", i)); } // Verify the global finger @@ -2806,7 +2767,7 @@ // Verify the task fingers assert(parallel_marking_threads() <= _max_worker_id, "sanity"); - for (int i = 0; i < (int) parallel_marking_threads(); i += 1) { + for (uint i = 0; i < parallel_marking_threads(); ++i) { CMTask* task = _tasks[i]; HeapWord* task_finger = task->finger(); if (task_finger != NULL && task_finger < _heap_end) { diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/gc/g1/concurrentMark.hpp --- a/hotspot/src/share/vm/gc/g1/concurrentMark.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/gc/g1/concurrentMark.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -246,9 +246,10 @@ // Make sure that we have not added any entries to the stack during GC. void note_end_of_gc(); - // iterate over the oops in the mark stack, up to the bound recorded via - // the call above. - void oops_do(OopClosure* f); + // Apply fn to each oop in the mark stack, up to the bound recorded + // via one of the above "note" functions. The mark stack must not + // be modified while iterating. + template void iterate(Fn fn); }; class ForceOverflowSettings VALUE_OBJ_CLASS_SPEC { diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/gc/g1/concurrentMark.inline.hpp --- a/hotspot/src/share/vm/gc/g1/concurrentMark.inline.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/gc/g1/concurrentMark.inline.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -223,6 +223,15 @@ #undef check_mark +template +inline void CMMarkStack::iterate(Fn fn) { + assert(_saved_index == _index, + err_msg("saved index: %d index: %d", _saved_index, _index)); + for (int i = 0; i < _index; ++i) { + fn(_base[i]); + } +} + inline void CMTask::push(oop obj) { HeapWord* objAddr = (HeapWord*) obj; assert(_g1h->is_in_g1_reserved(objAddr), "invariant"); diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/gc/g1/g1Allocator.hpp --- a/hotspot/src/share/vm/gc/g1/g1Allocator.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/gc/g1/g1Allocator.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -39,13 +39,8 @@ protected: G1CollectedHeap* _g1h; - // Outside of GC pauses, the number of bytes used in all regions other - // than the current allocation region. - size_t _summary_bytes_used; - public: - G1Allocator(G1CollectedHeap* heap) : - _g1h(heap), _summary_bytes_used(0) { } + G1Allocator(G1CollectedHeap* heap) : _g1h(heap) { } static G1Allocator* create_allocator(G1CollectedHeap* g1h); @@ -59,32 +54,13 @@ virtual MutatorAllocRegion* mutator_alloc_region(AllocationContext_t context) = 0; virtual SurvivorGCAllocRegion* survivor_gc_alloc_region(AllocationContext_t context) = 0; virtual OldGCAllocRegion* old_gc_alloc_region(AllocationContext_t context) = 0; - virtual size_t used() = 0; + virtual size_t used_in_alloc_regions() = 0; virtual bool is_retained_old_region(HeapRegion* hr) = 0; void reuse_retained_old_region(EvacuationInfo& evacuation_info, OldGCAllocRegion* old, HeapRegion** retained); - size_t used_unlocked() const { - return _summary_bytes_used; - } - - void increase_used(size_t bytes) { - _summary_bytes_used += bytes; - } - - void decrease_used(size_t bytes) { - assert(_summary_bytes_used >= bytes, - err_msg("invariant: _summary_bytes_used: " SIZE_FORMAT " should be >= bytes: " SIZE_FORMAT, - _summary_bytes_used, bytes)); - _summary_bytes_used -= bytes; - } - - void set_used(size_t bytes) { - _summary_bytes_used = bytes; - } - virtual HeapRegion* new_heap_region(uint hrs_index, G1BlockOffsetSharedArray* sharedOffsetArray, MemRegion mr) { @@ -133,10 +109,10 @@ return &_old_gc_alloc_region; } - virtual size_t used() { + virtual size_t used_in_alloc_regions() { assert(Heap_lock->owner() != NULL, "Should be owned on this thread's behalf."); - size_t result = _summary_bytes_used; + size_t result = 0; // Read only once in case it is set to NULL concurrently HeapRegion* hr = mutator_alloc_region(AllocationContext::current())->get(); diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -632,7 +632,7 @@ check_bitmaps("Humongous Region Allocation", first_hr); assert(first_hr->used() == word_size * HeapWordSize, "invariant"); - _allocator->increase_used(first_hr->used()); + increase_used(first_hr->used()); _humongous_set.add(first_hr); return new_obj; @@ -998,7 +998,7 @@ if ((prev_last_region != NULL) && (start_region == prev_last_region)) { start_address = start_region->end(); if (start_address > last_address) { - _allocator->increase_used(word_size * HeapWordSize); + increase_used(word_size * HeapWordSize); start_region->set_top(last_address + 1); continue; } @@ -1012,7 +1012,7 @@ if (!_hrm.allocate_containing_regions(curr_range, &commits)) { return false; } - _allocator->increase_used(word_size * HeapWordSize); + increase_used(word_size * HeapWordSize); if (commits != 0) { ergo_verbose1(ErgoHeapSizing, "attempt heap expansion", @@ -1104,7 +1104,7 @@ if (start_address != bottom_address) { size_t fill_size = pointer_delta(start_address, bottom_address); G1CollectedHeap::fill_with_objects(bottom_address, fill_size); - _allocator->increase_used(fill_size * HeapWordSize); + increase_used(fill_size * HeapWordSize); } } } @@ -1917,7 +1917,6 @@ _ref_processor_cm(NULL), _ref_processor_stw(NULL), _bot_shared(NULL), - _evac_failure_scan_stack(NULL), _cg1r(NULL), _g1mm(NULL), _refine_cte_cl(NULL), @@ -1930,6 +1929,7 @@ _free_regions_coming(false), _young_list(new YoungList(this)), _gc_time_stamp(0), + _summary_bytes_used(0), _survivor_plab_stats(YoungPLABSize, PLABWeight), _old_plab_stats(OldPLABSize, PLABWeight), _expand_heap_after_alloc_failure(true), @@ -2204,6 +2204,11 @@ G1StringDedup::initialize(); + _preserved_objs = NEW_C_HEAP_ARRAY(OopAndMarkOopStack, ParallelGCThreads, mtGC); + for (uint i = 0; i < ParallelGCThreads; i++) { + new (&_preserved_objs[i]) OopAndMarkOopStack(); + } + return JNI_OK; } @@ -2371,7 +2376,7 @@ // Computes the sum of the storage used by the various regions. size_t G1CollectedHeap::used() const { - size_t result = _allocator->used(); + size_t result = _summary_bytes_used + _allocator->used_in_alloc_regions(); if (_archive_allocator != NULL) { result += _archive_allocator->used(); } @@ -2379,7 +2384,7 @@ } size_t G1CollectedHeap::used_unlocked() const { - return _allocator->used_unlocked(); + return _summary_bytes_used; } class SumUsedClosure: public HeapRegionClosure { @@ -3376,7 +3381,7 @@ // Print the per-region information. st->cr(); - st->print_cr("Heap Regions: (Y=young(eden), SU=young(survivor), " + st->print_cr("Heap Regions: (E=young(eden), S=young(survivor), O=old, " "HS=humongous(starts), HC=humongous(continues), " "CS=collection set, F=free, A=archive, TS=gc time stamp, " "PTAMS=previous top-at-mark-start, " @@ -4102,7 +4107,7 @@ _young_list->reset_auxilary_lists(); if (evacuation_failed()) { - _allocator->set_used(recalculate_used()); + set_used(recalculate_used()); if (_archive_allocator != NULL) { _archive_allocator->clear_used(); } @@ -4114,7 +4119,7 @@ } else { // The "used" of the the collection set have already been subtracted // when they were freed. Add in the bytes evacuated. - _allocator->increase_used(g1_policy()->bytes_copied_during_gc()); + increase_used(g1_policy()->bytes_copied_during_gc()); } if (collector_state()->during_initial_mark_pause()) { @@ -4255,21 +4260,6 @@ return true; } -void G1CollectedHeap::init_for_evac_failure(OopsInHeapRegionClosure* cl) { - _drain_in_progress = false; - set_evac_failure_closure(cl); - _evac_failure_scan_stack = new (ResourceObj::C_HEAP, mtGC) GrowableArray(40, true); -} - -void G1CollectedHeap::finalize_for_evac_failure() { - assert(_evac_failure_scan_stack != NULL && - _evac_failure_scan_stack->length() == 0, - "Postcondition"); - assert(!_drain_in_progress, "Postcondition"); - delete _evac_failure_scan_stack; - _evac_failure_scan_stack = NULL; -} - void G1CollectedHeap::remove_self_forwarding_pointers() { double remove_self_forwards_start = os::elapsedTime(); @@ -4277,104 +4267,30 @@ workers()->run_task(&rsfp_task); // Now restore saved marks, if any. - assert(_objs_with_preserved_marks.size() == - _preserved_marks_of_objs.size(), "Both or none."); - while (!_objs_with_preserved_marks.is_empty()) { - oop obj = _objs_with_preserved_marks.pop(); - markOop m = _preserved_marks_of_objs.pop(); - obj->set_mark(m); - } - _objs_with_preserved_marks.clear(true); - _preserved_marks_of_objs.clear(true); + for (uint i = 0; i < ParallelGCThreads; i++) { + OopAndMarkOopStack& cur = _preserved_objs[i]; + while (!cur.is_empty()) { + OopAndMarkOop elem = cur.pop(); + elem.set_mark(); + } + cur.clear(true); + } g1_policy()->phase_times()->record_evac_fail_remove_self_forwards((os::elapsedTime() - remove_self_forwards_start) * 1000.0); } -void G1CollectedHeap::push_on_evac_failure_scan_stack(oop obj) { - _evac_failure_scan_stack->push(obj); -} - -void G1CollectedHeap::drain_evac_failure_scan_stack() { - assert(_evac_failure_scan_stack != NULL, "precondition"); - - while (_evac_failure_scan_stack->length() > 0) { - oop obj = _evac_failure_scan_stack->pop(); - _evac_failure_closure->set_region(heap_region_containing(obj)); - obj->oop_iterate_backwards(_evac_failure_closure); - } -} - -oop -G1CollectedHeap::handle_evacuation_failure_par(G1ParScanThreadState* _par_scan_state, - oop old) { - assert(obj_in_cs(old), - err_msg("obj: " PTR_FORMAT " should still be in the CSet", - p2i(old))); - markOop m = old->mark(); - oop forward_ptr = old->forward_to_atomic(old); - if (forward_ptr == NULL) { - // Forward-to-self succeeded. - assert(_par_scan_state != NULL, "par scan state"); - OopsInHeapRegionClosure* cl = _par_scan_state->evac_failure_closure(); - uint queue_num = _par_scan_state->queue_num(); - +void G1CollectedHeap::preserve_mark_during_evac_failure(uint queue_num, oop obj, markOop m) { + if (!_evacuation_failed) { _evacuation_failed = true; - _evacuation_failed_info_array[queue_num].register_copy_failure(old->size()); - if (_evac_failure_closure != cl) { - MutexLockerEx x(EvacFailureStack_lock, Mutex::_no_safepoint_check_flag); - assert(!_drain_in_progress, - "Should only be true while someone holds the lock."); - // Set the global evac-failure closure to the current thread's. - assert(_evac_failure_closure == NULL, "Or locking has failed."); - set_evac_failure_closure(cl); - // Now do the common part. - handle_evacuation_failure_common(old, m); - // Reset to NULL. - set_evac_failure_closure(NULL); - } else { - // The lock is already held, and this is recursive. - assert(_drain_in_progress, "This should only be the recursive case."); - handle_evacuation_failure_common(old, m); - } - return old; - } else { - // Forward-to-self failed. Either someone else managed to allocate - // space for this object (old != forward_ptr) or they beat us in - // self-forwarding it (old == forward_ptr). - assert(old == forward_ptr || !obj_in_cs(forward_ptr), - err_msg("obj: " PTR_FORMAT " forwarded to: " PTR_FORMAT " " - "should not be in the CSet", - p2i(old), p2i(forward_ptr))); - return forward_ptr; - } -} - -void G1CollectedHeap::handle_evacuation_failure_common(oop old, markOop m) { - preserve_mark_if_necessary(old, m); - - HeapRegion* r = heap_region_containing(old); - if (!r->evacuation_failed()) { - r->set_evacuation_failed(true); - _hr_printer.evac_failure(r); - } - - push_on_evac_failure_scan_stack(old); - - if (!_drain_in_progress) { - // prevent recursion in copy_to_survivor_space() - _drain_in_progress = true; - drain_evac_failure_scan_stack(); - _drain_in_progress = false; - } -} - -void G1CollectedHeap::preserve_mark_if_necessary(oop obj, markOop m) { - assert(evacuation_failed(), "Oversaving!"); + } + + _evacuation_failed_info_array[queue_num].register_copy_failure(obj->size()); + // We want to call the "for_promotion_failure" version only in the // case of a promotion failure. if (m->must_be_preserved_for_promotion_failure(obj)) { - _objs_with_preserved_marks.push(obj); - _preserved_marks_of_objs.push(m); + OopAndMarkOop elem(obj, m); + _preserved_objs[queue_num].push(elem); } } @@ -4450,14 +4366,7 @@ mark_object(obj); } } - - if (barrier == G1BarrierEvac) { - _par_scan_state->update_rs(_from, p, _worker_id); - } -} - -template void G1ParCopyClosure::do_oop_work(oop* p); -template void G1ParCopyClosure::do_oop_work(narrowOop* p); +} class G1ParEvacuateFollowersClosure : public VoidClosure { protected: @@ -4597,9 +4506,6 @@ ReferenceProcessor* rp = _g1h->ref_processor_stw(); G1ParScanThreadState pss(_g1h, worker_id, rp); - G1ParScanHeapEvacFailureClosure evac_failure_cl(_g1h, &pss, rp); - - pss.set_evac_failure_closure(&evac_failure_cl); bool only_young = _g1h->collector_state()->gcs_are_young(); @@ -5269,9 +5175,6 @@ G1STWIsAliveClosure is_alive(_g1h); G1ParScanThreadState pss(_g1h, worker_id, NULL); - G1ParScanHeapEvacFailureClosure evac_failure_cl(_g1h, &pss, NULL); - - pss.set_evac_failure_closure(&evac_failure_cl); G1ParScanExtRootClosure only_copy_non_heap_cl(_g1h, &pss, NULL); @@ -5368,10 +5271,6 @@ HandleMark hm; G1ParScanThreadState pss(_g1h, worker_id, NULL); - G1ParScanHeapEvacFailureClosure evac_failure_cl(_g1h, &pss, NULL); - - pss.set_evac_failure_closure(&evac_failure_cl); - assert(pss.queue_is_empty(), "both queue and overflow should be empty"); G1ParScanExtRootClosure only_copy_non_heap_cl(_g1h, &pss, NULL); @@ -5476,15 +5375,11 @@ // Use only a single queue for this PSS. G1ParScanThreadState pss(this, 0, NULL); + assert(pss.queue_is_empty(), "pre-condition"); // We do not embed a reference processor in the copying/scanning // closures while we're actually processing the discovered // reference objects. - G1ParScanHeapEvacFailureClosure evac_failure_cl(this, &pss, NULL); - - pss.set_evac_failure_closure(&evac_failure_cl); - - assert(pss.queue_is_empty(), "pre-condition"); G1ParScanExtRootClosure only_copy_non_heap_cl(this, &pss, NULL); @@ -5590,8 +5485,6 @@ const uint n_workers = workers()->active_workers(); - init_for_evac_failure(NULL); - assert(dirty_card_queue_set().completed_buffers_num() == 0, "Should be empty"); double start_par_time_sec = os::elapsedTime(); double end_par_time_sec; @@ -5655,8 +5548,6 @@ purge_code_root_memory(); - finalize_for_evac_failure(); - if (evacuation_failed()) { remove_self_forwarding_pointers(); @@ -5745,7 +5636,7 @@ } void G1CollectedHeap::decrement_summary_bytes(size_t bytes) { - _allocator->decrease_used(bytes); + decrease_used(bytes); } class G1ParCleanupCTTask : public AbstractGangTask { @@ -6395,6 +6286,21 @@ _hrm.remove_all_free_regions(); } +void G1CollectedHeap::increase_used(size_t bytes) { + _summary_bytes_used += bytes; +} + +void G1CollectedHeap::decrease_used(size_t bytes) { + assert(_summary_bytes_used >= bytes, + err_msg("invariant: _summary_bytes_used: " SIZE_FORMAT " should be >= bytes: " SIZE_FORMAT, + _summary_bytes_used, bytes)); + _summary_bytes_used -= bytes; +} + +void G1CollectedHeap::set_used(size_t bytes) { + _summary_bytes_used = bytes; +} + class RebuildRegionSetsClosure : public HeapRegionClosure { private: bool _free_list_only; @@ -6463,15 +6369,15 @@ heap_region_iterate(&cl); if (!free_list_only) { - _allocator->set_used(cl.total_used()); + set_used(cl.total_used()); if (_archive_allocator != NULL) { _archive_allocator->clear_used(); } } - assert(_allocator->used_unlocked() == recalculate_used(), - err_msg("inconsistent _allocator->used_unlocked(), " + assert(used_unlocked() == recalculate_used(), + err_msg("inconsistent used_unlocked(), " "value: " SIZE_FORMAT " recalculated: " SIZE_FORMAT, - _allocator->used_unlocked(), recalculate_used())); + used_unlocked(), recalculate_used())); } void G1CollectedHeap::set_refine_cte_cl_concurrency(bool concurrent) { @@ -6511,7 +6417,7 @@ assert(alloc_region->is_eden(), "all mutator alloc regions should be eden"); g1_policy()->add_region_to_incremental_cset_lhs(alloc_region); - _allocator->increase_used(allocated_bytes); + increase_used(allocated_bytes); _hr_printer.retire(alloc_region); // We update the eden sizes here, when the region is retired, // instead of when it's allocated, since this is the point that its diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -251,6 +251,15 @@ // Class that handles the different kinds of allocations. G1Allocator* _allocator; + // Outside of GC pauses, the number of bytes used in all regions other + // than the current allocation region(s). + size_t _summary_bytes_used; + + void increase_used(size_t bytes); + void decrease_used(size_t bytes); + + void set_used(size_t bytes); + // Class that handles archive allocation ranges. G1ArchiveAllocator* _archive_allocator; @@ -858,44 +867,27 @@ // forwarding pointers to themselves. Reset them. void remove_self_forwarding_pointers(); - // Together, these store an object with a preserved mark, and its mark value. - Stack _objs_with_preserved_marks; - Stack _preserved_marks_of_objs; + struct OopAndMarkOop { + private: + oop _o; + markOop _m; + public: + OopAndMarkOop(oop obj, markOop m) : _o(obj), _m(m) { + } + + void set_mark() { + _o->set_mark(_m); + } + }; + + typedef Stack OopAndMarkOopStack; + // Stores marks with the corresponding oop that we need to preserve during evacuation + // failure. + OopAndMarkOopStack* _preserved_objs; // Preserve the mark of "obj", if necessary, in preparation for its mark // word being overwritten with a self-forwarding-pointer. - void preserve_mark_if_necessary(oop obj, markOop m); - - // The stack of evac-failure objects left to be scanned. - GrowableArray* _evac_failure_scan_stack; - // The closure to apply to evac-failure objects. - - OopsInHeapRegionClosure* _evac_failure_closure; - // Set the field above. - void - set_evac_failure_closure(OopsInHeapRegionClosure* evac_failure_closure) { - _evac_failure_closure = evac_failure_closure; - } - - // Push "obj" on the scan stack. - void push_on_evac_failure_scan_stack(oop obj); - // Process scan stack entries until the stack is empty. - void drain_evac_failure_scan_stack(); - // True iff an invocation of "drain_scan_stack" is in progress; to - // prevent unnecessary recursion. - bool _drain_in_progress; - - // Do any necessary initialization for evacuation-failure handling. - // "cl" is the closure that will be used to process evac-failure - // objects. - void init_for_evac_failure(OopsInHeapRegionClosure* cl); - // Do any necessary cleanup for evacuation-failure handling data - // structures. - void finalize_for_evac_failure(); - - // An attempt to evacuate "obj" has failed; take necessary steps. - oop handle_evacuation_failure_par(G1ParScanThreadState* _par_scan_state, oop obj); - void handle_evacuation_failure_common(oop obj, markOop m); + void preserve_mark_during_evac_failure(uint queue, oop obj, markOop m); #ifndef PRODUCT // Support for forcing evacuation failures. Analogous to diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/gc/g1/g1OopClosures.hpp --- a/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -111,7 +111,6 @@ enum G1Barrier { G1BarrierNone, - G1BarrierEvac, G1BarrierKlass }; @@ -148,8 +147,6 @@ // We use a separate closure to handle references during evacuation // failure processing. -typedef G1ParCopyClosure G1ParScanHeapEvacFailureClosure; - class FilterIntoCSClosure: public ExtendedOopClosure { G1CollectedHeap* _g1; OopClosure* _oc; diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp --- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -144,8 +144,6 @@ #endif // ASSERT void G1ParScanThreadState::trim_queue() { - assert(_evac_failure_cl != NULL, "not set"); - StarTask ref; do { // Drain the overflow stack first, so other threads can steal. @@ -222,7 +220,7 @@ if (obj_ptr == NULL) { // This will either forward-to-self, or detect that someone else has // installed a forwarding pointer. - return _g1h->handle_evacuation_failure_par(this, old); + return handle_evacuation_failure_par(old, old_mark); } } } @@ -236,7 +234,7 @@ // Doing this after all the allocation attempts also tests the // undo_allocation() method too. _g1_par_allocator->undo_allocation(dest_state, obj_ptr, word_sz, context); - return _g1h->handle_evacuation_failure_par(this, old); + return handle_evacuation_failure_par(old, old_mark); } #endif // !PRODUCT @@ -301,3 +299,36 @@ return forward_ptr; } } + +oop G1ParScanThreadState::handle_evacuation_failure_par(oop old, markOop m) { + assert(_g1h->obj_in_cs(old), + err_msg("Object " PTR_FORMAT " should be in the CSet", p2i(old))); + + oop forward_ptr = old->forward_to_atomic(old); + if (forward_ptr == NULL) { + // Forward-to-self succeeded. We are the "owner" of the object. + HeapRegion* r = _g1h->heap_region_containing(old); + + if (!r->evacuation_failed()) { + r->set_evacuation_failed(true); + _g1h->hr_printer()->evac_failure(r); + } + + _g1h->preserve_mark_during_evac_failure(_queue_num, old, m); + + _scanner.set_region(r); + old->oop_iterate_backwards(&_scanner); + + return old; + } else { + // Forward-to-self failed. Either someone else managed to allocate + // space for this object (old != forward_ptr) or they beat us in + // self-forwarding it (old == forward_ptr). + assert(old == forward_ptr || !_g1h->obj_in_cs(forward_ptr), + err_msg("Object " PTR_FORMAT " forwarded to: " PTR_FORMAT " " + "should not be in the CSet", + p2i(old), p2i(forward_ptr))); + return forward_ptr; + } +} + diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp --- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -54,8 +54,6 @@ uint _tenuring_threshold; G1ParScanClosure _scanner; - OopsInHeapRegionClosure* _evac_failure_cl; - int _hash_seed; uint _queue_num; @@ -114,12 +112,6 @@ } } - void set_evac_failure_closure(OopsInHeapRegionClosure* evac_failure_cl) { - _evac_failure_cl = evac_failure_cl; - } - - OopsInHeapRegionClosure* evac_failure_closure() { return _evac_failure_cl; } - int* hash_seed() { return &_hash_seed; } uint queue_num() { return _queue_num; } @@ -211,6 +203,9 @@ void trim_queue(); inline void steal_and_trim_queue(RefToScanQueueSet *task_queues); + + // An attempt to evacuate "obj" has failed; take necessary steps. + oop handle_evacuation_failure_par(oop obj, markOop m); }; #endif // SHARE_VM_GC_G1_G1PARSCANTHREADSTATE_HPP diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/gc/g1/g1_globals.hpp --- a/hotspot/src/share/vm/gc/g1/g1_globals.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/gc/g1/g1_globals.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -252,12 +252,12 @@ "Percentage (0-100) of the heap size to use as default " \ " maximum young gen size.") \ range(0, 100) \ - constraint(G1MaxNewSizePercentConstraintFunc) \ + constraint(G1MaxNewSizePercentConstraintFunc,AfterErgo) \ \ experimental(uintx, G1NewSizePercent, 5, \ "Percentage (0-100) of the heap size to use as default " \ "minimum young gen size.") \ - constraint(G1NewSizePercentConstraintFunc) \ + constraint(G1NewSizePercentConstraintFunc,AfterErgo) \ \ experimental(uintx, G1MixedGCLiveThresholdPercent, 85, \ "Threshold for regions to be considered for inclusion in the " \ diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp --- a/hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -45,13 +45,11 @@ nonstatic_field(HeapRegionManager, _regions, G1HeapRegionTable) \ nonstatic_field(HeapRegionManager, _num_committed, uint) \ \ - nonstatic_field(G1Allocator, _summary_bytes_used, size_t) \ - \ + nonstatic_field(G1CollectedHeap, _summary_bytes_used, size_t) \ nonstatic_field(G1CollectedHeap, _hrm, HeapRegionManager) \ nonstatic_field(G1CollectedHeap, _g1mm, G1MonitoringSupport*) \ nonstatic_field(G1CollectedHeap, _old_set, HeapRegionSetBase) \ nonstatic_field(G1CollectedHeap, _humongous_set, HeapRegionSetBase) \ - nonstatic_field(G1CollectedHeap, _allocator, G1Allocator*) \ \ nonstatic_field(G1MonitoringSupport, _eden_committed, size_t) \ nonstatic_field(G1MonitoringSupport, _eden_used, size_t) \ @@ -78,12 +76,10 @@ declare_toplevel_type(HeapRegionSetBase) \ declare_toplevel_type(HeapRegionSetCount) \ declare_toplevel_type(G1MonitoringSupport) \ - declare_toplevel_type(G1Allocator) \ \ declare_toplevel_type(G1CollectedHeap*) \ declare_toplevel_type(HeapRegion*) \ declare_toplevel_type(G1MonitoringSupport*) \ - declare_toplevel_type(G1Allocator*) \ #endif // SHARE_VM_GC_G1_VMSTRUCTS_G1_HPP diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/gc/parallel/cardTableExtension.cpp --- a/hotspot/src/share/vm/gc/parallel/cardTableExtension.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/gc/parallel/cardTableExtension.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -40,7 +40,6 @@ PSYoungGen* _young_gen; CardTableExtension* _card_table; HeapWord* _unmarked_addr; - jbyte* _unmarked_card; protected: template void do_oop_work(T* p) { @@ -50,7 +49,6 @@ // Don't overwrite the first missing card mark if (_unmarked_addr == NULL) { _unmarked_addr = (HeapWord*)p; - _unmarked_card = _card_table->byte_for(p); } } } diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/gc/serial/defNewGeneration.cpp --- a/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -623,7 +623,7 @@ { // DefNew needs to run with n_threads == 0, to make sure the serial // version of the card table scanning code is used. - // See: CardTableModRefBS::non_clean_card_iterate_possibly_parallel. + // See: CardTableModRefBSForCTRS::non_clean_card_iterate_possibly_parallel. StrongRootsScope srs(0); gch->gen_process_roots(&srs, diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/gc/shared/cardTableModRefBS.cpp --- a/hotspot/src/share/vm/gc/shared/cardTableModRefBS.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/gc/shared/cardTableModRefBS.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -24,22 +24,12 @@ #include "precompiled.hpp" #include "gc/shared/cardTableModRefBS.inline.hpp" -#include "gc/shared/cardTableRS.hpp" #include "gc/shared/collectedHeap.hpp" #include "gc/shared/genCollectedHeap.hpp" -#include "gc/shared/space.hpp" #include "gc/shared/space.inline.hpp" -#include "memory/allocation.inline.hpp" -#include "memory/universe.hpp" #include "memory/virtualspace.hpp" -#include "runtime/java.hpp" -#include "runtime/mutexLocker.hpp" #include "services/memTracker.hpp" #include "utilities/macros.hpp" -#ifdef COMPILER1 -#include "c1/c1_LIR.hpp" -#include "c1/c1_LIRGenerator.hpp" -#endif // This kind of "BarrierSet" allows a "CollectedHeap" to detect and // enumerate ref fields that have been modified (since the last @@ -68,12 +58,7 @@ _committed(NULL), _cur_covered_regions(0), _byte_map(NULL), - byte_map_base(NULL), - // LNC functionality - _lowest_non_clean(NULL), - _lowest_non_clean_chunk_size(NULL), - _lowest_non_clean_base_chunk_index(NULL), - _last_LNC_resizing_collection(NULL) + byte_map_base(NULL) { assert((uintptr_t(_whole_heap.start()) & (card_size - 1)) == 0, "heap must start at card boundary"); assert((uintptr_t(_whole_heap.end()) & (card_size - 1)) == 0, "heap must end at card boundary"); @@ -130,25 +115,6 @@ !ExecMem, "card table last card"); *guard_card = last_card; - _lowest_non_clean = - NEW_C_HEAP_ARRAY(CardArr, _max_covered_regions, mtGC); - _lowest_non_clean_chunk_size = - NEW_C_HEAP_ARRAY(size_t, _max_covered_regions, mtGC); - _lowest_non_clean_base_chunk_index = - NEW_C_HEAP_ARRAY(uintptr_t, _max_covered_regions, mtGC); - _last_LNC_resizing_collection = - NEW_C_HEAP_ARRAY(int, _max_covered_regions, mtGC); - if (_lowest_non_clean == NULL - || _lowest_non_clean_chunk_size == NULL - || _lowest_non_clean_base_chunk_index == NULL - || _last_LNC_resizing_collection == NULL) - vm_exit_during_initialization("couldn't allocate an LNC array."); - for (int i = 0; i < _max_covered_regions; i++) { - _lowest_non_clean[i] = NULL; - _lowest_non_clean_chunk_size[i] = 0; - _last_LNC_resizing_collection[i] = -1; - } - if (TraceCardTableModRefBS) { gclog_or_tty->print_cr("CardTableModRefBS::CardTableModRefBS: "); gclog_or_tty->print_cr(" " @@ -171,22 +137,6 @@ delete[] _committed; _committed = NULL; } - if (_lowest_non_clean) { - FREE_C_HEAP_ARRAY(CardArr, _lowest_non_clean); - _lowest_non_clean = NULL; - } - if (_lowest_non_clean_chunk_size) { - FREE_C_HEAP_ARRAY(size_t, _lowest_non_clean_chunk_size); - _lowest_non_clean_chunk_size = NULL; - } - if (_lowest_non_clean_base_chunk_index) { - FREE_C_HEAP_ARRAY(uintptr_t, _lowest_non_clean_base_chunk_index); - _lowest_non_clean_base_chunk_index = NULL; - } - if (_last_LNC_resizing_collection) { - FREE_C_HEAP_ARRAY(int, _last_LNC_resizing_collection); - _last_LNC_resizing_collection = NULL; - } } int CardTableModRefBS::find_covering_region_by_base(HeapWord* base) { @@ -437,32 +387,6 @@ } -void CardTableModRefBS::non_clean_card_iterate_possibly_parallel(Space* sp, - MemRegion mr, - OopsInGenClosure* cl, - CardTableRS* ct, - uint n_threads) { - if (!mr.is_empty()) { - if (n_threads > 0) { -#if INCLUDE_ALL_GCS - non_clean_card_iterate_parallel_work(sp, mr, cl, ct, n_threads); -#else // INCLUDE_ALL_GCS - fatal("Parallel gc not supported here."); -#endif // INCLUDE_ALL_GCS - } else { - // clear_cl finds contiguous dirty ranges of cards to process and clear. - - // This is the single-threaded version used by DefNew. - const bool parallel = false; - - DirtyCardToOopClosure* dcto_cl = sp->new_dcto_cl(cl, precision(), cl->gen_boundary(), parallel); - ClearNoncleanCardWrapper clear_cl(dcto_cl, ct, parallel); - - clear_cl.do_MemRegion(mr); - } - } -} - void CardTableModRefBS::dirty_MemRegion(MemRegion mr) { assert((HeapWord*)align_size_down((uintptr_t)mr.start(), HeapWordSize) == mr.start(), "Unaligned start"); assert((HeapWord*)align_size_up ((uintptr_t)mr.end(), HeapWordSize) == mr.end(), "Unaligned end" ); @@ -623,15 +547,3 @@ p2i(_byte_map), p2i(_byte_map + _byte_map_size), p2i(byte_map_base)); } -bool CardTableModRefBSForCTRS::card_will_be_scanned(jbyte cv) { - return - CardTableModRefBS::card_will_be_scanned(cv) || - _rs->is_prev_nonclean_card_val(cv); -}; - -bool CardTableModRefBSForCTRS::card_may_have_been_dirty(jbyte cv) { - return - cv != clean_card && - (CardTableModRefBS::card_may_have_been_dirty(cv) || - CardTableRS::youngergen_may_have_been_dirty(cv)); -}; diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/gc/shared/cardTableModRefBS.hpp --- a/hotspot/src/share/vm/gc/shared/cardTableModRefBS.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/gc/shared/cardTableModRefBS.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -40,23 +40,9 @@ // Closures used to scan dirty cards should take these // considerations into account. -class Generation; -class OopsInGenClosure; -class DirtyCardToOopClosure; -class ClearNoncleanCardWrapper; -class CardTableRS; - class CardTableModRefBS: public ModRefBarrierSet { // Some classes get to look at some private stuff. - friend class BytecodeInterpreter; friend class VMStructs; - friend class CardTableRS; - friend class CheckForUnmarkedOops; // Needs access to raw card bytes. - friend class SharkBuilder; -#ifndef PRODUCT - // For debugging. - friend class GuaranteeNotModClosure; -#endif protected: enum CardValues { @@ -75,24 +61,6 @@ // a word's worth (row) of clean card values static const intptr_t clean_card_row = (intptr_t)(-1); - // dirty and precleaned are equivalent wrt younger_refs_iter. - static bool card_is_dirty_wrt_gen_iter(jbyte cv) { - return cv == dirty_card || cv == precleaned_card; - } - - // Returns "true" iff the value "cv" will cause the card containing it - // to be scanned in the current traversal. May be overridden by - // subtypes. - virtual bool card_will_be_scanned(jbyte cv) { - return CardTableModRefBS::card_is_dirty_wrt_gen_iter(cv); - } - - // Returns "true" iff the value "cv" may have represented a dirty card at - // some point. - virtual bool card_may_have_been_dirty(jbyte cv) { - return card_is_dirty_wrt_gen_iter(cv); - } - // The declaration order of these const fields is important; see the // constructor before changing. const MemRegion _whole_heap; // the region covered by the card table @@ -174,20 +142,6 @@ return byte_for(p) + 1; } - // Iterate over the portion of the card-table which covers the given - // region mr in the given space and apply cl to any dirty sub-regions - // of mr. Clears the dirty cards as they are processed. - void non_clean_card_iterate_possibly_parallel(Space* sp, MemRegion mr, - OopsInGenClosure* cl, CardTableRS* ct, - uint n_threads); - - private: - // Work method used to implement non_clean_card_iterate_possibly_parallel() - // above in the parallel case. - void non_clean_card_iterate_parallel_work(Space* sp, MemRegion mr, - OopsInGenClosure* cl, CardTableRS* ct, - uint n_threads); - protected: // Dirty the bytes corresponding to "mr" (not all of which must be // covered.) @@ -197,65 +151,6 @@ // all of which must be covered.) void clear_MemRegion(MemRegion mr); - // *** Support for parallel card scanning. - - // This is an array, one element per covered region of the card table. - // Each entry is itself an array, with one element per chunk in the - // covered region. Each entry of these arrays is the lowest non-clean - // card of the corresponding chunk containing part of an object from the - // previous chunk, or else NULL. - typedef jbyte* CardPtr; - typedef CardPtr* CardArr; - CardArr* _lowest_non_clean; - size_t* _lowest_non_clean_chunk_size; - uintptr_t* _lowest_non_clean_base_chunk_index; - int* _last_LNC_resizing_collection; - - // Initializes "lowest_non_clean" to point to the array for the region - // covering "sp", and "lowest_non_clean_base_chunk_index" to the chunk - // index of the corresponding to the first element of that array. - // Ensures that these arrays are of sufficient size, allocating if necessary. - // May be called by several threads concurrently. - void get_LNC_array_for_space(Space* sp, - jbyte**& lowest_non_clean, - uintptr_t& lowest_non_clean_base_chunk_index, - size_t& lowest_non_clean_chunk_size); - - // Returns the number of chunks necessary to cover "mr". - size_t chunks_to_cover(MemRegion mr) { - return (size_t)(addr_to_chunk_index(mr.last()) - - addr_to_chunk_index(mr.start()) + 1); - } - - // Returns the index of the chunk in a stride which - // covers the given address. - uintptr_t addr_to_chunk_index(const void* addr) { - uintptr_t card = (uintptr_t) byte_for(addr); - return card / ParGCCardsPerStrideChunk; - } - - // Apply cl, which must either itself apply dcto_cl or be dcto_cl, - // to the cards in the stride (of n_strides) within the given space. - void process_stride(Space* sp, - MemRegion used, - jint stride, int n_strides, - OopsInGenClosure* cl, - CardTableRS* ct, - jbyte** lowest_non_clean, - uintptr_t lowest_non_clean_base_chunk_index, - size_t lowest_non_clean_chunk_size); - - // Makes sure that chunk boundaries are handled appropriately, by - // adjusting the min_done of dcto_cl, and by using a special card-table - // value to indicate how min_done should be set. - void process_chunk_boundaries(Space* sp, - DirtyCardToOopClosure* dcto_cl, - MemRegion chunk_mr, - MemRegion used, - jbyte** lowest_non_clean, - uintptr_t lowest_non_clean_base_chunk_index, - size_t lowest_non_clean_chunk_size); - public: // Constants enum SomePublicConstants { @@ -436,34 +331,5 @@ static const BarrierSet::Name value = BarrierSet::CardTableModRef; }; -class CardTableRS; - -// A specialization for the CardTableRS gen rem set. -class CardTableModRefBSForCTRS: public CardTableModRefBS { - CardTableRS* _rs; -protected: - bool card_will_be_scanned(jbyte cv); - bool card_may_have_been_dirty(jbyte cv); -public: - CardTableModRefBSForCTRS(MemRegion whole_heap) : - CardTableModRefBS( - whole_heap, - // Concrete tag should be BarrierSet::CardTableForRS. - // That will presently break things in a bunch of places though. - // The concrete tag is used as a dispatch key in many places, and - // CardTableForRS does not correctly dispatch in some of those - // uses. This will be addressed as part of a reorganization of the - // BarrierSet hierarchy. - BarrierSet::FakeRtti(BarrierSet::CardTableModRef, 0).add_tag(BarrierSet::CardTableForRS)) - {} - - void set_CTRS(CardTableRS* rs) { _rs = rs; } -}; - -template<> -struct BarrierSet::GetName { - static const BarrierSet::Name value = BarrierSet::CardTableForRS; -}; - #endif // SHARE_VM_GC_SHARED_CARDTABLEMODREFBS_HPP diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/gc/shared/cardTableModRefBSForCTRS.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/gc/shared/cardTableModRefBSForCTRS.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -0,0 +1,129 @@ +/* + * 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. + * + */ + +#include "precompiled.hpp" +#include "gc/shared/cardTableModRefBS.inline.hpp" +#include "gc/shared/cardTableRS.hpp" +#include "memory/allocation.inline.hpp" +#include "gc/shared/space.inline.hpp" + +CardTableModRefBSForCTRS::CardTableModRefBSForCTRS(MemRegion whole_heap) : + CardTableModRefBS( + whole_heap, + // Concrete tag should be BarrierSet::CardTableForRS. + // That will presently break things in a bunch of places though. + // The concrete tag is used as a dispatch key in many places, and + // CardTableForRS does not correctly dispatch in some of those + // uses. This will be addressed as part of a reorganization of the + // BarrierSet hierarchy. + BarrierSet::FakeRtti(BarrierSet::CardTableModRef, 0).add_tag(BarrierSet::CardTableForRS)), + // LNC functionality + _lowest_non_clean(NULL), + _lowest_non_clean_chunk_size(NULL), + _lowest_non_clean_base_chunk_index(NULL), + _last_LNC_resizing_collection(NULL) +{ } + +void CardTableModRefBSForCTRS::initialize() { + CardTableModRefBS::initialize(); + _lowest_non_clean = + NEW_C_HEAP_ARRAY(CardArr, _max_covered_regions, mtGC); + _lowest_non_clean_chunk_size = + NEW_C_HEAP_ARRAY(size_t, _max_covered_regions, mtGC); + _lowest_non_clean_base_chunk_index = + NEW_C_HEAP_ARRAY(uintptr_t, _max_covered_regions, mtGC); + _last_LNC_resizing_collection = + NEW_C_HEAP_ARRAY(int, _max_covered_regions, mtGC); + if (_lowest_non_clean == NULL + || _lowest_non_clean_chunk_size == NULL + || _lowest_non_clean_base_chunk_index == NULL + || _last_LNC_resizing_collection == NULL) + vm_exit_during_initialization("couldn't allocate an LNC array."); + for (int i = 0; i < _max_covered_regions; i++) { + _lowest_non_clean[i] = NULL; + _lowest_non_clean_chunk_size[i] = 0; + _last_LNC_resizing_collection[i] = -1; + } +} + +CardTableModRefBSForCTRS::~CardTableModRefBSForCTRS() { + if (_lowest_non_clean) { + FREE_C_HEAP_ARRAY(CardArr, _lowest_non_clean); + _lowest_non_clean = NULL; + } + if (_lowest_non_clean_chunk_size) { + FREE_C_HEAP_ARRAY(size_t, _lowest_non_clean_chunk_size); + _lowest_non_clean_chunk_size = NULL; + } + if (_lowest_non_clean_base_chunk_index) { + FREE_C_HEAP_ARRAY(uintptr_t, _lowest_non_clean_base_chunk_index); + _lowest_non_clean_base_chunk_index = NULL; + } + if (_last_LNC_resizing_collection) { + FREE_C_HEAP_ARRAY(int, _last_LNC_resizing_collection); + _last_LNC_resizing_collection = NULL; + } +} + +bool CardTableModRefBSForCTRS::card_will_be_scanned(jbyte cv) { + return + card_is_dirty_wrt_gen_iter(cv) || + _rs->is_prev_nonclean_card_val(cv); +} + +bool CardTableModRefBSForCTRS::card_may_have_been_dirty(jbyte cv) { + return + cv != clean_card && + (card_is_dirty_wrt_gen_iter(cv) || + CardTableRS::youngergen_may_have_been_dirty(cv)); +} + +void CardTableModRefBSForCTRS::non_clean_card_iterate_possibly_parallel( + Space* sp, + MemRegion mr, + OopsInGenClosure* cl, + CardTableRS* ct, + uint n_threads) +{ + if (!mr.is_empty()) { + if (n_threads > 0) { +#if INCLUDE_ALL_GCS + non_clean_card_iterate_parallel_work(sp, mr, cl, ct, n_threads); +#else // INCLUDE_ALL_GCS + fatal("Parallel gc not supported here."); +#endif // INCLUDE_ALL_GCS + } else { + // clear_cl finds contiguous dirty ranges of cards to process and clear. + + // This is the single-threaded version used by DefNew. + const bool parallel = false; + + DirtyCardToOopClosure* dcto_cl = sp->new_dcto_cl(cl, precision(), cl->gen_boundary(), parallel); + ClearNoncleanCardWrapper clear_cl(dcto_cl, ct, parallel); + + clear_cl.do_MemRegion(mr); + } + } +} + diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/gc/shared/cardTableModRefBSForCTRS.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/gc/shared/cardTableModRefBSForCTRS.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -0,0 +1,143 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_GC_SHARED_CARDTABLEMODREFBSFORCTRS_HPP +#define SHARE_VM_GC_SHARED_CARDTABLEMODREFBSFORCTRS_HPP + +#include "gc/shared/cardTableModRefBS.hpp" + +class CardTableRS; +class DirtyCardToOopClosure; +class OopsInGenClosure; + +// A specialization for the CardTableRS gen rem set. +class CardTableModRefBSForCTRS: public CardTableModRefBS { + friend class CardTableRS; + +public: + CardTableModRefBSForCTRS(MemRegion whole_heap); + ~CardTableModRefBSForCTRS(); + + virtual void initialize(); + + void set_CTRS(CardTableRS* rs) { _rs = rs; } + +private: + CardTableRS* _rs; + + // *** Support for parallel card scanning. + + // dirty and precleaned are equivalent wrt younger_refs_iter. + static bool card_is_dirty_wrt_gen_iter(jbyte cv) { + return cv == dirty_card || cv == precleaned_card; + } + + // Returns "true" iff the value "cv" will cause the card containing it + // to be scanned in the current traversal. May be overridden by + // subtypes. + bool card_will_be_scanned(jbyte cv); + + // Returns "true" iff the value "cv" may have represented a dirty card at + // some point. + bool card_may_have_been_dirty(jbyte cv); + + // Iterate over the portion of the card-table which covers the given + // region mr in the given space and apply cl to any dirty sub-regions + // of mr. Clears the dirty cards as they are processed. + void non_clean_card_iterate_possibly_parallel(Space* sp, MemRegion mr, + OopsInGenClosure* cl, CardTableRS* ct, + uint n_threads); + + // Work method used to implement non_clean_card_iterate_possibly_parallel() + // above in the parallel case. + void non_clean_card_iterate_parallel_work(Space* sp, MemRegion mr, + OopsInGenClosure* cl, CardTableRS* ct, + uint n_threads); + + // This is an array, one element per covered region of the card table. + // Each entry is itself an array, with one element per chunk in the + // covered region. Each entry of these arrays is the lowest non-clean + // card of the corresponding chunk containing part of an object from the + // previous chunk, or else NULL. + typedef jbyte* CardPtr; + typedef CardPtr* CardArr; + CardArr* _lowest_non_clean; + size_t* _lowest_non_clean_chunk_size; + uintptr_t* _lowest_non_clean_base_chunk_index; + int* _last_LNC_resizing_collection; + + // Initializes "lowest_non_clean" to point to the array for the region + // covering "sp", and "lowest_non_clean_base_chunk_index" to the chunk + // index of the corresponding to the first element of that array. + // Ensures that these arrays are of sufficient size, allocating if necessary. + // May be called by several threads concurrently. + void get_LNC_array_for_space(Space* sp, + jbyte**& lowest_non_clean, + uintptr_t& lowest_non_clean_base_chunk_index, + size_t& lowest_non_clean_chunk_size); + + // Returns the number of chunks necessary to cover "mr". + size_t chunks_to_cover(MemRegion mr) { + return (size_t)(addr_to_chunk_index(mr.last()) - + addr_to_chunk_index(mr.start()) + 1); + } + + // Returns the index of the chunk in a stride which + // covers the given address. + uintptr_t addr_to_chunk_index(const void* addr) { + uintptr_t card = (uintptr_t) byte_for(addr); + return card / ParGCCardsPerStrideChunk; + } + + // Apply cl, which must either itself apply dcto_cl or be dcto_cl, + // to the cards in the stride (of n_strides) within the given space. + void process_stride(Space* sp, + MemRegion used, + jint stride, int n_strides, + OopsInGenClosure* cl, + CardTableRS* ct, + jbyte** lowest_non_clean, + uintptr_t lowest_non_clean_base_chunk_index, + size_t lowest_non_clean_chunk_size); + + // Makes sure that chunk boundaries are handled appropriately, by + // adjusting the min_done of dcto_cl, and by using a special card-table + // value to indicate how min_done should be set. + void process_chunk_boundaries(Space* sp, + DirtyCardToOopClosure* dcto_cl, + MemRegion chunk_mr, + MemRegion used, + jbyte** lowest_non_clean, + uintptr_t lowest_non_clean_base_chunk_index, + size_t lowest_non_clean_chunk_size); + +}; + +template<> +struct BarrierSet::GetName { + static const BarrierSet::Name value = BarrierSet::CardTableForRS; +}; + +#endif // include guard + diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/gc/shared/cardTableRS.cpp --- a/hotspot/src/share/vm/gc/shared/cardTableRS.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/gc/shared/cardTableRS.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -240,7 +240,7 @@ // cur-younger-gen ==> cur_younger_gen // cur_youngergen_and_prev_nonclean_card ==> no change. void CardTableRS::write_ref_field_gc_par(void* field, oop new_val) { - jbyte* entry = ct_bs()->byte_for(field); + jbyte* entry = _ct_bs->byte_for(field); do { jbyte entry_val = *entry; // We put this first because it's probably the most common case. @@ -398,10 +398,10 @@ jbyte* cur_entry = byte_for(used.start()); jbyte* limit = byte_after(used.last()); while (cur_entry < limit) { - if (*cur_entry == CardTableModRefBS::clean_card) { + if (*cur_entry == clean_card_val()) { jbyte* first_dirty = cur_entry+1; while (first_dirty < limit && - *first_dirty == CardTableModRefBS::clean_card) { + *first_dirty == clean_card_val()) { first_dirty++; } // If the first object is a regular object, and it has a @@ -418,7 +418,7 @@ !boundary_obj->is_typeArray()) { guarantee(cur_entry > byte_for(used.start()), "else boundary would be boundary_block"); - if (*byte_for(boundary_block) != CardTableModRefBS::clean_card) { + if (*byte_for(boundary_block) != clean_card_val()) { begin = boundary_block + s->block_size(boundary_block); start_block = begin; } diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/gc/shared/cardTableRS.hpp --- a/hotspot/src/share/vm/gc/shared/cardTableRS.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/gc/shared/cardTableRS.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -25,7 +25,7 @@ #ifndef SHARE_VM_GC_SHARED_CARDTABLERS_HPP #define SHARE_VM_GC_SHARED_CARDTABLERS_HPP -#include "gc/shared/cardTableModRefBS.hpp" +#include "gc/shared/cardTableModRefBSForCTRS.hpp" #include "gc/shared/genRemSet.hpp" #include "memory/memRegion.hpp" @@ -42,16 +42,16 @@ friend class ClearNoncleanCardWrapper; static jbyte clean_card_val() { - return CardTableModRefBS::clean_card; + return CardTableModRefBSForCTRS::clean_card; } static intptr_t clean_card_row() { - return CardTableModRefBS::clean_card_row; + return CardTableModRefBSForCTRS::clean_card_row; } static bool card_is_dirty_wrt_gen_iter(jbyte cv) { - return CardTableModRefBS::card_is_dirty_wrt_gen_iter(cv); + return CardTableModRefBSForCTRS::card_is_dirty_wrt_gen_iter(cv); } CardTableModRefBSForCTRS* _ct_bs; @@ -61,17 +61,17 @@ void verify_space(Space* s, HeapWord* gen_start); enum ExtendedCardValue { - youngergen_card = CardTableModRefBS::CT_MR_BS_last_reserved + 1, + youngergen_card = CardTableModRefBSForCTRS::CT_MR_BS_last_reserved + 1, // These are for parallel collection. // There are three P (parallel) youngergen card values. In general, this // needs to be more than the number of generations (including the perm // gen) that might have younger_refs_do invoked on them separately. So // if we add more gens, we have to add more values. - youngergenP1_card = CardTableModRefBS::CT_MR_BS_last_reserved + 2, - youngergenP2_card = CardTableModRefBS::CT_MR_BS_last_reserved + 3, - youngergenP3_card = CardTableModRefBS::CT_MR_BS_last_reserved + 4, + youngergenP1_card = CardTableModRefBSForCTRS::CT_MR_BS_last_reserved + 2, + youngergenP2_card = CardTableModRefBSForCTRS::CT_MR_BS_last_reserved + 3, + youngergenP3_card = CardTableModRefBSForCTRS::CT_MR_BS_last_reserved + 4, cur_youngergen_and_prev_nonclean_card = - CardTableModRefBS::CT_MR_BS_last_reserved + 5 + CardTableModRefBSForCTRS::CT_MR_BS_last_reserved + 5 }; // An array that contains, for each generation, the card table value last @@ -107,7 +107,7 @@ // *** GenRemSet functions. CardTableRS* as_CardTableRS() { return this; } - CardTableModRefBS* ct_bs() { return _ct_bs; } + CardTableModRefBSForCTRS* ct_bs() { return _ct_bs; } // Override. void prepare_for_younger_refs_iterate(bool parallel); @@ -147,7 +147,7 @@ void invalidate_or_clear(Generation* old_gen); static uintx ct_max_alignment_constraint() { - return CardTableModRefBS::ct_max_alignment_constraint(); + return CardTableModRefBSForCTRS::ct_max_alignment_constraint(); } jbyte* byte_for(void* p) { return _ct_bs->byte_for(p); } diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/gc/shared/taskqueue.hpp --- a/hotspot/src/share/vm/gc/shared/taskqueue.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/gc/shared/taskqueue.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -295,8 +295,9 @@ // Delete any resource associated with the queue. ~GenericTaskQueue(); - // apply the closure to all elements in the task queue - void oops_do(OopClosure* f); + // Apply fn to each element in the task queue. The queue must not + // be modified while iterating. + template void iterate(Fn fn); private: // Element array. diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/gc/shared/taskqueue.inline.hpp --- a/hotspot/src/share/vm/gc/shared/taskqueue.inline.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/gc/shared/taskqueue.inline.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -259,20 +259,14 @@ } template -inline void GenericTaskQueue::oops_do(OopClosure* f) { - // tty->print_cr("START OopTaskQueue::oops_do"); +template +inline void GenericTaskQueue::iterate(Fn fn) { uint iters = size(); uint index = _bottom; for (uint i = 0; i < iters; ++i) { index = decrement_index(index); - // tty->print_cr(" doing entry %d," INTPTR_T " -> " INTPTR_T, - // index, &_elems[index], _elems[index]); - E* t = (E*)&_elems[index]; // cast away volatility - oop* p = (oop*)t; - assert((*t)->is_oop_or_null(), err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(*t))); - f->do_oop(p); + fn(const_cast(_elems[index])); // cast away volatility } - // tty->print_cr("END OopTaskQueue::oops_do"); } diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/memory/universe.cpp --- a/hotspot/src/share/vm/memory/universe.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/memory/universe.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -56,6 +56,7 @@ #include "prims/jvmtiRedefineClassesTrace.hpp" #include "runtime/arguments.hpp" #include "runtime/atomic.inline.hpp" +#include "runtime/commandLineFlagConstraintList.hpp" #include "runtime/deoptimization.hpp" #include "runtime/fprofiler.hpp" #include "runtime/handles.inline.hpp" @@ -656,6 +657,11 @@ Metaspace::global_initialize(); + // Checks 'AfterMemoryInit' constraints. + if (!CommandLineFlagConstraintList::check_constraints(CommandLineFlagConstraint::AfterMemoryInit)) { + return JNI_EINVAL; + } + // Create memory for metadata. Must be after initializing heap for // DumpSharedSpaces. ClassLoaderData::init_null_class_loader_data(); diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/oops/oop.hpp --- a/hotspot/src/share/vm/oops/oop.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/oops/oop.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -200,7 +200,6 @@ // Access to fields in a instanceOop through these methods. oop obj_field(int offset) const; - volatile oop obj_field_volatile(int offset) const; void obj_field_put(int offset, oop value); void obj_field_put_raw(int offset, oop value); void obj_field_put_volatile(int offset, oop value); diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/oops/oop.inline.hpp --- a/hotspot/src/share/vm/oops/oop.inline.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/oops/oop.inline.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -284,11 +284,7 @@ load_decode_heap_oop(obj_field_addr(offset)) : load_decode_heap_oop(obj_field_addr(offset)); } -inline volatile oop oopDesc::obj_field_volatile(int offset) const { - volatile oop value = obj_field(offset); - OrderAccess::acquire(); - return value; -} + inline void oopDesc::obj_field_put(int offset, oop value) { UseCompressedOops ? oop_store(obj_field_addr(offset), value) : oop_store(obj_field_addr(offset), value); diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/opto/c2_globals.hpp --- a/hotspot/src/share/vm/opto/c2_globals.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/opto/c2_globals.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -659,7 +659,7 @@ "0 for no aliasing, 1 for oop/field/static/array split, " \ "2 for class split, 3 for unique instances") \ range(0, 3) \ - constraint(AliasLevelConstraintFunc) \ + constraint(AliasLevelConstraintFunc,AfterErgo) \ \ develop(bool, VerifyAliases, false, \ "perform extra checks on the results of alias analysis") \ diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/opto/c2compiler.cpp --- a/hotspot/src/share/vm/opto/c2compiler.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/opto/c2compiler.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -79,7 +79,6 @@ return OptoRuntime::generate(thread->env()); } - void C2Compiler::initialize() { // The first compiler thread that gets here will initialize the // small amount of global state (and runtime stubs) that C2 needs. @@ -154,11 +153,361 @@ } } - void C2Compiler::print_timers() { Compile::print_timers(); } +bool C2Compiler::is_intrinsic_available(methodHandle method, methodHandle compilation_context) { + // Assume a non-virtual dispatch. A virtual dispatch is + // possible for only a limited set of available intrinsics whereas + // a non-virtual dispatch is possible for all available intrinsics. + return is_intrinsic_supported(method, false) && + !is_intrinsic_disabled_by_flag(method, compilation_context); +} + +bool C2Compiler::is_intrinsic_supported(methodHandle method, bool is_virtual) { + vmIntrinsics::ID id = method->intrinsic_id(); + assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); + + if (id < vmIntrinsics::FIRST_ID || id >= vmIntrinsics::LAST_COMPILER_INLINE) { + return false; + } + + // Only Object.hashCode and Object.clone intrinsics implement also a virtual + // dispatch because calling both methods is expensive but both methods are + // frequently overridden. All other intrinsics implement only a non-virtual + // dispatch. + if (is_virtual) { + switch (id) { + case vmIntrinsics::_hashCode: + case vmIntrinsics::_clone: + break; + default: + return false; + } + } + + switch (id) { + case vmIntrinsics::_compareTo: + if (!Matcher::match_rule_supported(Op_StrComp)) return false; + break; + case vmIntrinsics::_equals: + if (!Matcher::match_rule_supported(Op_StrEquals)) return false; + break; + case vmIntrinsics::_equalsC: + if (!Matcher::match_rule_supported(Op_AryEq)) return false; + break; + case vmIntrinsics::_copyMemory: + if (StubRoutines::unsafe_arraycopy() == NULL) return false; + break; + case vmIntrinsics::_encodeISOArray: + if (!Matcher::match_rule_supported(Op_EncodeISOArray)) return false; + break; + case vmIntrinsics::_bitCount_i: + if (!Matcher::match_rule_supported(Op_PopCountI)) return false; + break; + case vmIntrinsics::_bitCount_l: + if (!Matcher::match_rule_supported(Op_PopCountL)) return false; + break; + case vmIntrinsics::_numberOfLeadingZeros_i: + if (!Matcher::match_rule_supported(Op_CountLeadingZerosI)) return false; + break; + case vmIntrinsics::_numberOfLeadingZeros_l: + if (!Matcher::match_rule_supported(Op_CountLeadingZerosL)) return false; + break; + case vmIntrinsics::_numberOfTrailingZeros_i: + if (!Matcher::match_rule_supported(Op_CountTrailingZerosI)) return false; + break; + case vmIntrinsics::_numberOfTrailingZeros_l: + if (!Matcher::match_rule_supported(Op_CountTrailingZerosL)) return false; + break; + case vmIntrinsics::_reverseBytes_c: + if (!Matcher::match_rule_supported(Op_ReverseBytesUS)) return false; + break; + case vmIntrinsics::_reverseBytes_s: + if (!Matcher::match_rule_supported(Op_ReverseBytesS)) return false; + break; + case vmIntrinsics::_reverseBytes_i: + if (!Matcher::match_rule_supported(Op_ReverseBytesI)) return false; + break; + case vmIntrinsics::_reverseBytes_l: + if (!Matcher::match_rule_supported(Op_ReverseBytesL)) return false; + break; + case vmIntrinsics::_compareAndSwapObject: +#ifdef _LP64 + if (!UseCompressedOops && !Matcher::match_rule_supported(Op_CompareAndSwapP)) return false; +#endif + break; + case vmIntrinsics::_compareAndSwapLong: + if (!Matcher::match_rule_supported(Op_CompareAndSwapL)) return false; + break; + case vmIntrinsics::_getAndAddInt: + if (!Matcher::match_rule_supported(Op_GetAndAddI)) return false; + break; + case vmIntrinsics::_getAndAddLong: + if (!Matcher::match_rule_supported(Op_GetAndAddL)) return false; + break; + case vmIntrinsics::_getAndSetInt: + if (!Matcher::match_rule_supported(Op_GetAndSetI)) return false; + break; + case vmIntrinsics::_getAndSetLong: + if (!Matcher::match_rule_supported(Op_GetAndSetL)) return false; + break; + case vmIntrinsics::_getAndSetObject: +#ifdef _LP64 + if (!UseCompressedOops && !Matcher::match_rule_supported(Op_GetAndSetP)) return false; + if (UseCompressedOops && !Matcher::match_rule_supported(Op_GetAndSetN)) return false; + break; +#else + if (!Matcher::match_rule_supported(Op_GetAndSetP)) return false; + break; +#endif + case vmIntrinsics::_incrementExactI: + case vmIntrinsics::_addExactI: + if (!Matcher::match_rule_supported(Op_OverflowAddI)) return false; + break; + case vmIntrinsics::_incrementExactL: + case vmIntrinsics::_addExactL: + if (!Matcher::match_rule_supported(Op_OverflowAddL)) return false; + break; + case vmIntrinsics::_decrementExactI: + case vmIntrinsics::_subtractExactI: + if (!Matcher::match_rule_supported(Op_OverflowSubI)) return false; + break; + case vmIntrinsics::_decrementExactL: + case vmIntrinsics::_subtractExactL: + if (!Matcher::match_rule_supported(Op_OverflowSubL)) return false; + break; + case vmIntrinsics::_negateExactI: + if (!Matcher::match_rule_supported(Op_OverflowSubI)) return false; + break; + case vmIntrinsics::_negateExactL: + if (!Matcher::match_rule_supported(Op_OverflowSubL)) return false; + break; + case vmIntrinsics::_multiplyExactI: + if (!Matcher::match_rule_supported(Op_OverflowMulI)) return false; + break; + case vmIntrinsics::_multiplyExactL: + if (!Matcher::match_rule_supported(Op_OverflowMulL)) return false; + break; + case vmIntrinsics::_getCallerClass: + if (SystemDictionary::reflect_CallerSensitive_klass() == NULL) return false; + break; + case vmIntrinsics::_hashCode: + case vmIntrinsics::_identityHashCode: + case vmIntrinsics::_getClass: + case vmIntrinsics::_dsin: + case vmIntrinsics::_dcos: + case vmIntrinsics::_dtan: + case vmIntrinsics::_dabs: + case vmIntrinsics::_datan2: + case vmIntrinsics::_dsqrt: + case vmIntrinsics::_dexp: + case vmIntrinsics::_dlog: + case vmIntrinsics::_dlog10: + case vmIntrinsics::_dpow: + case vmIntrinsics::_min: + case vmIntrinsics::_max: + case vmIntrinsics::_arraycopy: + case vmIntrinsics::_indexOf: + case vmIntrinsics::_getObject: + case vmIntrinsics::_getBoolean: + case vmIntrinsics::_getByte: + case vmIntrinsics::_getShort: + case vmIntrinsics::_getChar: + case vmIntrinsics::_getInt: + case vmIntrinsics::_getLong: + case vmIntrinsics::_getFloat: + case vmIntrinsics::_getDouble: + case vmIntrinsics::_putObject: + case vmIntrinsics::_putBoolean: + case vmIntrinsics::_putByte: + case vmIntrinsics::_putShort: + case vmIntrinsics::_putChar: + case vmIntrinsics::_putInt: + case vmIntrinsics::_putLong: + case vmIntrinsics::_putFloat: + case vmIntrinsics::_putDouble: + case vmIntrinsics::_getByte_raw: + case vmIntrinsics::_getShort_raw: + case vmIntrinsics::_getChar_raw: + case vmIntrinsics::_getInt_raw: + case vmIntrinsics::_getLong_raw: + case vmIntrinsics::_getFloat_raw: + case vmIntrinsics::_getDouble_raw: + case vmIntrinsics::_getAddress_raw: + case vmIntrinsics::_putByte_raw: + case vmIntrinsics::_putShort_raw: + case vmIntrinsics::_putChar_raw: + case vmIntrinsics::_putInt_raw: + case vmIntrinsics::_putLong_raw: + case vmIntrinsics::_putFloat_raw: + case vmIntrinsics::_putDouble_raw: + case vmIntrinsics::_putAddress_raw: + case vmIntrinsics::_getObjectVolatile: + case vmIntrinsics::_getBooleanVolatile: + case vmIntrinsics::_getByteVolatile: + case vmIntrinsics::_getShortVolatile: + case vmIntrinsics::_getCharVolatile: + case vmIntrinsics::_getIntVolatile: + case vmIntrinsics::_getLongVolatile: + case vmIntrinsics::_getFloatVolatile: + case vmIntrinsics::_getDoubleVolatile: + case vmIntrinsics::_putObjectVolatile: + case vmIntrinsics::_putBooleanVolatile: + case vmIntrinsics::_putByteVolatile: + case vmIntrinsics::_putShortVolatile: + case vmIntrinsics::_putCharVolatile: + case vmIntrinsics::_putIntVolatile: + case vmIntrinsics::_putLongVolatile: + case vmIntrinsics::_putFloatVolatile: + case vmIntrinsics::_putDoubleVolatile: + case vmIntrinsics::_getShortUnaligned: + case vmIntrinsics::_getCharUnaligned: + case vmIntrinsics::_getIntUnaligned: + case vmIntrinsics::_getLongUnaligned: + case vmIntrinsics::_putShortUnaligned: + case vmIntrinsics::_putCharUnaligned: + case vmIntrinsics::_putIntUnaligned: + case vmIntrinsics::_putLongUnaligned: + case vmIntrinsics::_compareAndSwapInt: + case vmIntrinsics::_putOrderedObject: + case vmIntrinsics::_putOrderedInt: + case vmIntrinsics::_putOrderedLong: + case vmIntrinsics::_loadFence: + case vmIntrinsics::_storeFence: + case vmIntrinsics::_fullFence: + case vmIntrinsics::_currentThread: + case vmIntrinsics::_isInterrupted: +#ifdef TRACE_HAVE_INTRINSICS + case vmIntrinsics::_classID: + case vmIntrinsics::_threadID: + case vmIntrinsics::_counterTime: +#endif + case vmIntrinsics::_currentTimeMillis: + case vmIntrinsics::_nanoTime: + case vmIntrinsics::_allocateInstance: + case vmIntrinsics::_newArray: + case vmIntrinsics::_getLength: + case vmIntrinsics::_copyOf: + case vmIntrinsics::_copyOfRange: + case vmIntrinsics::_clone: + case vmIntrinsics::_isAssignableFrom: + case vmIntrinsics::_isInstance: + case vmIntrinsics::_getModifiers: + case vmIntrinsics::_isInterface: + case vmIntrinsics::_isArray: + case vmIntrinsics::_isPrimitive: + case vmIntrinsics::_getSuperclass: + case vmIntrinsics::_getClassAccessFlags: + case vmIntrinsics::_floatToRawIntBits: + case vmIntrinsics::_floatToIntBits: + case vmIntrinsics::_intBitsToFloat: + case vmIntrinsics::_doubleToRawLongBits: + case vmIntrinsics::_doubleToLongBits: + case vmIntrinsics::_longBitsToDouble: + case vmIntrinsics::_Reference_get: + case vmIntrinsics::_Class_cast: + case vmIntrinsics::_aescrypt_encryptBlock: + case vmIntrinsics::_aescrypt_decryptBlock: + case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt: + case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt: + case vmIntrinsics::_sha_implCompress: + case vmIntrinsics::_sha2_implCompress: + case vmIntrinsics::_sha5_implCompress: + case vmIntrinsics::_digestBase_implCompressMB: + case vmIntrinsics::_multiplyToLen: + case vmIntrinsics::_squareToLen: + case vmIntrinsics::_mulAdd: + case vmIntrinsics::_montgomeryMultiply: + case vmIntrinsics::_montgomerySquare: + case vmIntrinsics::_ghash_processBlocks: + case vmIntrinsics::_updateCRC32: + case vmIntrinsics::_updateBytesCRC32: + case vmIntrinsics::_updateByteBufferCRC32: + case vmIntrinsics::_updateBytesCRC32C: + case vmIntrinsics::_updateDirectByteBufferCRC32C: + case vmIntrinsics::_profileBoolean: + case vmIntrinsics::_isCompileConstant: + break; + default: + return false; + } + return true; +} + +bool C2Compiler::is_intrinsic_disabled_by_flag(methodHandle method, methodHandle compilation_context) { + vmIntrinsics::ID id = method->intrinsic_id(); + assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); + + if (vmIntrinsics::is_disabled_by_flags(method->intrinsic_id())) { + return true; + } + + // Check if the intrinsic corresponding to 'method' has been disabled on + // the command line by using the DisableIntrinsic flag (either globally + // or on a per-method level, see src/share/vm/compiler/abstractCompiler.hpp + // for details). + // Usually, the compilation context is the caller of the method 'method'. + // The only case when for a non-recursive method 'method' the compilation context + // is not the caller of the 'method' (but it is the method itself) is + // java.lang.ref.Referene::get. + // For java.lang.ref.Reference::get, the intrinsic version is used + // instead of the C2-compiled version so that the value in the referent + // field can be registered by the G1 pre-barrier code. The intrinsified + // version of Reference::get also adds a memory barrier to prevent + // commoning reads from the referent field across safepoint since GC + // can change the referent field's value. See Compile::Compile() + // in src/share/vm/opto/compile.cpp for more details. + ccstr disable_intr = NULL; + if ((DisableIntrinsic[0] != '\0' && strstr(DisableIntrinsic, vmIntrinsics::name_at(id)) != NULL) || + (!compilation_context.is_null() && + CompilerOracle::has_option_value(compilation_context, "DisableIntrinsic", disable_intr) && + strstr(disable_intr, vmIntrinsics::name_at(id)) != NULL) + ) { + return true; + } + + // -XX:-InlineNatives disables nearly all intrinsics except the ones listed in + // the following switch statement. + if (!InlineNatives) { + switch (id) { + case vmIntrinsics::_indexOf: + case vmIntrinsics::_compareTo: + case vmIntrinsics::_equals: + case vmIntrinsics::_equalsC: + case vmIntrinsics::_getAndAddInt: + case vmIntrinsics::_getAndAddLong: + case vmIntrinsics::_getAndSetInt: + case vmIntrinsics::_getAndSetLong: + case vmIntrinsics::_getAndSetObject: + case vmIntrinsics::_loadFence: + case vmIntrinsics::_storeFence: + case vmIntrinsics::_fullFence: + case vmIntrinsics::_Reference_get: + break; + default: + return true; + } + } + + if (!InlineUnsafeOps) { + switch (id) { + case vmIntrinsics::_loadFence: + case vmIntrinsics::_storeFence: + case vmIntrinsics::_fullFence: + case vmIntrinsics::_compareAndSwapObject: + case vmIntrinsics::_compareAndSwapLong: + case vmIntrinsics::_compareAndSwapInt: + return true; + default: + return false; + } + } + + return false; +} + int C2Compiler::initial_code_buffer_size() { assert(SegmentedCodeCache, "Should be only used with a segmented code cache"); return Compile::MAX_inst_size + Compile::MAX_locs_size + initial_const_capacity; diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/opto/c2compiler.hpp --- a/hotspot/src/share/vm/opto/c2compiler.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/opto/c2compiler.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -36,7 +36,6 @@ // Name const char *name() { return "C2"; } - void initialize(); // Compilation entry point for methods @@ -52,6 +51,26 @@ // Print compilation timers and statistics void print_timers(); + // Check the availability of an intrinsic for 'method' given a compilation context. + virtual bool is_intrinsic_available(methodHandle method, methodHandle compilation_context); + + // Return true if the intrinsification of a method supported by the compiler + // assuming a non-virtual dispatch. Return false otherwise. + virtual bool is_intrinsic_supported(methodHandle method) { + return is_intrinsic_supported(method, false); + } + + // Check if the compiler supports an intrinsic for 'method' given the + // the dispatch mode specified by the 'is_virtual' parameter. + virtual bool is_intrinsic_supported(methodHandle method, bool is_virtual); + + // Processing of command-line flags specific to the C2 compiler. + virtual bool is_intrinsic_disabled_by_flag(methodHandle method) { + return is_intrinsic_disabled_by_flag(method, NULL); + } + + virtual bool is_intrinsic_disabled_by_flag(methodHandle method, methodHandle compilation_context); + // Initial size of the code buffer (may be increased at runtime) static int initial_code_buffer_size(); }; diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/opto/library_call.cpp --- a/hotspot/src/share/vm/opto/library_call.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/opto/library_call.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -31,6 +31,7 @@ #include "oops/objArrayKlass.hpp" #include "opto/addnode.hpp" #include "opto/arraycopynode.hpp" +#include "opto/c2compiler.hpp" #include "opto/callGenerator.hpp" #include "opto/castnode.hpp" #include "opto/cfgnode.hpp" @@ -305,330 +306,40 @@ bool inline_isCompileConstant(); }; - //---------------------------make_vm_intrinsic---------------------------- CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) { vmIntrinsics::ID id = m->intrinsic_id(); assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); - ccstr disable_intr = NULL; - - if ((DisableIntrinsic[0] != '\0' - && strstr(DisableIntrinsic, vmIntrinsics::name_at(id)) != NULL) || - (method_has_option_value("DisableIntrinsic", disable_intr) - && strstr(disable_intr, vmIntrinsics::name_at(id)) != NULL)) { - // disabled by a user request on the command line: - // example: -XX:DisableIntrinsic=_hashCode,_getClass - return NULL; - } - if (!m->is_loaded()) { - // do not attempt to inline unloaded methods - return NULL; - } - - // Only a few intrinsics implement a virtual dispatch. - // They are expensive calls which are also frequently overridden. - if (is_virtual) { - switch (id) { - case vmIntrinsics::_hashCode: - case vmIntrinsics::_clone: - // OK, Object.hashCode and Object.clone intrinsics come in both flavors - break; - default: - return NULL; - } - } - - // -XX:-InlineNatives disables nearly all intrinsics: - if (!InlineNatives) { - switch (id) { - case vmIntrinsics::_indexOf: - case vmIntrinsics::_compareTo: - case vmIntrinsics::_equals: - case vmIntrinsics::_equalsC: - case vmIntrinsics::_getAndAddInt: - case vmIntrinsics::_getAndAddLong: - case vmIntrinsics::_getAndSetInt: - case vmIntrinsics::_getAndSetLong: - case vmIntrinsics::_getAndSetObject: - case vmIntrinsics::_loadFence: - case vmIntrinsics::_storeFence: - case vmIntrinsics::_fullFence: - break; // InlineNatives does not control String.compareTo - case vmIntrinsics::_Reference_get: - break; // InlineNatives does not control Reference.get - default: - return NULL; - } - } - - int predicates = 0; - bool does_virtual_dispatch = false; - - switch (id) { - case vmIntrinsics::_compareTo: - if (!SpecialStringCompareTo) return NULL; - if (!Matcher::match_rule_supported(Op_StrComp)) return NULL; - break; - case vmIntrinsics::_indexOf: - if (!SpecialStringIndexOf) return NULL; - break; - case vmIntrinsics::_equals: - if (!SpecialStringEquals) return NULL; - if (!Matcher::match_rule_supported(Op_StrEquals)) return NULL; - break; - case vmIntrinsics::_equalsC: - if (!SpecialArraysEquals) return NULL; - if (!Matcher::match_rule_supported(Op_AryEq)) return NULL; - break; - case vmIntrinsics::_arraycopy: - if (!InlineArrayCopy) return NULL; - break; - case vmIntrinsics::_copyMemory: - if (StubRoutines::unsafe_arraycopy() == NULL) return NULL; - if (!InlineArrayCopy) return NULL; - break; - case vmIntrinsics::_hashCode: - if (!InlineObjectHash) return NULL; - does_virtual_dispatch = true; - break; - case vmIntrinsics::_clone: - does_virtual_dispatch = true; - case vmIntrinsics::_copyOf: - case vmIntrinsics::_copyOfRange: - if (!InlineObjectCopy) return NULL; - // These also use the arraycopy intrinsic mechanism: - if (!InlineArrayCopy) return NULL; - break; - case vmIntrinsics::_encodeISOArray: - if (!SpecialEncodeISOArray) return NULL; - if (!Matcher::match_rule_supported(Op_EncodeISOArray)) return NULL; - break; - case vmIntrinsics::_checkIndex: - // We do not intrinsify this. The optimizer does fine with it. + // Do not attempt to inline unloaded methods. return NULL; - - case vmIntrinsics::_getCallerClass: - if (!InlineReflectionGetCallerClass) return NULL; - if (SystemDictionary::reflect_CallerSensitive_klass() == NULL) return NULL; - break; - - case vmIntrinsics::_bitCount_i: - if (!Matcher::match_rule_supported(Op_PopCountI)) return NULL; - break; - - case vmIntrinsics::_bitCount_l: - if (!Matcher::match_rule_supported(Op_PopCountL)) return NULL; - break; - - case vmIntrinsics::_numberOfLeadingZeros_i: - if (!Matcher::match_rule_supported(Op_CountLeadingZerosI)) return NULL; - break; - - case vmIntrinsics::_numberOfLeadingZeros_l: - if (!Matcher::match_rule_supported(Op_CountLeadingZerosL)) return NULL; - break; - - case vmIntrinsics::_numberOfTrailingZeros_i: - if (!Matcher::match_rule_supported(Op_CountTrailingZerosI)) return NULL; - break; - - case vmIntrinsics::_numberOfTrailingZeros_l: - if (!Matcher::match_rule_supported(Op_CountTrailingZerosL)) return NULL; - break; - - case vmIntrinsics::_reverseBytes_c: - if (!Matcher::match_rule_supported(Op_ReverseBytesUS)) return NULL; - break; - case vmIntrinsics::_reverseBytes_s: - if (!Matcher::match_rule_supported(Op_ReverseBytesS)) return NULL; - break; - case vmIntrinsics::_reverseBytes_i: - if (!Matcher::match_rule_supported(Op_ReverseBytesI)) return NULL; - break; - case vmIntrinsics::_reverseBytes_l: - if (!Matcher::match_rule_supported(Op_ReverseBytesL)) return NULL; - break; - - case vmIntrinsics::_Reference_get: - // Use the intrinsic version of Reference.get() so that the value in - // the referent field can be registered by the G1 pre-barrier code. - // Also add memory barrier to prevent commoning reads from this field - // across safepoint since GC can change it value. - break; - - case vmIntrinsics::_compareAndSwapObject: -#ifdef _LP64 - if (!UseCompressedOops && !Matcher::match_rule_supported(Op_CompareAndSwapP)) return NULL; -#endif - break; - - case vmIntrinsics::_compareAndSwapLong: - if (!Matcher::match_rule_supported(Op_CompareAndSwapL)) return NULL; - break; - - case vmIntrinsics::_getAndAddInt: - if (!Matcher::match_rule_supported(Op_GetAndAddI)) return NULL; - break; - - case vmIntrinsics::_getAndAddLong: - if (!Matcher::match_rule_supported(Op_GetAndAddL)) return NULL; - break; - - case vmIntrinsics::_getAndSetInt: - if (!Matcher::match_rule_supported(Op_GetAndSetI)) return NULL; - break; - - case vmIntrinsics::_getAndSetLong: - if (!Matcher::match_rule_supported(Op_GetAndSetL)) return NULL; - break; - - case vmIntrinsics::_getAndSetObject: -#ifdef _LP64 - if (!UseCompressedOops && !Matcher::match_rule_supported(Op_GetAndSetP)) return NULL; - if (UseCompressedOops && !Matcher::match_rule_supported(Op_GetAndSetN)) return NULL; - break; -#else - if (!Matcher::match_rule_supported(Op_GetAndSetP)) return NULL; - break; -#endif - - case vmIntrinsics::_aescrypt_encryptBlock: - case vmIntrinsics::_aescrypt_decryptBlock: - if (!UseAESIntrinsics) return NULL; - break; - - case vmIntrinsics::_multiplyToLen: - if (!UseMultiplyToLenIntrinsic) return NULL; - break; - - case vmIntrinsics::_squareToLen: - if (!UseSquareToLenIntrinsic) return NULL; - break; - - case vmIntrinsics::_mulAdd: - if (!UseMulAddIntrinsic) return NULL; - break; - - case vmIntrinsics::_montgomeryMultiply: - if (!UseMontgomeryMultiplyIntrinsic) return NULL; - break; - case vmIntrinsics::_montgomerySquare: - if (!UseMontgomerySquareIntrinsic) return NULL; - break; - - case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt: - case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt: - if (!UseAESIntrinsics) return NULL; - // these two require the predicated logic - predicates = 1; - break; - - case vmIntrinsics::_sha_implCompress: - if (!UseSHA1Intrinsics) return NULL; - break; - - case vmIntrinsics::_sha2_implCompress: - if (!UseSHA256Intrinsics) return NULL; - break; - - case vmIntrinsics::_sha5_implCompress: - if (!UseSHA512Intrinsics) return NULL; - break; - - case vmIntrinsics::_digestBase_implCompressMB: - if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics)) return NULL; - predicates = 3; - break; - - case vmIntrinsics::_ghash_processBlocks: - if (!UseGHASHIntrinsics) return NULL; - break; - - case vmIntrinsics::_updateCRC32: - case vmIntrinsics::_updateBytesCRC32: - case vmIntrinsics::_updateByteBufferCRC32: - if (!UseCRC32Intrinsics) return NULL; - break; - - case vmIntrinsics::_updateBytesCRC32C: - case vmIntrinsics::_updateDirectByteBufferCRC32C: - if (!UseCRC32CIntrinsics) return NULL; - break; - - case vmIntrinsics::_incrementExactI: - case vmIntrinsics::_addExactI: - if (!Matcher::match_rule_supported(Op_OverflowAddI) || !UseMathExactIntrinsics) return NULL; - break; - case vmIntrinsics::_incrementExactL: - case vmIntrinsics::_addExactL: - if (!Matcher::match_rule_supported(Op_OverflowAddL) || !UseMathExactIntrinsics) return NULL; - break; - case vmIntrinsics::_decrementExactI: - case vmIntrinsics::_subtractExactI: - if (!Matcher::match_rule_supported(Op_OverflowSubI) || !UseMathExactIntrinsics) return NULL; - break; - case vmIntrinsics::_decrementExactL: - case vmIntrinsics::_subtractExactL: - if (!Matcher::match_rule_supported(Op_OverflowSubL) || !UseMathExactIntrinsics) return NULL; - break; - case vmIntrinsics::_negateExactI: - if (!Matcher::match_rule_supported(Op_OverflowSubI) || !UseMathExactIntrinsics) return NULL; - break; - case vmIntrinsics::_negateExactL: - if (!Matcher::match_rule_supported(Op_OverflowSubL) || !UseMathExactIntrinsics) return NULL; - break; - case vmIntrinsics::_multiplyExactI: - if (!Matcher::match_rule_supported(Op_OverflowMulI) || !UseMathExactIntrinsics) return NULL; - break; - case vmIntrinsics::_multiplyExactL: - if (!Matcher::match_rule_supported(Op_OverflowMulL) || !UseMathExactIntrinsics) return NULL; - break; - - case vmIntrinsics::_getShortUnaligned: - case vmIntrinsics::_getCharUnaligned: - case vmIntrinsics::_getIntUnaligned: - case vmIntrinsics::_getLongUnaligned: - case vmIntrinsics::_putShortUnaligned: - case vmIntrinsics::_putCharUnaligned: - case vmIntrinsics::_putIntUnaligned: - case vmIntrinsics::_putLongUnaligned: - if (!UseUnalignedAccesses) return NULL; - break; - - default: + } + + C2Compiler* compiler = (C2Compiler*)CompileBroker::compiler(CompLevel_full_optimization); + bool is_available = false; + + { + // For calling is_intrinsic_supported and is_intrinsic_disabled_by_flag + // the compiler must transition to '_thread_in_vm' state because both + // methods access VM-internal data. + VM_ENTRY_MARK; + methodHandle mh(THREAD, m->get_Method()); + methodHandle ct(THREAD, method()->get_Method()); + is_available = compiler->is_intrinsic_supported(mh, is_virtual) && + !compiler->is_intrinsic_disabled_by_flag(mh, ct); + } + + if (is_available) { assert(id <= vmIntrinsics::LAST_COMPILER_INLINE, "caller responsibility"); assert(id != vmIntrinsics::_Object_init && id != vmIntrinsics::_invoke, "enum out of order?"); - break; - } - - // -XX:-InlineClassNatives disables natives from the Class class. - // The flag applies to all reflective calls, notably Array.newArray - // (visible to Java programmers as Array.newInstance). - if (m->holder()->name() == ciSymbol::java_lang_Class() || - m->holder()->name() == ciSymbol::java_lang_reflect_Array()) { - if (!InlineClassNatives) return NULL; - } - - // -XX:-InlineThreadNatives disables natives from the Thread class. - if (m->holder()->name() == ciSymbol::java_lang_Thread()) { - if (!InlineThreadNatives) return NULL; - } - - // -XX:-InlineMathNatives disables natives from the Math,Float and Double classes. - if (m->holder()->name() == ciSymbol::java_lang_Math() || - m->holder()->name() == ciSymbol::java_lang_Float() || - m->holder()->name() == ciSymbol::java_lang_Double()) { - if (!InlineMathNatives) return NULL; - } - - // -XX:-InlineUnsafeOps disables natives from the Unsafe class. - if (m->holder()->name() == ciSymbol::sun_misc_Unsafe()) { - if (!InlineUnsafeOps) return NULL; - } - - return new LibraryIntrinsic(m, is_virtual, predicates, does_virtual_dispatch, (vmIntrinsics::ID) id); + return new LibraryIntrinsic(m, is_virtual, + vmIntrinsics::predicates_needed(id), + vmIntrinsics::does_virtual_dispatch(id), + (vmIntrinsics::ID) id); + } else { + return NULL; + } } //----------------------register_library_intrinsics----------------------- @@ -812,7 +523,6 @@ case vmIntrinsics::_getLong: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, !is_volatile); case vmIntrinsics::_getFloat: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, !is_volatile); case vmIntrinsics::_getDouble: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, !is_volatile); - case vmIntrinsics::_putObject: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, !is_volatile); case vmIntrinsics::_putBoolean: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, !is_volatile); case vmIntrinsics::_putByte: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, !is_volatile); diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/prims/jvmtiTagMap.cpp --- a/hotspot/src/share/vm/prims/jvmtiTagMap.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -2824,7 +2824,7 @@ if (klass->oop_is_instance()) { InstanceKlass* ik = InstanceKlass::cast(klass); - // ignore the class if it's has been initialized yet + // Ignore the class if it hasn't been initialized yet if (!ik->is_linked()) { return true; } diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/prims/whitebox.cpp --- a/hotspot/src/share/vm/prims/whitebox.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/prims/whitebox.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -528,6 +528,24 @@ return mh->queued_for_compilation(); WB_END +WB_ENTRY(jboolean, WB_IsIntrinsicAvailable(JNIEnv* env, jobject o, jobject method, jobject compilation_context, jint compLevel)) + if (compLevel < CompLevel_none || compLevel > CompLevel_highest_tier) { + return false; // Intrinsic is not available on a non-existent compilation level. + } + jmethodID method_id, compilation_context_id; + method_id = reflected_method_to_jmid(thread, env, method); + CHECK_JNI_EXCEPTION_(env, JNI_FALSE); + methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(method_id)); + if (compilation_context != NULL) { + compilation_context_id = reflected_method_to_jmid(thread, env, compilation_context); + CHECK_JNI_EXCEPTION_(env, JNI_FALSE); + methodHandle cch(THREAD, Method::checked_resolve_jmethod_id(compilation_context_id)); + return CompileBroker::compiler(compLevel)->is_intrinsic_available(mh, cch); + } else { + return CompileBroker::compiler(compLevel)->is_intrinsic_available(mh, NULL); + } +WB_END + WB_ENTRY(jint, WB_GetMethodCompilationLevel(JNIEnv* env, jobject o, jobject method, jboolean is_osr)) jmethodID jmid = reflected_method_to_jmid(thread, env, method); CHECK_JNI_EXCEPTION_(env, CompLevel_none); @@ -1477,14 +1495,17 @@ #endif // INCLUDE_NMT {CC"deoptimizeFrames", CC"(Z)I", (void*)&WB_DeoptimizeFrames }, {CC"deoptimizeAll", CC"()V", (void*)&WB_DeoptimizeAll }, - {CC"deoptimizeMethod0", CC"(Ljava/lang/reflect/Executable;Z)I", - (void*)&WB_DeoptimizeMethod }, + {CC"deoptimizeMethod0", CC"(Ljava/lang/reflect/Executable;Z)I", + (void*)&WB_DeoptimizeMethod }, {CC"isMethodCompiled0", CC"(Ljava/lang/reflect/Executable;Z)Z", (void*)&WB_IsMethodCompiled }, {CC"isMethodCompilable0", CC"(Ljava/lang/reflect/Executable;IZ)Z", (void*)&WB_IsMethodCompilable}, {CC"isMethodQueuedForCompilation0", CC"(Ljava/lang/reflect/Executable;)Z", (void*)&WB_IsMethodQueuedForCompilation}, + {CC"isIntrinsicAvailable0", + CC"(Ljava/lang/reflect/Executable;Ljava/lang/reflect/Executable;I)Z", + (void*)&WB_IsIntrinsicAvailable}, {CC"makeMethodNotCompilable0", CC"(Ljava/lang/reflect/Executable;IZ)V", (void*)&WB_MakeMethodNotCompilable}, {CC"testSetDontInlineMethod0", diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/runtime/arguments.cpp --- a/hotspot/src/share/vm/runtime/arguments.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/runtime/arguments.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -788,9 +788,11 @@ st->print_cr("VM Arguments:"); if (num_jvm_flags() > 0) { st->print("jvm_flags: "); print_jvm_flags_on(st); + st->cr(); } if (num_jvm_args() > 0) { st->print("jvm_args: "); print_jvm_args_on(st); + st->cr(); } st->print_cr("java_command: %s", java_command() ? java_command() : ""); if (_java_class_path != NULL) { @@ -800,12 +802,32 @@ st->print_cr("Launcher Type: %s", _sun_java_launcher); } +void Arguments::print_summary_on(outputStream* st) { + // Print the command line. Environment variables that are helpful for + // reproducing the problem are written later in the hs_err file. + // flags are from setting file + if (num_jvm_flags() > 0) { + st->print_raw("Settings File: "); + print_jvm_flags_on(st); + st->cr(); + } + // args are the command line and environment variable arguments. + st->print_raw("Command Line: "); + if (num_jvm_args() > 0) { + print_jvm_args_on(st); + } + // this is the classfile and any arguments to the java program + if (java_command() != NULL) { + st->print("%s", java_command()); + } + st->cr(); +} + void Arguments::print_jvm_flags_on(outputStream* st) { if (_num_jvm_flags > 0) { for (int i=0; i < _num_jvm_flags; i++) { st->print("%s ", _jvm_flags_array[i]); } - st->cr(); } } @@ -814,7 +836,6 @@ for (int i=0; i < _num_jvm_args; i++) { st->print("%s ", _jvm_args_array[i]); } - st->cr(); } } @@ -1205,32 +1226,6 @@ } } -/** - * Returns the minimum number of compiler threads needed to run the JVM. The following - * configurations are possible. - * - * 1) The JVM is build using an interpreter only. As a result, the minimum number of - * compiler threads is 0. - * 2) The JVM is build using the compiler(s) and tiered compilation is disabled. As - * a result, either C1 or C2 is used, so the minimum number of compiler threads is 1. - * 3) The JVM is build using the compiler(s) and tiered compilation is enabled. However, - * the option "TieredStopAtLevel < CompLevel_full_optimization". As a result, only - * C1 can be used, so the minimum number of compiler threads is 1. - * 4) The JVM is build using the compilers and tiered compilation is enabled. The option - * 'TieredStopAtLevel = CompLevel_full_optimization' (the default value). As a result, - * the minimum number of compiler threads is 2. - */ -int Arguments::get_min_number_of_compiler_threads() { -#if !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK) - return 0; // case 1 -#else - if (!TieredCompilation || (TieredStopAtLevel < CompLevel_full_optimization)) { - return 1; // case 2 or case 3 - } - return 2; // case 4 (tiered) -#endif -} - #if INCLUDE_ALL_GCS static void disable_adaptive_size_policy(const char* collector_name) { if (UseAdaptiveSizePolicy) { @@ -2178,10 +2173,6 @@ status = false; } - int min_number_of_compiler_threads = get_min_number_of_compiler_threads(); - // The default CICompilerCount's value is CI_COMPILER_COUNT. - assert(min_number_of_compiler_threads <= CI_COMPILER_COUNT, "minimum should be less or equal default number"); - if (!FLAG_IS_DEFAULT(CICompilerCount) && !FLAG_IS_DEFAULT(CICompilerCountPerCPU) && CICompilerCountPerCPU) { warning("The VM option CICompilerCountPerCPU overrides CICompilerCount."); } @@ -3989,10 +3980,10 @@ return JNI_OK; } -// Any custom code post the final range and constraint check +// Any custom code post the 'CommandLineFlagConstraint::AfterErgo' constraint check // can be done here. We pass a flag that specifies whether // the check passed successfully -void Arguments::post_final_range_and_constraint_check(bool check_passed) { +void Arguments::post_after_ergo_constraint_check(bool check_passed) { // This does not set the flag itself, but stores the value in a safe place for later usage. _min_heap_free_ratio = MinHeapFreeRatio; _max_heap_free_ratio = MaxHeapFreeRatio; diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/runtime/arguments.hpp --- a/hotspot/src/share/vm/runtime/arguments.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/runtime/arguments.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -445,9 +445,6 @@ static char* SharedArchivePath; public: - // Tiered - static int get_min_number_of_compiler_threads(); - // Scale compile thresholds // Returns threshold scaled with CompileThresholdScaling static intx scaled_compile_threshold(intx threshold, double scale); @@ -466,8 +463,8 @@ static jint apply_ergo(); // Adjusts the arguments after the OS have adjusted the arguments static jint adjust_after_os(); - // Set any arguments that need to be set after the final range and constraint check - static void post_final_range_and_constraint_check(bool check_passed); + // Set any arguments that need to be set after the 'CommandLineFlagConstraint::AfterErgo' constraint check + static void post_after_ergo_constraint_check(bool check_passed); static void set_gc_specific_flags(); static inline bool gc_selected(); // whether a gc has been selected @@ -495,6 +492,7 @@ // print jvm_flags, jvm_args and java_command static void print_on(outputStream* st); + static void print_summary_on(outputStream* st); // convenient methods to obtain / print jvm_flags and jvm_args static const char* jvm_flags() { return build_resource_string(_jvm_flags_array, _num_jvm_flags); } diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -39,7 +39,9 @@ public: // the "name" argument must be a string literal - CommandLineFlagConstraint_bool(const char* name, CommandLineFlagConstraintFunc_bool func) : CommandLineFlagConstraint(name) { + CommandLineFlagConstraint_bool(const char* name, + CommandLineFlagConstraintFunc_bool func, + ConstraintType type) : CommandLineFlagConstraint(name, type) { _constraint=func; } @@ -53,7 +55,9 @@ public: // the "name" argument must be a string literal - CommandLineFlagConstraint_int(const char* name, CommandLineFlagConstraintFunc_int func) : CommandLineFlagConstraint(name) { + CommandLineFlagConstraint_int(const char* name, + CommandLineFlagConstraintFunc_int func, + ConstraintType type) : CommandLineFlagConstraint(name, type) { _constraint=func; } @@ -67,7 +71,9 @@ public: // the "name" argument must be a string literal - CommandLineFlagConstraint_intx(const char* name, CommandLineFlagConstraintFunc_intx func) : CommandLineFlagConstraint(name) { + CommandLineFlagConstraint_intx(const char* name, + CommandLineFlagConstraintFunc_intx func, + ConstraintType type) : CommandLineFlagConstraint(name, type) { _constraint=func; } @@ -81,7 +87,9 @@ public: // the "name" argument must be a string literal - CommandLineFlagConstraint_uint(const char* name, CommandLineFlagConstraintFunc_uint func) : CommandLineFlagConstraint(name) { + CommandLineFlagConstraint_uint(const char* name, + CommandLineFlagConstraintFunc_uint func, + ConstraintType type) : CommandLineFlagConstraint(name, type) { _constraint=func; } @@ -95,7 +103,9 @@ public: // the "name" argument must be a string literal - CommandLineFlagConstraint_uintx(const char* name, CommandLineFlagConstraintFunc_uintx func) : CommandLineFlagConstraint(name) { + CommandLineFlagConstraint_uintx(const char* name, + CommandLineFlagConstraintFunc_uintx func, + ConstraintType type) : CommandLineFlagConstraint(name, type) { _constraint=func; } @@ -109,7 +119,9 @@ public: // the "name" argument must be a string literal - CommandLineFlagConstraint_uint64_t(const char* name, CommandLineFlagConstraintFunc_uint64_t func) : CommandLineFlagConstraint(name) { + CommandLineFlagConstraint_uint64_t(const char* name, + CommandLineFlagConstraintFunc_uint64_t func, + ConstraintType type) : CommandLineFlagConstraint(name, type) { _constraint=func; } @@ -123,7 +135,9 @@ public: // the "name" argument must be a string literal - CommandLineFlagConstraint_size_t(const char* name, CommandLineFlagConstraintFunc_size_t func) : CommandLineFlagConstraint(name) { + CommandLineFlagConstraint_size_t(const char* name, + CommandLineFlagConstraintFunc_size_t func, + ConstraintType type) : CommandLineFlagConstraint(name, type) { _constraint=func; } @@ -137,7 +151,9 @@ public: // the "name" argument must be a string literal - CommandLineFlagConstraint_double(const char* name, CommandLineFlagConstraintFunc_double func) : CommandLineFlagConstraint(name) { + CommandLineFlagConstraint_double(const char* name, + CommandLineFlagConstraintFunc_double func, + ConstraintType type) : CommandLineFlagConstraint(name, type) { _constraint=func; } @@ -162,29 +178,29 @@ void emit_constraint_double(const char* /*name*/) { /* NOP */ } // CommandLineFlagConstraint emitting code functions if function argument is provided -void emit_constraint_bool(const char* name, CommandLineFlagConstraintFunc_bool func) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_bool(name, func)); +void emit_constraint_bool(const char* name, CommandLineFlagConstraintFunc_bool func, CommandLineFlagConstraint::ConstraintType type) { + CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_bool(name, func, type)); } -void emit_constraint_int(const char* name, CommandLineFlagConstraintFunc_int func) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_int(name, func)); +void emit_constraint_int(const char* name, CommandLineFlagConstraintFunc_int func, CommandLineFlagConstraint::ConstraintType type) { + CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_int(name, func, type)); } -void emit_constraint_intx(const char* name, CommandLineFlagConstraintFunc_intx func) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_intx(name, func)); +void emit_constraint_intx(const char* name, CommandLineFlagConstraintFunc_intx func, CommandLineFlagConstraint::ConstraintType type) { + CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_intx(name, func, type)); } -void emit_constraint_uint(const char* name, CommandLineFlagConstraintFunc_uint func) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_uint(name, func)); +void emit_constraint_uint(const char* name, CommandLineFlagConstraintFunc_uint func, CommandLineFlagConstraint::ConstraintType type) { + CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_uint(name, func, type)); } -void emit_constraint_uintx(const char* name, CommandLineFlagConstraintFunc_uintx func) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_uintx(name, func)); +void emit_constraint_uintx(const char* name, CommandLineFlagConstraintFunc_uintx func, CommandLineFlagConstraint::ConstraintType type) { + CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_uintx(name, func, type)); } -void emit_constraint_uint64_t(const char* name, CommandLineFlagConstraintFunc_uint64_t func) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_uint64_t(name, func)); +void emit_constraint_uint64_t(const char* name, CommandLineFlagConstraintFunc_uint64_t func, CommandLineFlagConstraint::ConstraintType type) { + CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_uint64_t(name, func, type)); } -void emit_constraint_size_t(const char* name, CommandLineFlagConstraintFunc_size_t func) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_size_t(name, func)); +void emit_constraint_size_t(const char* name, CommandLineFlagConstraintFunc_size_t func, CommandLineFlagConstraint::ConstraintType type) { + CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_size_t(name, func, type)); } -void emit_constraint_double(const char* name, CommandLineFlagConstraintFunc_double func) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_double(name, func)); +void emit_constraint_double(const char* name, CommandLineFlagConstraintFunc_double func, CommandLineFlagConstraint::ConstraintType type) { + CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_double(name, func, type)); } // Generate code to call emit_constraint_xxx function @@ -201,16 +217,17 @@ #define EMIT_CONSTRAINT_LP64_PRODUCT_FLAG(type, name, value, doc) ); emit_constraint_##type(#name // Generate func argument to pass into emit_constraint_xxx functions -#define EMIT_CONSTRAINT_CHECK(func) , func +#define EMIT_CONSTRAINT_CHECK(func, type) , func, CommandLineFlagConstraint::type // the "name" argument must be a string literal -#define INITIAL_CONTRAINTS_SIZE 16 +#define INITIAL_CONSTRAINTS_SIZE 16 GrowableArray* CommandLineFlagConstraintList::_constraints = NULL; +CommandLineFlagConstraint::ConstraintType CommandLineFlagConstraintList::_validating_type = CommandLineFlagConstraint::AtParse; // Check the ranges of all flags that have them or print them out and exit if requested void CommandLineFlagConstraintList::init(void) { - _constraints = new (ResourceObj::C_HEAP, mtInternal) GrowableArray(INITIAL_CONTRAINTS_SIZE, true); + _constraints = new (ResourceObj::C_HEAP, mtInternal) GrowableArray(INITIAL_CONSTRAINTS_SIZE, true); emit_constraint_no(NULL RUNTIME_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG, EMIT_CONSTRAINT_PD_DEVELOPER_FLAG, @@ -273,14 +290,89 @@ #endif // INCLUDE_ALL_GCS } -CommandLineFlagConstraint* CommandLineFlagConstraintList::find(const char* name) { +// Find constraints by name and return only if found constraint's type is equal or lower than current validating type. +CommandLineFlagConstraint* CommandLineFlagConstraintList::find_if_needs_check(const char* name) { CommandLineFlagConstraint* found = NULL; for (int i=0; iname(), name) == 0) { + if ((strcmp(constraint->name(), name) == 0) && + (constraint->type() <= _validating_type)) { found = constraint; break; } } return found; } + +// Check constraints for specific constraint type. +bool CommandLineFlagConstraintList::check_constraints(CommandLineFlagConstraint::ConstraintType type) { +//#define PRINT_CONSTRAINTS_SIZES +#ifdef PRINT_CONSTRAINTS_SIZES + { + size_t size_constraints = sizeof(CommandLineFlagConstraintList); + for (int i=0; iname(); + Flag* flag = Flag::find_flag(name, strlen(name), true, true); + if (flag->is_bool()) { + size_constraints += sizeof(CommandLineFlagConstraintFunc_bool); + size_constraints += sizeof(CommandLineFlagConstraint*); + } else if (flag->is_intx()) { + size_constraints += sizeof(CommandLineFlagConstraintFunc_intx); + size_constraints += sizeof(CommandLineFlagConstraint*); + } else if (flag->is_uintx()) { + size_constraints += sizeof(CommandLineFlagConstraintFunc_uintx); + size_constraints += sizeof(CommandLineFlagConstraint*); + } else if (flag->is_uint64_t()) { + size_constraints += sizeof(CommandLineFlagConstraintFunc_uint64_t); + size_constraints += sizeof(CommandLineFlagConstraint*); + } else if (flag->is_size_t()) { + size_constraints += sizeof(CommandLineFlagConstraintFunc_size_t); + size_constraints += sizeof(CommandLineFlagConstraint*); + } else if (flag->is_double()) { + size_constraints += sizeof(CommandLineFlagConstraintFunc_double); + size_constraints += sizeof(CommandLineFlagConstraint*); + } + } + fprintf(stderr, "Size of %d constraints: " SIZE_FORMAT " bytes\n", + length(), size_constraints); + } +#endif // PRINT_CONSTRAINTS_SIZES + + // Skip if we already checked. + if (type < _validating_type) { + return true; + } + _validating_type = type; + + bool status = true; + for (int i=0; itype()) continue; + const char*name = constraint->name(); + Flag* flag = Flag::find_flag(name, strlen(name), true, true); + if (flag != NULL) { + if (flag->is_bool()) { + bool value = flag->get_bool(); + if (constraint->apply_bool(&value, true) != Flag::SUCCESS) status = false; + } else if (flag->is_intx()) { + intx value = flag->get_intx(); + if (constraint->apply_intx(&value, true) != Flag::SUCCESS) status = false; + } else if (flag->is_uintx()) { + uintx value = flag->get_uintx(); + if (constraint->apply_uintx(&value, true) != Flag::SUCCESS) status = false; + } else if (flag->is_uint64_t()) { + uint64_t value = flag->get_uint64_t(); + if (constraint->apply_uint64_t(&value, true) != Flag::SUCCESS) status = false; + } else if (flag->is_size_t()) { + size_t value = flag->get_size_t(); + if (constraint->apply_size_t(&value, true) != Flag::SUCCESS) status = false; + } else if (flag->is_double()) { + double value = flag->get_double(); + if (constraint->apply_double(&value, true) != Flag::SUCCESS) status = false; + } + } + } + return status; +} diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/runtime/commandLineFlagConstraintList.hpp --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -49,13 +49,27 @@ typedef Flag::Error (*CommandLineFlagConstraintFunc_double)(bool verbose, double* value); class CommandLineFlagConstraint : public CHeapObj { +public: + // During VM initialization, constraint validation will be done order of ConstraintType. + enum ConstraintType { + // Will be validated during argument processing (Arguments::parse_argument). + AtParse = 0, + // Will be validated by CommandLineFlags::check_constraints_of_after_ergo(). + AfterErgo = 1, + // Will be validated by CommandLineFlags::check_constraints_of_after_memory_init(). + AfterMemoryInit = 2 + }; + private: const char* _name; + ConstraintType _validate_type; + public: // the "name" argument must be a string literal - CommandLineFlagConstraint(const char* name) { _name=name; }; + CommandLineFlagConstraint(const char* name, ConstraintType type) { _name=name; _validate_type=type; }; ~CommandLineFlagConstraint() {}; - const char* name() { return _name; } + const char* name() const { return _name; } + ConstraintType type() const { return _validate_type; } virtual Flag::Error apply_bool(bool* value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; virtual Flag::Error apply_int(int* value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; virtual Flag::Error apply_intx(intx* value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; @@ -69,12 +83,17 @@ class CommandLineFlagConstraintList : public AllStatic { private: static GrowableArray* _constraints; + // Latest constraint validation type. + static CommandLineFlagConstraint::ConstraintType _validating_type; public: static void init(); static int length() { return (_constraints != NULL) ? _constraints->length() : 0; } static CommandLineFlagConstraint* at(int i) { return (_constraints != NULL) ? _constraints->at(i) : NULL; } - static CommandLineFlagConstraint* find(const char* name); + static CommandLineFlagConstraint* find_if_needs_check(const char* name); static void add(CommandLineFlagConstraint* constraint) { _constraints->append(constraint); } + // True if 'AfterErgo' or later constraint functions are validated. + static bool validated_after_ergo() { return _validating_type >= CommandLineFlagConstraint::AfterErgo; }; + static bool check_constraints(CommandLineFlagConstraint::ConstraintType type); }; #endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTLIST_HPP */ diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.cpp --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -29,16 +29,57 @@ #include "utilities/defaultStream.hpp" Flag::Error AliasLevelConstraintFunc(bool verbose, intx* value) { - if (CommandLineFlags::finishedInitializing() == true) { - if ((*value <= 1) && (Arguments::mode() == Arguments::_comp)) { - if (verbose == true) { - jio_fprintf(defaultStream::error_stream(), - "AliasLevel (" INTX_FORMAT ") is not compatible " - "with -Xcomp \n", - *value); - } - return Flag::VIOLATES_CONSTRAINT; + if ((*value <= 1) && (Arguments::mode() == Arguments::_comp)) { + if (verbose == true) { + jio_fprintf(defaultStream::error_stream(), + "AliasLevel (" INTX_FORMAT ") is not compatible " + "with -Xcomp \n", + *value); } + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; } - return Flag::SUCCESS; } + +/** + * Validate the minimum number of compiler threads needed to run the + * JVM. The following configurations are possible. + * + * 1) The JVM is build using an interpreter only. As a result, the minimum number of + * compiler threads is 0. + * 2) The JVM is build using the compiler(s) and tiered compilation is disabled. As + * a result, either C1 or C2 is used, so the minimum number of compiler threads is 1. + * 3) The JVM is build using the compiler(s) and tiered compilation is enabled. However, + * the option "TieredStopAtLevel < CompLevel_full_optimization". As a result, only + * C1 can be used, so the minimum number of compiler threads is 1. + * 4) The JVM is build using the compilers and tiered compilation is enabled. The option + * 'TieredStopAtLevel = CompLevel_full_optimization' (the default value). As a result, + * the minimum number of compiler threads is 2. + */ +Flag::Error CICompilerCountConstraintFunc(bool verbose, intx* value) { + int min_number_of_compiler_threads = 0; +#if !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK) + // case 1 +#else + if (!TieredCompilation || (TieredStopAtLevel < CompLevel_full_optimization)) { + min_number_of_compiler_threads = 1; // case 2 or case 3 + } else { + min_number_of_compiler_threads = 2; // case 4 (tiered) + } +#endif + + // The default CICompilerCount's value is CI_COMPILER_COUNT. + assert(min_number_of_compiler_threads <= CI_COMPILER_COUNT, "minimum should be less or equal default number"); + + if (*value < (intx)min_number_of_compiler_threads) { + if (verbose == true) { + jio_fprintf(defaultStream::error_stream(), + "CICompilerCount=" INTX_FORMAT " must be at least %d \n", + *value, min_number_of_compiler_threads); + } + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.hpp --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -36,4 +36,6 @@ Flag::Error AliasLevelConstraintFunc(bool verbose, intx* value); +Flag::Error CICompilerCountConstraintFunc(bool verbose, intx* value); + #endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSCOMPILER_HPP */ diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -30,6 +30,9 @@ #if INCLUDE_ALL_GCS #include "gc/g1/g1_globals.hpp" +#include "gc/g1/heapRegionBounds.inline.hpp" +#include "gc/parallel/parallelScavengeHeap.hpp" +#include "gc/shared/plab.hpp" #endif // INCLUDE_ALL_GCS #ifdef COMPILER1 #include "c1/c1_globals.hpp" @@ -38,8 +41,49 @@ #include "opto/c2_globals.hpp" #endif // COMPILER2 +static Flag::Error MinPLABSizeBounds(const char* name, bool verbose, size_t* value) { +#if INCLUDE_ALL_GCS + if ((UseConcMarkSweepGC || UseG1GC) && (*value < PLAB::min_size())) { + if (verbose == true) { + jio_fprintf(defaultStream::error_stream(), + "%s (" SIZE_FORMAT ") must be greater than " + "ergonomic PLAB minimum size (" SIZE_FORMAT ")\n", + name, *value, PLAB::min_size()); + } + return Flag::VIOLATES_CONSTRAINT; + } +#endif // INCLUDE_ALL_GCS + return Flag::SUCCESS; +} + +static Flag::Error MaxPLABSizeBounds(const char* name, bool verbose, size_t* value) { +#if INCLUDE_ALL_GCS + if ((UseConcMarkSweepGC || UseG1GC) && (*value > PLAB::max_size())) { + if (verbose == true) { + jio_fprintf(defaultStream::error_stream(), + "%s (" SIZE_FORMAT ") must be less than " + "ergonomic PLAB maximum size (" SIZE_FORMAT ")\n", + name, *value, PLAB::max_size()); + } + return Flag::VIOLATES_CONSTRAINT; + } +#endif // INCLUDE_ALL_GCS + return Flag::SUCCESS; +} + +static Flag::Error MinMaxPLABSizeBounds(const char* name, bool verbose, size_t* value) { + if (MinPLABSizeBounds(name, verbose, value) == Flag::SUCCESS) { + return MaxPLABSizeBounds(name, verbose, value); + } + return Flag::VIOLATES_CONSTRAINT; +} + +Flag::Error YoungPLABSizeConstraintFunc(bool verbose, size_t* value) { + return MinMaxPLABSizeBounds("YoungPLABSize", verbose, value); +} + Flag::Error MinHeapFreeRatioConstraintFunc(bool verbose, uintx* value) { - if ((CommandLineFlags::finishedInitializing()) && (*value > MaxHeapFreeRatio)) { + if (*value > MaxHeapFreeRatio) { if (verbose == true) { jio_fprintf(defaultStream::error_stream(), "MinHeapFreeRatio (" UINTX_FORMAT ") must be less than or " @@ -53,7 +97,7 @@ } Flag::Error MaxHeapFreeRatioConstraintFunc(bool verbose, uintx* value) { - if ((CommandLineFlags::finishedInitializing()) && (*value < MinHeapFreeRatio)) { + if (*value < MinHeapFreeRatio) { if (verbose == true) { jio_fprintf(defaultStream::error_stream(), "MaxHeapFreeRatio (" UINTX_FORMAT ") must be greater than or " @@ -67,7 +111,7 @@ } Flag::Error MinMetaspaceFreeRatioConstraintFunc(bool verbose, uintx* value) { - if ((CommandLineFlags::finishedInitializing()) && (*value > MaxMetaspaceFreeRatio)) { + if (*value > MaxMetaspaceFreeRatio) { if (verbose == true) { jio_fprintf(defaultStream::error_stream(), "MinMetaspaceFreeRatio (" UINTX_FORMAT ") must be less than or " @@ -81,7 +125,7 @@ } Flag::Error MaxMetaspaceFreeRatioConstraintFunc(bool verbose, uintx* value) { - if ((CommandLineFlags::finishedInitializing()) && (*value < MinMetaspaceFreeRatio)) { + if (*value < MinMetaspaceFreeRatio) { if (verbose == true) { jio_fprintf(defaultStream::error_stream(), "MaxMetaspaceFreeRatio (" UINTX_FORMAT ") must be greater than or " @@ -106,7 +150,7 @@ Flag::Error InitialTenuringThresholdConstraintFunc(bool verbose, uintx* value) { UseConcMarkSweepGCWorkaroundIfNeeded(*value, MaxTenuringThreshold); - if ((CommandLineFlags::finishedInitializing()) && (*value > MaxTenuringThreshold)) { + if (*value > MaxTenuringThreshold) { if (verbose == true) { jio_fprintf(defaultStream::error_stream(), "InitialTenuringThreshold (" UINTX_FORMAT ") must be less than or " @@ -122,7 +166,7 @@ Flag::Error MaxTenuringThresholdConstraintFunc(bool verbose, uintx* value) { UseConcMarkSweepGCWorkaroundIfNeeded(InitialTenuringThreshold, *value); - if ((CommandLineFlags::finishedInitializing()) && (*value < InitialTenuringThreshold)) { + if (*value < InitialTenuringThreshold) { if (verbose == true) { jio_fprintf(defaultStream::error_stream(), "MaxTenuringThreshold (" UINTX_FORMAT ") must be greater than or " @@ -136,9 +180,8 @@ } #if INCLUDE_ALL_GCS - Flag::Error G1NewSizePercentConstraintFunc(bool verbose, uintx* value) { - if ((CommandLineFlags::finishedInitializing()) && (*value > G1MaxNewSizePercent)) { + if (*value > G1MaxNewSizePercent) { if (verbose == true) { jio_fprintf(defaultStream::error_stream(), "G1NewSizePercent (" UINTX_FORMAT ") must be less than or " @@ -152,7 +195,7 @@ } Flag::Error G1MaxNewSizePercentConstraintFunc(bool verbose, uintx* value) { - if ((CommandLineFlags::finishedInitializing()) && (*value < G1NewSizePercent)) { + if (*value < G1NewSizePercent) { if (verbose == true) { jio_fprintf(defaultStream::error_stream(), "G1MaxNewSizePercent (" UINTX_FORMAT ") must be greater than or " @@ -168,7 +211,7 @@ #endif // INCLUDE_ALL_GCS Flag::Error CMSOldPLABMinConstraintFunc(bool verbose, size_t* value) { - if ((CommandLineFlags::finishedInitializing()) && (*value > CMSOldPLABMax)) { + if (*value > CMSOldPLABMax) { if (verbose == true) { jio_fprintf(defaultStream::error_stream(), "CMSOldPLABMin (" SIZE_FORMAT ") must be less than or " @@ -182,7 +225,7 @@ } Flag::Error CMSPrecleanDenominatorConstraintFunc(bool verbose, uintx* value) { - if ((CommandLineFlags::finishedInitializing()) && (*value <= CMSPrecleanNumerator)) { + if (*value <= CMSPrecleanNumerator) { if (verbose == true) { jio_fprintf(defaultStream::error_stream(), "CMSPrecleanDenominator (" UINTX_FORMAT ") must be strickly greater than " @@ -196,7 +239,7 @@ } Flag::Error CMSPrecleanNumeratorConstraintFunc(bool verbose, uintx* value) { - if ((CommandLineFlags::finishedInitializing()) && (*value > (CMSPrecleanDenominator - 1))) { + if (*value > (CMSPrecleanDenominator - 1)) { if (verbose == true) { jio_fprintf(defaultStream::error_stream(), "CMSPrecleanNumerator (" UINTX_FORMAT ") must be less than or " @@ -210,25 +253,23 @@ } Flag::Error SurvivorAlignmentInBytesConstraintFunc(bool verbose, intx* value) { - if (CommandLineFlags::finishedInitializing()) { - if (*value != 0) { - if (!is_power_of_2(*value)) { - if (verbose == true) { - jio_fprintf(defaultStream::error_stream(), - "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be power of 2\n", - *value); - } - return Flag::VIOLATES_CONSTRAINT; + if (*value != 0) { + if (!is_power_of_2(*value)) { + if (verbose == true) { + jio_fprintf(defaultStream::error_stream(), + "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be power of 2\n", + *value); } - if (*value < ObjectAlignmentInBytes) { - if (verbose == true) { - jio_fprintf(defaultStream::error_stream(), - "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be greater than or " - "equal to ObjectAlignmentInBytes (" INTX_FORMAT ") \n", - *value, ObjectAlignmentInBytes); - } - return Flag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; + } + if (*value < ObjectAlignmentInBytes) { + if (verbose == true) { + jio_fprintf(defaultStream::error_stream(), + "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be greater than or " + "equal to ObjectAlignmentInBytes (" INTX_FORMAT ")\n", + *value, ObjectAlignmentInBytes); } + return Flag::VIOLATES_CONSTRAINT; } } return Flag::SUCCESS; diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -34,6 +34,8 @@ * an appropriate error value. */ +Flag::Error YoungPLABSizeConstraintFunc(bool verbose, size_t* value); + Flag::Error MinHeapFreeRatioConstraintFunc(bool verbose, uintx* value); Flag::Error MaxHeapFreeRatioConstraintFunc(bool verbose, uintx* value); diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp --- a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -365,3 +365,63 @@ st->print("[ ... ]"); } } + +bool CommandLineFlagRangeList::check_ranges() { +//#define PRINT_RANGES_SIZES +#ifdef PRINT_RANGES_SIZES + { + size_t size_ranges = sizeof(CommandLineFlagRangeList); + for (int i=0; iname(); + Flag* flag = Flag::find_flag(name, strlen(name), true, true); + if (flag->is_intx()) { + size_ranges += 2*sizeof(intx); + size_ranges += sizeof(CommandLineFlagRange*); + } else if (flag->is_uintx()) { + size_ranges += 2*sizeof(uintx); + size_ranges += sizeof(CommandLineFlagRange*); + } else if (flag->is_uint64_t()) { + size_ranges += 2*sizeof(uint64_t); + size_ranges += sizeof(CommandLineFlagRange*); + } else if (flag->is_size_t()) { + size_ranges += 2*sizeof(size_t); + size_ranges += sizeof(CommandLineFlagRange*); + } else if (flag->is_double()) { + size_ranges += 2*sizeof(double); + size_ranges += sizeof(CommandLineFlagRange*); + } + } + fprintf(stderr, "Size of %d ranges: " SIZE_FORMAT " bytes\n", + length(), size_ranges); + } +#endif // PRINT_RANGES_SIZES + + // Check ranges. + bool status = true; + for (int i=0; iname(); + Flag* flag = Flag::find_flag(name, strlen(name), true, true); + if (flag != NULL) { + if (flag->is_intx()) { + intx value = flag->get_intx(); + if (range->check_intx(value, true) != Flag::SUCCESS) status = false; + } else if (flag->is_uintx()) { + uintx value = flag->get_uintx(); + if (range->check_uintx(value, true) != Flag::SUCCESS) status = false; + } else if (flag->is_uint64_t()) { + uint64_t value = flag->get_uint64_t(); + if (range->check_uint64_t(value, true) != Flag::SUCCESS) status = false; + } else if (flag->is_size_t()) { + size_t value = flag->get_size_t(); + if (range->check_size_t(value, true) != Flag::SUCCESS) status = false; + } else if (flag->is_double()) { + double value = flag->get_double(); + if (range->check_double(value, true) != Flag::SUCCESS) status = false; + } + } + } + return status; +} diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/runtime/commandLineFlagRangeList.hpp --- a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -66,6 +66,8 @@ static CommandLineFlagRange* find(const char* name); static void add(CommandLineFlagRange* range) { _ranges->append(range); } static void print(const char* name, outputStream* st, bool unspecified = false); + // Check the final values of all flags for ranges. + static bool check_ranges(); }; #endif // SHARE_VM_RUNTIME_COMMANDLINEFLAGRANGELIST_HPP diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/runtime/globals.cpp --- a/hotspot/src/share/vm/runtime/globals.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/runtime/globals.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -770,7 +770,7 @@ static Flag::Error apply_constraint_and_check_range_bool(const char* name, bool* new_value, bool verbose = true) { Flag::Error status = Flag::SUCCESS; - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find(name); + CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); if (constraint != NULL) { status = constraint->apply_bool(new_value, verbose); } @@ -789,7 +789,7 @@ Flag* result = Flag::find_flag(name, len); if (result == NULL) return Flag::INVALID_FLAG; if (!result->is_bool()) return Flag::WRONG_FORMAT; - Flag::Error check = apply_constraint_and_check_range_bool(name, value, !CommandLineFlags::finishedInitializing()); + Flag::Error check = apply_constraint_and_check_range_bool(name, value, !CommandLineFlagConstraintList::validated_after_ergo()); if (check != Flag::SUCCESS) return check; bool old_value = result->get_bool(); trace_flag_changed(name, old_value, *value, origin); @@ -817,7 +817,7 @@ range_status = range->check_int(*new_value, verbose); } Flag::Error constraint_status = Flag::SUCCESS; - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find(name); + CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); if (constraint != NULL) { constraint_status = constraint->apply_int(new_value, verbose); } @@ -836,7 +836,7 @@ Flag* result = Flag::find_flag(name, len); if (result == NULL) return Flag::INVALID_FLAG; if (!result->is_int()) return Flag::WRONG_FORMAT; - Flag::Error check = apply_constraint_and_check_range_int(name, value, !CommandLineFlags::finishedInitializing()); + Flag::Error check = apply_constraint_and_check_range_int(name, value, !CommandLineFlagConstraintList::validated_after_ergo()); if (check != Flag::SUCCESS) return check; int old_value = result->get_int(); trace_flag_changed(name, old_value, *value, origin); @@ -862,7 +862,7 @@ range_status = range->check_uint(*new_value, verbose); } Flag::Error constraint_status = Flag::SUCCESS; - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find(name); + CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); if (constraint != NULL) { constraint_status = constraint->apply_uint(new_value, verbose); } @@ -881,7 +881,7 @@ Flag* result = Flag::find_flag(name, len); if (result == NULL) return Flag::INVALID_FLAG; if (!result->is_uint()) return Flag::WRONG_FORMAT; - Flag::Error check = apply_constraint_and_check_range_uint(name, value, !CommandLineFlags::finishedInitializing()); + Flag::Error check = apply_constraint_and_check_range_uint(name, value, !CommandLineFlagConstraintList::validated_after_ergo()); if (check != Flag::SUCCESS) return check; uint old_value = result->get_uint(); trace_flag_changed(name, old_value, *value, origin); @@ -915,7 +915,7 @@ range_status = range->check_intx(*new_value, verbose); } Flag::Error constraint_status = Flag::SUCCESS; - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find(name); + CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); if (constraint != NULL) { constraint_status = constraint->apply_intx(new_value, verbose); } @@ -926,7 +926,7 @@ Flag* result = Flag::find_flag(name, len); if (result == NULL) return Flag::INVALID_FLAG; if (!result->is_intx()) return Flag::WRONG_FORMAT; - Flag::Error check = apply_constraint_and_check_range_intx(name, value, !CommandLineFlags::finishedInitializing()); + Flag::Error check = apply_constraint_and_check_range_intx(name, value, !CommandLineFlagConstraintList::validated_after_ergo()); if (check != Flag::SUCCESS) return check; intx old_value = result->get_intx(); trace_flag_changed(name, old_value, *value, origin); @@ -962,7 +962,7 @@ range_status = range->check_uintx(*new_value, verbose); } Flag::Error constraint_status = Flag::SUCCESS; - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find(name); + CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); if (constraint != NULL) { constraint_status = constraint->apply_uintx(new_value, verbose); } @@ -973,7 +973,7 @@ Flag* result = Flag::find_flag(name, len); if (result == NULL) return Flag::INVALID_FLAG; if (!result->is_uintx()) return Flag::WRONG_FORMAT; - Flag::Error check = apply_constraint_and_check_range_uintx(name, value, !CommandLineFlags::finishedInitializing()); + Flag::Error check = apply_constraint_and_check_range_uintx(name, value, !CommandLineFlagConstraintList::validated_after_ergo()); if (check != Flag::SUCCESS) return check; uintx old_value = result->get_uintx(); trace_flag_changed(name, old_value, *value, origin); @@ -1009,7 +1009,7 @@ range_status = range->check_uint64_t(*new_value, verbose); } Flag::Error constraint_status = Flag::SUCCESS; - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find(name); + CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); if (constraint != NULL) { constraint_status = constraint->apply_uint64_t(new_value, verbose); } @@ -1020,7 +1020,7 @@ Flag* result = Flag::find_flag(name, len); if (result == NULL) return Flag::INVALID_FLAG; if (!result->is_uint64_t()) return Flag::WRONG_FORMAT; - Flag::Error check = apply_constraint_and_check_range_uint64_t(name, value, !CommandLineFlags::finishedInitializing()); + Flag::Error check = apply_constraint_and_check_range_uint64_t(name, value, !CommandLineFlagConstraintList::validated_after_ergo()); if (check != Flag::SUCCESS) return check; uint64_t old_value = result->get_uint64_t(); trace_flag_changed(name, old_value, *value, origin); @@ -1056,7 +1056,7 @@ range_status = range->check_size_t(*new_value, verbose); } Flag::Error constraint_status = Flag::SUCCESS; - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find(name); + CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); if (constraint != NULL) { constraint_status = constraint->apply_size_t(new_value, verbose); } @@ -1067,7 +1067,7 @@ Flag* result = Flag::find_flag(name, len); if (result == NULL) return Flag::INVALID_FLAG; if (!result->is_size_t()) return Flag::WRONG_FORMAT; - Flag::Error check = apply_constraint_and_check_range_size_t(name, value, !CommandLineFlags::finishedInitializing()); + Flag::Error check = apply_constraint_and_check_range_size_t(name, value, !CommandLineFlagConstraintList::validated_after_ergo()); if (check != Flag::SUCCESS) return check; size_t old_value = result->get_size_t(); trace_flag_changed(name, old_value, *value, origin); @@ -1103,7 +1103,7 @@ range_status = range->check_double(*new_value, verbose); } Flag::Error constraint_status = Flag::SUCCESS; - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find(name); + CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); if (constraint != NULL) { constraint_status = constraint->apply_double(new_value, verbose); } @@ -1114,7 +1114,7 @@ Flag* result = Flag::find_flag(name, len); if (result == NULL) return Flag::INVALID_FLAG; if (!result->is_double()) return Flag::WRONG_FORMAT; - Flag::Error check = apply_constraint_and_check_range_double(name, value, !CommandLineFlags::finishedInitializing()); + Flag::Error check = apply_constraint_and_check_range_double(name, value, !CommandLineFlagConstraintList::validated_after_ergo()); if (check != Flag::SUCCESS) return check; double old_value = result->get_double(); trace_flag_changed(name, old_value, *value, origin); @@ -1127,7 +1127,7 @@ Flag::Error CommandLineFlagsEx::doubleAtPut(CommandLineFlagWithType flag, double value, Flag::Flags origin) { Flag* faddr = address_of_flag(flag); guarantee(faddr != NULL && faddr->is_double(), "wrong flag type"); - Flag::Error check = apply_constraint_and_check_range_double(faddr->_name, &value, !CommandLineFlags::finishedInitializing()); + Flag::Error check = apply_constraint_and_check_range_double(faddr->_name, &value); if (check != Flag::SUCCESS) return check; trace_flag_changed(faddr->_name, faddr->get_double(), value, origin); faddr->set_double(value); @@ -1210,129 +1210,6 @@ FREE_C_HEAP_ARRAY(Flag*, array); } -bool CommandLineFlags::_finished_initializing = false; - -bool CommandLineFlags::check_all_ranges_and_constraints() { - -//#define PRINT_RANGES_AND_CONSTRAINTS_SIZES -#ifdef PRINT_RANGES_AND_CONSTRAINTS_SIZES - { - size_t size_ranges = sizeof(CommandLineFlagRangeList); - for (int i=0; iname(); - Flag* flag = Flag::find_flag(name, strlen(name), true, true); - if (flag->is_intx()) { - size_ranges += 2*sizeof(intx); - size_ranges += sizeof(CommandLineFlagRange*); - } else if (flag->is_uintx()) { - size_ranges += 2*sizeof(uintx); - size_ranges += sizeof(CommandLineFlagRange*); - } else if (flag->is_uint64_t()) { - size_ranges += 2*sizeof(uint64_t); - size_ranges += sizeof(CommandLineFlagRange*); - } else if (flag->is_size_t()) { - size_ranges += 2*sizeof(size_t); - size_ranges += sizeof(CommandLineFlagRange*); - } else if (flag->is_double()) { - size_ranges += 2*sizeof(double); - size_ranges += sizeof(CommandLineFlagRange*); - } - } - fprintf(stderr, "Size of %d ranges: " SIZE_FORMAT " bytes\n", - CommandLineFlagRangeList::length(), size_ranges); - } - { - size_t size_constraints = sizeof(CommandLineFlagConstraintList); - for (int i=0; iname(); - Flag* flag = Flag::find_flag(name, strlen(name), true, true); - if (flag->is_bool()) { - size_constraints += sizeof(CommandLineFlagConstraintFunc_bool); - size_constraints += sizeof(CommandLineFlagConstraint*); - } else if (flag->is_intx()) { - size_constraints += sizeof(CommandLineFlagConstraintFunc_intx); - size_constraints += sizeof(CommandLineFlagConstraint*); - } else if (flag->is_uintx()) { - size_constraints += sizeof(CommandLineFlagConstraintFunc_uintx); - size_constraints += sizeof(CommandLineFlagConstraint*); - } else if (flag->is_uint64_t()) { - size_constraints += sizeof(CommandLineFlagConstraintFunc_uint64_t); - size_constraints += sizeof(CommandLineFlagConstraint*); - } else if (flag->is_size_t()) { - size_constraints += sizeof(CommandLineFlagConstraintFunc_size_t); - size_constraints += sizeof(CommandLineFlagConstraint*); - } else if (flag->is_double()) { - size_constraints += sizeof(CommandLineFlagConstraintFunc_double); - size_constraints += sizeof(CommandLineFlagConstraint*); - } - } - fprintf(stderr, "Size of %d constraints: " SIZE_FORMAT " bytes\n", - CommandLineFlagConstraintList::length(), size_constraints); - } -#endif // PRINT_RANGES_AND_CONSTRAINTS_SIZES - - _finished_initializing = true; - - bool status = true; - for (int i=0; iname(); - Flag* flag = Flag::find_flag(name, strlen(name), true, true); - if (flag != NULL) { - if (flag->is_intx()) { - intx value = flag->get_intx(); - if (range->check_intx(value, true) != Flag::SUCCESS) status = false; - } else if (flag->is_uintx()) { - uintx value = flag->get_uintx(); - if (range->check_uintx(value, true) != Flag::SUCCESS) status = false; - } else if (flag->is_uint64_t()) { - uint64_t value = flag->get_uint64_t(); - if (range->check_uint64_t(value, true) != Flag::SUCCESS) status = false; - } else if (flag->is_size_t()) { - size_t value = flag->get_size_t(); - if (range->check_size_t(value, true) != Flag::SUCCESS) status = false; - } else if (flag->is_double()) { - double value = flag->get_double(); - if (range->check_double(value, true) != Flag::SUCCESS) status = false; - } - } - } - for (int i=0; iname(); - Flag* flag = Flag::find_flag(name, strlen(name), true, true); - if (flag != NULL) { - if (flag->is_bool()) { - bool value = flag->get_bool(); - if (constraint->apply_bool(&value, true) != Flag::SUCCESS) status = false; - } else if (flag->is_intx()) { - intx value = flag->get_intx(); - if (constraint->apply_intx(&value, true) != Flag::SUCCESS) status = false; - } else if (flag->is_uintx()) { - uintx value = flag->get_uintx(); - if (constraint->apply_uintx(&value, true) != Flag::SUCCESS) status = false; - } else if (flag->is_uint64_t()) { - uint64_t value = flag->get_uint64_t(); - if (constraint->apply_uint64_t(&value, true) != Flag::SUCCESS) status = false; - } else if (flag->is_size_t()) { - size_t value = flag->get_size_t(); - if (constraint->apply_size_t(&value, true) != Flag::SUCCESS) status = false; - } else if (flag->is_double()) { - double value = flag->get_double(); - if (constraint->apply_double(&value, true) != Flag::SUCCESS) status = false; - } - } - } - - Arguments::post_final_range_and_constraint_check(status); - - return status; -} - #ifndef PRODUCT void CommandLineFlags::verify() { diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/runtime/globals.hpp --- a/hotspot/src/share/vm/runtime/globals.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/runtime/globals.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -450,7 +450,6 @@ class CommandLineFlags { - static bool _finished_initializing; public: static Flag::Error boolAt(const char* name, size_t len, bool* value, bool allow_locked = false, bool return_flag = false); static Flag::Error boolAt(const char* name, bool* value, bool allow_locked = false, bool return_flag = false) { return boolAt(name, strlen(name), value, allow_locked, return_flag); } @@ -506,12 +505,6 @@ // printRanges will print out flags type, name and range values as expected by -XX:+PrintFlagsRanges static void printFlags(outputStream* out, bool withComments, bool printRanges = false); - // Returns true if all flags have their final values set (ready for ranges and constraint check) - static bool finishedInitializing() { return _finished_initializing; } - - // Check the final values of all flags for ranges and constraints - static bool check_all_ranges_and_constraints(); - static void verify() PRODUCT_RETURN; }; @@ -640,7 +633,7 @@ lp64_product(intx, ObjectAlignmentInBytes, 8, \ "Default object alignment in bytes, 8 is minimum") \ range(8, 256) \ - constraint(ObjectAlignmentInBytesConstraintFunc) \ + constraint(ObjectAlignmentInBytesConstraintFunc,AtParse) \ \ product(bool, AssumeMP, false, \ "Instruct the VM to assume multiple processors are available") \ @@ -1286,7 +1279,7 @@ \ experimental(intx, SyncVerbose, 0, "(Unstable)") \ \ - product(bool, InlineNotify, true, "intrinsify subset of notify" ) \ + diagnostic(bool, InlineNotify, true, "intrinsify subset of notify") \ \ experimental(intx, ClearFPUAtPark, 0, "(Unsafe, Unstable)") \ \ @@ -1396,7 +1389,7 @@ product(intx, ContendedPaddingWidth, 128, \ "How many bytes to pad the fields/classes marked @Contended with")\ range(0, 8192) \ - constraint(ContendedPaddingWidthConstraintFunc) \ + constraint(ContendedPaddingWidthConstraintFunc,AtParse) \ \ product(bool, EnableContended, true, \ "Enable @Contended annotation support") \ @@ -1597,6 +1590,7 @@ \ product(size_t, YoungPLABSize, 4096, \ "Size of young gen promotion LAB's (in HeapWords)") \ + constraint(YoungPLABSizeConstraintFunc,AfterMemoryInit) \ \ product(size_t, OldPLABSize, 1024, \ "Size of old gen promotion LAB's (in HeapWords), or Number \ @@ -1735,7 +1729,7 @@ "Minimum size of CMS gen promotion LAB caches per worker " \ "per block size") \ range(1, max_uintx) \ - constraint(CMSOldPLABMinConstraintFunc) \ + constraint(CMSOldPLABMinConstraintFunc,AfterErgo) \ \ product(uintx, CMSOldPLABNumRefills, 4, \ "Nominal number of refills of CMS gen promotion LAB cache " \ @@ -1931,13 +1925,13 @@ "CMSPrecleanNumerator:CMSPrecleanDenominator yields convergence " \ "ratio") \ range(1, max_uintx) \ - constraint(CMSPrecleanDenominatorConstraintFunc) \ + constraint(CMSPrecleanDenominatorConstraintFunc,AfterErgo) \ \ product(uintx, CMSPrecleanNumerator, 2, \ "CMSPrecleanNumerator:CMSPrecleanDenominator yields convergence " \ "ratio") \ range(0, max_uintx-1) \ - constraint(CMSPrecleanNumeratorConstraintFunc) \ + constraint(CMSPrecleanNumeratorConstraintFunc,AfterErgo) \ \ product(bool, CMSPrecleanRefLists1, true, \ "Preclean ref lists during (initial) preclean phase") \ @@ -2649,8 +2643,8 @@ /* because of overflow issue */ \ product(intx, CICompilerCount, CI_COMPILER_COUNT, \ "Number of compiler threads to run") \ - range((intx)Arguments::get_min_number_of_compiler_threads(), \ - max_jint) \ + range(0, max_jint) \ + constraint(CICompilerCountConstraintFunc, AtParse) \ \ product(intx, CompilationPolicyChoice, 0, \ "which compilation policy (0-3)") \ @@ -3361,14 +3355,14 @@ " For most GCs this applies to the old generation. In G1 and" \ " ParallelGC it applies to the whole heap.") \ range(0, 100) \ - constraint(MinHeapFreeRatioConstraintFunc) \ + constraint(MinHeapFreeRatioConstraintFunc,AfterErgo) \ \ manageable(uintx, MaxHeapFreeRatio, 70, \ "The maximum percentage of heap free after GC to avoid shrinking."\ " For most GCs this applies to the old generation. In G1 and" \ " ParallelGC it applies to the whole heap.") \ range(0, 100) \ - constraint(MaxHeapFreeRatioConstraintFunc) \ + constraint(MaxHeapFreeRatioConstraintFunc,AfterErgo) \ \ product(intx, SoftRefLRUPolicyMSPerMB, 1000, \ "Number of milliseconds per MB of free space in the heap") \ @@ -3383,13 +3377,13 @@ "The maximum percentage of Metaspace free after GC to avoid " \ "shrinking") \ range(0, 100) \ - constraint(MaxMetaspaceFreeRatioConstraintFunc) \ + constraint(MaxMetaspaceFreeRatioConstraintFunc,AfterErgo) \ \ product(uintx, MinMetaspaceFreeRatio, 40, \ "The minimum percentage of Metaspace free after GC to avoid " \ "expansion") \ range(0, 99) \ - constraint(MinMetaspaceFreeRatioConstraintFunc) \ + constraint(MinMetaspaceFreeRatioConstraintFunc,AfterErgo) \ \ product(size_t, MaxMetaspaceExpansion, ScaleForWordSize(4*M), \ "The maximum expansion of Metaspace without full GC (in bytes)") \ @@ -3407,12 +3401,12 @@ product(uintx, MaxTenuringThreshold, 15, \ "Maximum value for tenuring threshold") \ range(0, markOopDesc::max_age + 1) \ - constraint(MaxTenuringThresholdConstraintFunc) \ + constraint(MaxTenuringThresholdConstraintFunc,AfterErgo) \ \ product(uintx, InitialTenuringThreshold, 7, \ "Initial value for tenuring threshold") \ range(0, markOopDesc::max_age + 1) \ - constraint(InitialTenuringThresholdConstraintFunc) \ + constraint(InitialTenuringThresholdConstraintFunc,AfterErgo) \ \ product(uintx, TargetSurvivorRatio, 50, \ "Desired percentage of survivor space used after scavenge") \ @@ -4090,7 +4084,7 @@ \ experimental(intx, SurvivorAlignmentInBytes, 0, \ "Default survivor space alignment in bytes") \ - constraint(SurvivorAlignmentInBytesConstraintFunc) \ + constraint(SurvivorAlignmentInBytesConstraintFunc,AfterErgo) \ \ product(bool , AllowNonVirtualCalls, false, \ "Obey the ACC_SUPER flag and allow invokenonvirtual calls") \ @@ -4194,7 +4188,7 @@ // Only materialize src code for range checking when required, ignore otherwise #define IGNORE_RANGE(a, b) // Only materialize src code for contraint checking when required, ignore otherwise -#define IGNORE_CONSTRAINT(func) +#define IGNORE_CONSTRAINT(func,type) RUNTIME_FLAGS(DECLARE_DEVELOPER_FLAG, \ DECLARE_PD_DEVELOPER_FLAG, \ diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/runtime/mutexLocker.cpp --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -83,7 +83,6 @@ Monitor* DirtyCardQ_CBL_mon = NULL; Mutex* Shared_DirtyCardQ_lock = NULL; Mutex* ParGCRareEvent_lock = NULL; -Mutex* EvacFailureStack_lock = NULL; Mutex* DerivedPointerTableGC_lock = NULL; Mutex* Compile_lock = NULL; Monitor* MethodCompileQueue_lock = NULL; @@ -201,7 +200,6 @@ def(OldSets_lock , Mutex , leaf , true, Monitor::_safepoint_check_never); def(RootRegionScan_lock , Monitor, leaf , true, Monitor::_safepoint_check_never); def(MMUTracker_lock , Mutex , leaf , true, Monitor::_safepoint_check_never); - def(EvacFailureStack_lock , Mutex , nonleaf , true, Monitor::_safepoint_check_never); def(StringDedupQueue_lock , Monitor, leaf, true, Monitor::_safepoint_check_never); def(StringDedupTable_lock , Mutex , leaf, true, Monitor::_safepoint_check_never); diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/runtime/mutexLocker.hpp --- a/hotspot/src/share/vm/runtime/mutexLocker.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -87,7 +87,6 @@ // non-Java threads. // (see option ExplicitGCInvokesConcurrent) extern Mutex* ParGCRareEvent_lock; // Synchronizes various (rare) parallel GC ops. -extern Mutex* EvacFailureStack_lock; // guards the evac failure scan stack extern Mutex* Compile_lock; // a lock held when Compilation is updating code (used to block CodeCache traversal, CHA updates, etc) extern Monitor* MethodCompileQueue_lock; // a lock held when method compilations are enqueued, dequeued extern Monitor* CompileThread_lock; // a lock held by compile threads during compilation system initialization diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/runtime/os.cpp --- a/hotspot/src/share/vm/runtime/os.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/runtime/os.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -843,6 +843,28 @@ pd_print_cpu_info(st, buf, buflen); } +// Print a one line string summarizing the cpu, number of cores, memory, and operating system version +void os::print_summary_info(outputStream* st, char* buf, size_t buflen) { + st->print("Host: "); +#ifndef PRODUCT + if (get_host_name(buf, buflen)) { + st->print("%s, ", buf); + } +#endif // PRODUCT + get_summary_cpu_info(buf, buflen); + st->print("%s, ", buf); + size_t mem = physical_memory()/G; + if (mem == 0) { // for low memory systems + mem = physical_memory()/M; + st->print("%d cores, %dM, ", processor_count(), mem); + } else { + st->print("%d cores, %dG, ", processor_count(), mem); + } + get_summary_os_info(buf, buflen); + st->print_raw(buf); + st->cr(); +} + void os::print_date_and_time(outputStream *st, char* buf, size_t buflen) { const int secs_per_day = 86400; const int secs_per_hour = 3600; @@ -850,12 +872,19 @@ time_t tloc; (void)time(&tloc); - st->print("time: %s", ctime(&tloc)); // ctime adds newline. + char* timestring = ctime(&tloc); // ctime adds newline. + // edit out the newline + char* nl = strchr(timestring, '\n'); + if (nl != NULL) { + *nl = '\0'; + } struct tm tz; if (localtime_pd(&tloc, &tz) != NULL) { ::strftime(buf, buflen, "%Z", &tz); - st->print_cr("timezone: %s", buf); + st->print("Time: %s %s", timestring, buf); + } else { + st->print("Time: %s", timestring); } double t = os::elapsedTime(); @@ -872,7 +901,7 @@ int elmins = (eltime - day_secs - hour_secs) / secs_per_min; int minute_secs = elmins * secs_per_min; int elsecs = (eltime - day_secs - hour_secs - minute_secs); - st->print_cr("elapsed time: %d seconds (%dd %dh %dm %ds)", eltime, eldays, elhours, elmins, elsecs); + st->print_cr(" elapsed time: %d seconds (%dd %dh %dm %ds)", eltime, eldays, elhours, elmins, elsecs); } // moved from debug.cpp (used to be find()) but still called from there diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/runtime/os.hpp --- a/hotspot/src/share/vm/runtime/os.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/runtime/os.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -150,6 +150,11 @@ static size_t page_size_for_region(size_t region_size, size_t min_pages, bool must_be_aligned); + // Get summary strings for system information in buffer provided + static bool get_host_name(char* buf, size_t buflen) PRODUCT_RETURN_(return false;); // true if available + static void get_summary_cpu_info(char* buf, size_t buflen); + static void get_summary_os_info(char* buf, size_t buflen); + public: static void init(void); // Called before command line parsing static void init_before_ergo(void); // Called after command line parsing @@ -590,6 +595,7 @@ static void print_os_info_brief(outputStream* st); static void print_cpu_info(outputStream* st, char* buf, size_t buflen); static void pd_print_cpu_info(outputStream* st, char* buf, size_t buflen); + static void print_summary_info(outputStream* st, char* buf, size_t buflen); static void print_memory_info(outputStream* st); static void print_dll_info(outputStream* st); static void print_environment_variables(outputStream* st, const char** env_list); diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/runtime/thread.cpp --- a/hotspot/src/share/vm/runtime/thread.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/runtime/thread.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -52,6 +52,8 @@ #include "runtime/arguments.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/biasedLocking.hpp" +#include "runtime/commandLineFlagConstraintList.hpp" +#include "runtime/commandLineFlagRangeList.hpp" #include "runtime/deoptimization.hpp" #include "runtime/fprofiler.hpp" #include "runtime/frame.inline.hpp" @@ -2739,6 +2741,9 @@ if (ct->env() != NULL) { ct->env()->metadata_do(f); } + if (ct->task() != NULL) { + ct->task()->metadata_do(f); + } } } @@ -3319,8 +3324,15 @@ jint ergo_result = Arguments::apply_ergo(); if (ergo_result != JNI_OK) return ergo_result; - // Final check of all arguments after ergonomics which may change values. - if (!CommandLineFlags::check_all_ranges_and_constraints()) { + // Final check of all ranges after ergonomics which may change values. + if (!CommandLineFlagRangeList::check_ranges()) { + return JNI_EINVAL; + } + + // Final check of all 'AfterErgo' constraints after ergonomics which may change values. + bool constraint_result = CommandLineFlagConstraintList::check_constraints(CommandLineFlagConstraint::AfterErgo); + Arguments::post_after_ergo_constraint_check(constraint_result); + if (!constraint_result) { return JNI_EINVAL; } diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/runtime/vframe.cpp --- a/hotspot/src/share/vm/runtime/vframe.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/runtime/vframe.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -148,8 +148,7 @@ if (obj.not_null()) { st->print("\t- %s <" INTPTR_FORMAT "> ", lock_state, (address)obj()); if (obj->klass() == SystemDictionary::Class_klass()) { - Klass* target_klass = java_lang_Class::as_Klass(obj()); - st->print_cr("(a java.lang.Class for %s)", InstanceKlass::cast(target_klass)->external_name()); + st->print_cr("(a java.lang.Class for %s)", java_lang_Class::as_external_name(obj())); } else { Klass* k = obj->klass(); st->print_cr("(a %s)", k->external_name()); diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/services/heapDumper.cpp --- a/hotspot/src/share/vm/services/heapDumper.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/services/heapDumper.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -899,6 +899,11 @@ assert(klass->oop_is_instance(), "not an InstanceKlass"); InstanceKlass* ik = (InstanceKlass*)klass; + // Ignore the class if it hasn't been initialized yet + if (!ik->is_linked()) { + return; + } + writer->write_u1(HPROF_GC_CLASS_DUMP); // class ID diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/shark/sharkBuilder.cpp --- a/hotspot/src/share/vm/shark/sharkBuilder.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/shark/sharkBuilder.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -25,6 +25,8 @@ #include "precompiled.hpp" #include "ci/ciMethod.hpp" +#include "gc/shared/barrierSet.hpp" +#include "gc/shared/cardTableModRefBS.hpp" #include "memory/resourceArea.hpp" #include "oops/method.hpp" #include "runtime/os.hpp" @@ -442,7 +444,7 @@ Unimplemented(); CreateStore( - LLVMValue::jbyte_constant(CardTableModRefBS::dirty_card), + LLVMValue::jbyte_constant(CardTableModRefBS::dirty_card_val()), CreateIntToPtr( CreateAdd( LLVMValue::intptr_constant( diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/shark/sharkBuilder.hpp --- a/hotspot/src/share/vm/shark/sharkBuilder.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/shark/sharkBuilder.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -27,8 +27,6 @@ #define SHARE_VM_SHARK_SHARKBUILDER_HPP #include "ci/ciType.hpp" -#include "gc/shared/barrierSet.hpp" -#include "gc/shared/cardTableModRefBS.hpp" #include "shark/llvmHeaders.hpp" #include "shark/llvmValue.hpp" #include "shark/sharkCodeBuffer.hpp" @@ -38,6 +36,8 @@ #include "utilities/debug.hpp" #include "utilities/sizes.hpp" +class BarrierSet; + class SharkBuilder : public llvm::IRBuilder<> { friend class SharkCompileInvariants; diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/utilities/vmError.cpp --- a/hotspot/src/share/vm/utilities/vmError.cpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/utilities/vmError.cpp Fri Jul 31 10:15:02 2015 -0700 @@ -306,6 +306,30 @@ #endif // ZERO } +void VMError::print_oom_reasons(outputStream* st) { + st->print_cr("# Possible reasons:"); + st->print_cr("# The system is out of physical RAM or swap space"); + st->print_cr("# In 32 bit mode, the process size limit was hit"); + st->print_cr("# Possible solutions:"); + st->print_cr("# Reduce memory load on the system"); + st->print_cr("# Increase physical memory or swap space"); + st->print_cr("# Check if swap backing store is full"); + st->print_cr("# Use 64 bit Java on a 64 bit OS"); + st->print_cr("# Decrease Java heap size (-Xmx/-Xms)"); + st->print_cr("# Decrease number of Java threads"); + st->print_cr("# Decrease Java thread stack sizes (-Xss)"); + st->print_cr("# Set larger code cache with -XX:ReservedCodeCacheSize="); + st->print_cr("# This output file may be truncated or incomplete."); +} + +const char* VMError::gc_mode() { + if (UseG1GC) return "g1 gc"; + if (UseParallelGC) return "parallel gc"; + if (UseConcMarkSweepGC) return "concurrent mark sweep gc"; + if (UseSerialGC) return "serial gc"; + return "ERROR in GC mode"; +} + // This is the main function to report a fatal error. Only one thread can // call this function, so we don't need to worry about MT-safety. But it's // possible that the error handler itself may crash or die on an internal @@ -358,21 +382,21 @@ // test secondary error handling. Test it twice, to test that resetting // error handler after a secondary crash works. - STEP(11, "(test secondary crash 1)") + STEP(20, "(test secondary crash 1)") if (_verbose && TestCrashInErrorHandler != 0) { st->print_cr("Will crash now (TestCrashInErrorHandler=%d)...", TestCrashInErrorHandler); controlled_crash(TestCrashInErrorHandler); } - STEP(12, "(test secondary crash 2)") + STEP(30, "(test secondary crash 2)") if (_verbose && TestCrashInErrorHandler != 0) { st->print_cr("Will crash now (TestCrashInErrorHandler=%d)...", TestCrashInErrorHandler); controlled_crash(TestCrashInErrorHandler); } - STEP(13, "(test safefetch in error handler)") + STEP(40, "(test safefetch in error handler)") // test whether it is safe to use SafeFetch32 in Crash Handler. Test twice // to test that resetting the signal handler works correctly. if (_verbose && TestSafeFetchInErrorHandler) { @@ -393,7 +417,7 @@ } #endif // PRODUCT - STEP(15, "(printing type of error)") + STEP(50, "(printing type of error)") switch(_id) { case OOM_MALLOC_ERROR: @@ -418,19 +442,7 @@ } // In error file give some solutions if (_verbose) { - st->print_cr("# Possible reasons:"); - st->print_cr("# The system is out of physical RAM or swap space"); - st->print_cr("# In 32 bit mode, the process size limit was hit"); - st->print_cr("# Possible solutions:"); - st->print_cr("# Reduce memory load on the system"); - st->print_cr("# Increase physical memory or swap space"); - st->print_cr("# Check if swap backing store is full"); - st->print_cr("# Use 64 bit Java on a 64 bit OS"); - st->print_cr("# Decrease Java heap size (-Xmx/-Xms)"); - st->print_cr("# Decrease number of Java threads"); - st->print_cr("# Decrease Java thread stack sizes (-Xss)"); - st->print_cr("# Set larger code cache with -XX:ReservedCodeCacheSize="); - st->print_cr("# This output file may be truncated or incomplete."); + print_oom_reasons(st); } else { return; // that's enough for the screen } @@ -440,7 +452,7 @@ break; } - STEP(20, "(printing exception/signal name)") + STEP(60, "(printing exception/signal name)") st->print_cr("#"); st->print("# "); @@ -470,14 +482,14 @@ } } - STEP(30, "(printing current thread and pid)") + STEP(70, "(printing current thread and pid)") // process id, thread id st->print(", pid=%d", os::current_process_id()); st->print(", tid=" INTPTR_FORMAT, os::current_thread_id()); st->cr(); - STEP(40, "(printing error message)") + STEP(80, "(printing error message)") if (should_report_bug(_id)) { // already printed the message. // error message @@ -488,7 +500,7 @@ } } - STEP(50, "(printing Java version string)") + STEP(90, "(printing Java version string)") // VM version st->print_cr("#"); @@ -498,15 +510,18 @@ const char* runtime_version = JDK_Version::runtime_version() != NULL ? JDK_Version::runtime_version() : ""; st->print_cr("# JRE version: %s (%s) (build %s)", runtime_name, buf, runtime_version); - st->print_cr("# Java VM: %s (%s %s %s %s)", + // This is the long version with some default settings added + st->print_cr("# Java VM: %s (%s, %s%s%s, %s, %s)", Abstract_VM_Version::vm_name(), Abstract_VM_Version::vm_release(), Abstract_VM_Version::vm_info_string(), - Abstract_VM_Version::vm_platform_string(), - UseCompressedOops ? "compressed oops" : "" + TieredCompilation ? ", tiered" : "", + UseCompressedOops ? ", compressed oops" : "", + gc_mode(), + Abstract_VM_Version::vm_platform_string() ); - STEP(60, "(printing problematic frame)") + STEP(100, "(printing problematic frame)") // Print current frame if we have a context (i.e. it's a crash) if (_context) { @@ -517,7 +532,8 @@ st->cr(); st->print_cr("#"); } - STEP(63, "(printing core file information)") + + STEP(110, "(printing core file information)") st->print("# "); if (CreateCoredumpOnCrash) { if (coredump_status) { @@ -531,13 +547,42 @@ st->cr(); st->print_cr("#"); - STEP(65, "(printing bug submit message)") + STEP(120, "(printing bug submit message)") if (should_report_bug(_id) && _verbose) { print_bug_submit_message(st, _thread); } - STEP(70, "(printing thread)" ) + STEP(130, "(printing summary)" ) + + if (_verbose) { + st->cr(); + st->print_cr("--------------- S U M M A R Y ------------"); + st->cr(); + } + + STEP(140, "(printing VM option summary)" ) + + if (_verbose) { + // VM options + Arguments::print_summary_on(st); + st->cr(); + } + + STEP(150, "(printing summary machine and OS info)") + + if (_verbose) { + os::print_summary_info(st, buf, sizeof(buf)); + } + + + STEP(160, "(printing date and time)" ) + + if (_verbose) { + os::print_date_and_time(st, buf, sizeof(buf)); + } + + STEP(170, "(printing thread)" ) if (_verbose) { st->cr(); @@ -545,7 +590,7 @@ st->cr(); } - STEP(80, "(printing current thread)" ) + STEP(180, "(printing current thread)" ) // current thread if (_verbose) { @@ -559,31 +604,20 @@ st->cr(); } - STEP(90, "(printing siginfo)" ) + STEP(190, "(printing current compile task)" ) - // signal no, signal code, address that caused the fault - if (_verbose && _siginfo) { - os::print_siginfo(st, _siginfo); - st->cr(); + if (_verbose && _thread && _thread->is_Compiler_thread()) { + CompilerThread* t = (CompilerThread*)_thread; + if (t->task()) { + st->cr(); + st->print_cr("Current CompileTask:"); + t->task()->print_line_on_error(st, buf, sizeof(buf)); + st->cr(); + } } - STEP(100, "(printing registers, top of stack, instructions near pc)") - // registers, top of stack, instructions near pc - if (_verbose && _context) { - os::print_context(st, _context); - st->cr(); - } - - STEP(105, "(printing register info)") - - // decode register contents if possible - if (_verbose && _context && Universe::is_fully_initialized()) { - os::print_register_info(st, _context); - st->cr(); - } - - STEP(110, "(printing stack bounds)" ) + STEP(200, "(printing stack bounds)" ) if (_verbose) { st->print("Stack: "); @@ -614,7 +648,7 @@ st->cr(); } - STEP(120, "(printing native stack)" ) + STEP(210, "(printing native stack)" ) if (_verbose) { if (os::platform_print_native_stack(st, _context, buf, sizeof(buf))) { @@ -628,13 +662,13 @@ } } - STEP(130, "(printing Java stack)" ) + STEP(220, "(printing Java stack)" ) if (_verbose && _thread && _thread->is_Java_thread()) { print_stack_trace(st, (JavaThread*)_thread, buf, sizeof(buf)); } - STEP(135, "(printing target Java thread stack)" ) + STEP(230, "(printing target Java thread stack)" ) // printing Java thread stack trace if it is involved in GC crash if (_verbose && _thread && (_thread->is_Named_thread())) { @@ -645,7 +679,32 @@ } } - STEP(140, "(printing VM operation)" ) + STEP(240, "(printing siginfo)" ) + + // signal no, signal code, address that caused the fault + if (_verbose && _siginfo) { + st->cr(); + os::print_siginfo(st, _siginfo); + st->cr(); + } + + STEP(250, "(printing register info)") + + // decode register contents if possible + if (_verbose && _context && Universe::is_fully_initialized()) { + os::print_register_info(st, _context); + st->cr(); + } + + STEP(260, "(printing registers, top of stack, instructions near pc)") + + // registers, top of stack, instructions near pc + if (_verbose && _context) { + os::print_context(st, _context); + st->cr(); + } + + STEP(270, "(printing VM operation)" ) if (_verbose && _thread && _thread->is_VM_thread()) { VMThread* t = (VMThread*)_thread; @@ -657,19 +716,7 @@ } } - STEP(150, "(printing current compile task)" ) - - if (_verbose && _thread && _thread->is_Compiler_thread()) { - CompilerThread* t = (CompilerThread*)_thread; - if (t->task()) { - st->cr(); - st->print_cr("Current CompileTask:"); - t->task()->print_line_on_error(st, buf, sizeof(buf)); - st->cr(); - } - } - - STEP(160, "(printing process)" ) + STEP(280, "(printing process)" ) if (_verbose) { st->cr(); @@ -677,7 +724,7 @@ st->cr(); } - STEP(170, "(printing all threads)" ) + STEP(290, "(printing all threads)" ) // all threads if (_verbose && _thread) { @@ -685,7 +732,7 @@ st->cr(); } - STEP(175, "(printing VM state)" ) + STEP(300, "(printing VM state)" ) if (_verbose) { // Safepoint state @@ -707,7 +754,7 @@ st->cr(); } - STEP(180, "(printing owned locks on error)" ) + STEP(310, "(printing owned locks on error)" ) // mutexes/monitors that currently have an owner if (_verbose) { @@ -715,7 +762,7 @@ st->cr(); } - STEP(182, "(printing number of OutOfMemoryError and StackOverflow exceptions)") + STEP(320, "(printing number of OutOfMemoryError and StackOverflow exceptions)") if (_verbose && Exceptions::has_exception_counts()) { st->print_cr("OutOfMemory and StackOverflow Exception counts:"); @@ -723,7 +770,7 @@ st->cr(); } - STEP(185, "(printing compressed oops mode") + STEP(330, "(printing compressed oops mode") if (_verbose && UseCompressedOops) { Universe::print_compressed_oops_mode(st); @@ -733,7 +780,7 @@ st->cr(); } - STEP(190, "(printing heap information)" ) + STEP(340, "(printing heap information)" ) if (_verbose && Universe::is_fully_initialized()) { Universe::heap()->print_on_error(st); @@ -743,7 +790,7 @@ st->cr(); } - STEP(195, "(printing code cache information)" ) + STEP(350, "(printing code cache information)" ) if (_verbose && Universe::is_fully_initialized()) { // print code cache information before vm abort @@ -751,14 +798,14 @@ st->cr(); } - STEP(200, "(printing ring buffers)" ) + STEP(360, "(printing ring buffers)" ) if (_verbose) { Events::print_all(st); st->cr(); } - STEP(205, "(printing dynamic libraries)" ) + STEP(370, "(printing dynamic libraries)" ) if (_verbose) { // dynamic libraries, or memory map @@ -766,7 +813,7 @@ st->cr(); } - STEP(210, "(printing VM options)" ) + STEP(380, "(printing VM options)" ) if (_verbose) { // VM options @@ -774,33 +821,33 @@ st->cr(); } - STEP(215, "(printing warning if internal testing API used)" ) + STEP(390, "(printing warning if internal testing API used)" ) if (WhiteBox::used()) { st->print_cr("Unsupported internal testing APIs have been used."); st->cr(); } - STEP(220, "(printing environment variables)" ) + STEP(400, "(printing all environment variables)" ) if (_verbose) { os::print_environment_variables(st, env_list); st->cr(); } - STEP(225, "(printing signal handlers)" ) + STEP(410, "(printing signal handlers)" ) if (_verbose) { os::print_signal_handlers(st, buf, sizeof(buf)); st->cr(); } - STEP(228, "(Native Memory Tracking)" ) + STEP(420, "(Native Memory Tracking)" ) if (_verbose) { MemTracker::error_report(st); } - STEP(230, "" ) + STEP(430, "(printing system)" ) if (_verbose) { st->cr(); @@ -808,48 +855,39 @@ st->cr(); } - STEP(240, "(printing OS information)" ) + STEP(440, "(printing OS information)" ) if (_verbose) { os::print_os_info(st); st->cr(); } - STEP(250, "(printing CPU info)" ) + STEP(450, "(printing CPU info)" ) if (_verbose) { os::print_cpu_info(st, buf, sizeof(buf)); st->cr(); } - STEP(260, "(printing memory info)" ) + STEP(460, "(printing memory info)" ) if (_verbose) { os::print_memory_info(st); st->cr(); } - STEP(270, "(printing internal vm info)" ) + STEP(470, "(printing internal vm info)" ) if (_verbose) { st->print_cr("vm_info: %s", Abstract_VM_Version::internal_vm_info_string()); st->cr(); } - STEP(280, "(printing date and time)" ) - - if (_verbose) { - os::print_date_and_time(st, buf, sizeof(buf)); - st->cr(); - } - -#ifndef PRODUCT // print a defined marker to show that error handling finished correctly. - STEP(290, "(printing end marker)" ) + STEP(480, "(printing end marker)" ) if (_verbose) { st->print_cr("END."); } -#endif END diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/src/share/vm/utilities/vmError.hpp --- a/hotspot/src/share/vm/utilities/vmError.hpp Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/src/share/vm/utilities/vmError.hpp Fri Jul 31 10:15:02 2015 -0700 @@ -89,6 +89,9 @@ static void print_stack_trace(outputStream* st, JavaThread* jt, char* buf, int buflen, bool verbose = false); + static const char* gc_mode(); + static void print_oom_reasons(outputStream* st); + // accessor const char* message() const { return _message; } const char* detail_msg() const { return _detail_msg; } diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/test/compiler/arguments/CheckCICompilerCount.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/arguments/CheckCICompilerCount.java Fri Jul 31 10:15:02 2015 -0700 @@ -0,0 +1,135 @@ +/* + * 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. + */ + +import jdk.test.lib.*; + +/* + * @test CheckCheckCICompilerCount + * @bug 8130858 + * @summary Check that correct range of values for CICompilerCount are allowed depending on whether tiered is enabled or not + * @library /testlibrary + * @modules java.base/sun.misc + * java.management + * @run main CheckCICompilerCount + */ + +public class CheckCICompilerCount { + private static final String[][] NON_TIERED_ARGUMENTS = { + { + "-XX:-TieredCompilation", + "-XX:+PrintFlagsFinal", + "-XX:CICompilerCount=0", + "-version" + }, + { + "-XX:-TieredCompilation", + "-XX:+PrintFlagsFinal", + "-XX:CICompilerCount=1", + "-version" + } + }; + + private static final String[][] NON_TIERED_EXPECTED_OUTPUTS = { + { + "CICompilerCount=0 must be at least 1", + "Improperly specified VM option 'CICompilerCount=0'" + }, + { + "intx CICompilerCount := 1 {product}" + } + }; + + private static final int[] NON_TIERED_EXIT = { + 1, + 0 + }; + + private static final String[][] TIERED_ARGUMENTS = { + { + "-XX:+TieredCompilation", + "-XX:+PrintFlagsFinal", + "-XX:CICompilerCount=1", + "-version" + }, + { + "-XX:+TieredCompilation", + "-XX:+PrintFlagsFinal", + "-XX:CICompilerCount=2", + "-version" + } + }; + + private static final String[][] TIERED_EXPECTED_OUTPUTS = { + { + "CICompilerCount=1 must be at least 2", + "Improperly specified VM option 'CICompilerCount=1'" + }, + { + "intx CICompilerCount := 2 {product}" + } + }; + + private static final int[] TIERED_EXIT = { + 1, + 0 + }; + + private static void verifyValidOption(String[] arguments, String[] expected_outputs, int exit, boolean tiered) throws Exception { + ProcessBuilder pb; + OutputAnalyzer out; + + pb = ProcessTools.createJavaProcessBuilder(arguments); + out = new OutputAnalyzer(pb.start()); + + try { + out.shouldHaveExitValue(exit); + for (String expected_output : expected_outputs) { + out.shouldContain(expected_output); + } + } catch (RuntimeException e) { + // Check if tiered compilation is available in this JVM + // Version. Throw exception only if it is available. + if (!(tiered && out.getOutput().contains("TieredCompilation is disabled in this release."))) { + throw new RuntimeException(e); + } + } + } + + public static void main(String[] args) throws Exception { + if (NON_TIERED_ARGUMENTS.length != NON_TIERED_EXPECTED_OUTPUTS.length || NON_TIERED_ARGUMENTS.length != NON_TIERED_EXIT.length) { + throw new RuntimeException("Test is set up incorrectly: length of arguments, expected outputs and exit codes in non-tiered mode of operation do not match."); + } + + if (TIERED_ARGUMENTS.length != TIERED_EXPECTED_OUTPUTS.length || TIERED_ARGUMENTS.length != TIERED_EXIT.length) { + throw new RuntimeException("Test is set up incorrectly: length of arguments, expected outputs and exit codes in tiered mode of operation do not match."); + } + + for (int i = 0; i < NON_TIERED_ARGUMENTS.length; i++) { + verifyValidOption(NON_TIERED_ARGUMENTS[i], NON_TIERED_EXPECTED_OUTPUTS[i], NON_TIERED_EXIT[i], false); + } + + for (int i = 0; i < TIERED_ARGUMENTS.length; i++) { + verifyValidOption(TIERED_ARGUMENTS[i], TIERED_EXPECTED_OUTPUTS[i], TIERED_EXIT[i], true); + } + } +} diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/test/compiler/intrinsics/IntrinsicAvailableTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/intrinsics/IntrinsicAvailableTest.java Fri Jul 31 10:15:02 2015 -0700 @@ -0,0 +1,126 @@ +/* + * 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. + */ +import java.lang.reflect.Executable; +import java.util.concurrent.Callable; +import java.util.Objects; +/* + * @test + * @bug 8130832 + * @library /testlibrary /../../test/lib /compiler/whitebox /compiler/testlibrary + * @build IntrinsicAvailableTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI + * -XX:+UseCRC32Intrinsics + * IntrinsicAvailableTest + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI + * -XX:-UseCRC32Intrinsics + * IntrinsicAvailableTest + */ +public class IntrinsicAvailableTest extends CompilerWhiteBoxTest { + protected String VMName; + + public IntrinsicAvailableTest(IntrinsicAvailableTestTestCase testCase) { + super(testCase); + VMName = System.getProperty("java.vm.name"); + } + + public static class IntrinsicAvailableTestTestCase implements TestCase { + + public String name() { + return "IntrinsicAvailableTestTestCase"; + } + + public Executable getExecutable() { + // Using a single method to test the + // WhiteBox.isIntrinsicAvailable(Executable method, int compLevel) + // call for the compilation level corresponding to both the C1 and C2 + // compiler keeps the current test simple. + // + // The tested method is java.util.zip.CRC32.update(int, int) because + // both C1 and C2 define an intrinsic for the method and + // the UseCRC32Intrinsics flag can be used to enable/disable + // intrinsification of the method in both product and fastdebug + // builds. + try { + return Class.forName("java.util.zip.CRC32").getDeclaredMethod("update", int.class, int.class); + } catch (NoSuchMethodException e) { + throw new RuntimeException("Test bug, method unavailable. " + e); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Test bug, class unavailable. " + e); + } + } + + public Callable getCallable() { + return null; + } + + public boolean isOsr() { + return false; + } + + } + + protected void checkIntrinsicForCompilationLevel(Executable method, int compLevel) throws Exception { + boolean intrinsicEnabled = Boolean.valueOf(getVMOption("UseCRC32Intrinsics")); + boolean intrinsicAvailable = WHITE_BOX.isIntrinsicAvailable(method, + compLevel); + + String intrinsicEnabledMessage = intrinsicEnabled ? "enabled" : "disabled"; + String intrinsicAvailableMessage = intrinsicAvailable ? "available" : "not available"; + + if (intrinsicEnabled == intrinsicAvailable) { + System.out.println("Expected result: intrinsic for java.util.zip.CRC32.update() is " + + intrinsicEnabledMessage + " and intrinsic is " + intrinsicAvailableMessage + + " at compilation level " + compLevel); + } else { + throw new RuntimeException("Unexpected result: intrinsic for java.util.zip.CRC32.update() is " + + intrinsicEnabledMessage + " but intrinsic is " + intrinsicAvailableMessage + + " at compilation level " + compLevel); + } + } + + protected boolean isServerVM() { + return VMName.toLowerCase().contains("server"); + } + + public void test() throws Exception { + Executable intrinsicMethod = testCase.getExecutable(); + if (isServerVM()) { + if (TIERED_COMPILATION) { + checkIntrinsicForCompilationLevel(intrinsicMethod, COMP_LEVEL_SIMPLE); + } + checkIntrinsicForCompilationLevel(intrinsicMethod, COMP_LEVEL_FULL_OPTIMIZATION); + } else { + checkIntrinsicForCompilationLevel(intrinsicMethod, COMP_LEVEL_SIMPLE); + } + } + + public static void main(String args[]) throws Exception { + new IntrinsicAvailableTest(new IntrinsicAvailableTestTestCase()).test(); + } +} diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java Fri Jul 31 10:15:02 2015 -0700 @@ -67,7 +67,7 @@ compileAtLevel(CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE); } - if (!isIntrinsicSupported()) { + if (!isIntrinsicAvailable()) { expectedIntrinsicCount = 0; } break; @@ -114,7 +114,11 @@ } } - protected abstract boolean isIntrinsicSupported(); + // An intrinsic is available if: + // - the intrinsic is enabled (by using the appropriate command-line flag) and + // - the intrinsic is supported by the VM (i.e., the platform on which the VM is + // running provides the instructions necessary for the VM to generate the intrinsic). + protected abstract boolean isIntrinsicAvailable(); protected abstract String getIntrinsicId(); @@ -123,14 +127,20 @@ } static class IntTest extends IntrinsicBase { + + protected boolean isIntrinsicAvailable; // The tested intrinsic is available on the current platform. + protected IntTest(MathIntrinsic.IntIntrinsic testCase) { super(testCase); + // Only the C2 compiler intrinsifies exact math methods + // so check if the intrinsics are available with C2. + isIntrinsicAvailable = WHITE_BOX.isIntrinsicAvailable(testCase.getTestMethod(), + COMP_LEVEL_FULL_OPTIMIZATION); } @Override - protected boolean isIntrinsicSupported() { - return isServerVM() && Boolean.valueOf(useMathExactIntrinsics) - && (Platform.isX86() || Platform.isX64() || Platform.isAArch64()); + protected boolean isIntrinsicAvailable() { + return isIntrinsicAvailable; } @Override @@ -140,14 +150,20 @@ } static class LongTest extends IntrinsicBase { + + protected boolean isIntrinsicAvailable; // The tested intrinsic is available on the current platform. + protected LongTest(MathIntrinsic.LongIntrinsic testCase) { super(testCase); + // Only the C2 compiler intrinsifies exact math methods + // so check if the intrinsics are available with C2. + isIntrinsicAvailable = WHITE_BOX.isIntrinsicAvailable(testCase.getTestMethod(), + COMP_LEVEL_FULL_OPTIMIZATION); } @Override - protected boolean isIntrinsicSupported() { - return isServerVM() && Boolean.valueOf(useMathExactIntrinsics) && - (Platform.isX64() || Platform.isPPC() || Platform.isAArch64()); + protected boolean isIntrinsicAvailable() { + return isIntrinsicAvailable; } @Override diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/test/compiler/intrinsics/mathexact/sanity/MathIntrinsic.java --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/MathIntrinsic.java Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/MathIntrinsic.java Fri Jul 31 10:15:02 2015 -0700 @@ -29,11 +29,21 @@ enum IntIntrinsic implements CompilerWhiteBoxTest.TestCase { Add { @Override + Executable testMethod() throws NoSuchMethodException, ClassNotFoundException { + return Class.forName("java.lang.Math").getDeclaredMethod("addExact", int.class, int.class); + } + + @Override Object execMathMethod() { return intR = Math.addExact(int1, int2); } }, - Subtract { + Subtract { + @Override + Executable testMethod() throws NoSuchMethodException, ClassNotFoundException { + return Class.forName("java.lang.Math").getDeclaredMethod("subtractExact", int.class, int.class); + } + @Override Object execMathMethod() { return intR = Math.subtractExact(int1, int2); @@ -41,34 +51,66 @@ }, Multiply { @Override + Executable testMethod() throws NoSuchMethodException, ClassNotFoundException { + return Class.forName("java.lang.Math").getDeclaredMethod("multiplyExact", int.class, int.class); + } + + @Override Object execMathMethod() { return intR = Math.multiplyExact(int1, int2); } }, Increment { @Override + Executable testMethod() throws NoSuchMethodException, ClassNotFoundException { + return Class.forName("java.lang.Math").getDeclaredMethod("incrementExact", int.class); + } + + @Override Object execMathMethod() { return intR = Math.incrementExact(int1); } }, Decrement { @Override + Executable testMethod() throws NoSuchMethodException, ClassNotFoundException { + return Class.forName("java.lang.Math").getDeclaredMethod("decrementExact", int.class); + } + + @Override Object execMathMethod() { return intR = Math.decrementExact(int1); } }, Negate { @Override + Executable testMethod() throws NoSuchMethodException, ClassNotFoundException { + return Class.forName("java.lang.Math").getDeclaredMethod("negateExact", int.class); + } + + @Override Object execMathMethod() { return intR = Math.negateExact(int1); } }; + protected int int1; protected int int2; protected int intR; + abstract Executable testMethod() throws NoSuchMethodException, ClassNotFoundException; abstract Object execMathMethod(); + public Executable getTestMethod() { + try { + return testMethod(); + } catch (NoSuchMethodException e) { + throw new RuntimeException("Test bug, no such method: " + e); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Test bug, no such class: " + e); + } + } + @Override public Executable getExecutable() { try { @@ -93,36 +135,66 @@ enum LongIntrinsic implements CompilerWhiteBoxTest.TestCase { Add { @Override + Executable testMethod() throws NoSuchMethodException, ClassNotFoundException { + return Class.forName("java.lang.Math").getDeclaredMethod("addExact", long.class, long.class); + } + + @Override Object execMathMethod() { return longR = Math.addExact(long1, long2); } }, Subtract { @Override + Executable testMethod() throws NoSuchMethodException, ClassNotFoundException { + return Class.forName("java.lang.Math").getDeclaredMethod("subtractExact", long.class, long.class); + } + + @Override Object execMathMethod() { return longR = Math.subtractExact(long1, long2); } }, Multiply { @Override + Executable testMethod() throws NoSuchMethodException, ClassNotFoundException { + return Class.forName("java.lang.Math").getDeclaredMethod("multiplyExact", long.class, long.class); + } + + @Override Object execMathMethod() { return longR = Math.multiplyExact(long1, long2); } }, Increment { @Override + Executable testMethod() throws NoSuchMethodException, ClassNotFoundException { + return Class.forName("java.lang.Math").getDeclaredMethod("incrementExact", long.class); + } + + @Override Object execMathMethod() { return longR = Math.incrementExact(long1); } }, Decrement { @Override + Executable testMethod() throws NoSuchMethodException, ClassNotFoundException { + return Class.forName("java.lang.Math").getDeclaredMethod("decrementExact", long.class); + } + + @Override Object execMathMethod() { return longR = Math.decrementExact(long1); } }, Negate { @Override + Executable testMethod() throws NoSuchMethodException, ClassNotFoundException { + return Class.forName("java.lang.Math").getDeclaredMethod("negateExact", long.class); + } + + @Override Object execMathMethod() { return longR = Math.negateExact(long1); } @@ -131,8 +203,19 @@ protected long long2; protected long longR; + abstract Executable testMethod() throws NoSuchMethodException, ClassNotFoundException; abstract Object execMathMethod(); + public Executable getTestMethod() { + try { + return testMethod(); + } catch (NoSuchMethodException e) { + throw new RuntimeException("Test bug, no such method: " + e); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Test bug, no such class: " + e); + } + } + @Override public Executable getExecutable() { try { diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/test/gc/g1/TestLargePageUseForAuxMemory.java --- a/hotspot/test/gc/g1/TestLargePageUseForAuxMemory.java Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/test/gc/g1/TestLargePageUseForAuxMemory.java Fri Jul 31 10:15:02 2015 -0700 @@ -94,29 +94,47 @@ output.shouldHaveExitValue(0); } + private static long gcd(long x, long y) { + while (x > 0) { + long t = x; + x = y % x; + y = t; + } + return y; + } + + private static long lcm(long x, long y) { + return x * (y / gcd(x, y)); + } + public static void main(String[] args) throws Exception { if (!Platform.isDebugBuild()) { System.out.println("Skip tests on non-debug builds because the required option TracePageSizes is a debug-only option."); return; } + // Size that a single card covers. + final int cardSize = 512; WhiteBox wb = WhiteBox.getWhiteBox(); smallPageSize = wb.getVMPageSize(); largePageSize = wb.getVMLargePageSize(); allocGranularity = wb.getVMAllocationGranularity(); + final long heapAlignment = lcm(cardSize * smallPageSize, largePageSize); if (largePageSize == 0) { System.out.println("Skip tests because large page support does not seem to be available on this platform."); return; } + if (largePageSize == smallPageSize) { + System.out.println("Skip tests because large page support does not seem to be available on this platform." + + "Small and large page size are the same."); + return; + } // To get large pages for the card table etc. we need at least a 1G heap (with 4k page size). // 32 bit systems will have problems reserving such an amount of contiguous space, so skip the // test there. if (!Platform.is32bit()) { - // Size that a single card covers. - final int cardSize = 512; - final long heapSizeForCardTableUsingLargePages = largePageSize * cardSize; final long heapSizeDiffForCardTable = Math.max(Math.max(allocGranularity * cardSize, HEAP_REGION_SIZE), largePageSize); @@ -131,7 +149,8 @@ // everywhere. final int bitmapTranslationFactor = 8 * 8; // ObjectAlignmentInBytes * BitsPerByte final long heapSizeForBitmapUsingLargePages = largePageSize * bitmapTranslationFactor; - final long heapSizeDiffForBitmap = Math.max(Math.max(allocGranularity * bitmapTranslationFactor, HEAP_REGION_SIZE), largePageSize); + final long heapSizeDiffForBitmap = Math.max(Math.max(allocGranularity * bitmapTranslationFactor, HEAP_REGION_SIZE), + Math.max(largePageSize, heapAlignment)); Asserts.assertGT(heapSizeForBitmapUsingLargePages, heapSizeDiffForBitmap, "To test we would require to use an invalid heap size"); diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/test/runtime/CompressedOops/ObjectAlignment.java --- a/hotspot/test/runtime/CompressedOops/ObjectAlignment.java Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/test/runtime/CompressedOops/ObjectAlignment.java Fri Jul 31 10:15:02 2015 -0700 @@ -48,7 +48,6 @@ .shouldHaveExitValue(1); testObjectAlignment(-1) - .shouldContain("must be power of 2") .shouldContain("outside the allowed range") .shouldHaveExitValue(1); @@ -75,4 +74,4 @@ "-version"); return new OutputAnalyzer(pb.start()); } -} \ No newline at end of file +} diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/test/runtime/ErrorHandling/CreateCoredumpOnCrash.java --- a/hotspot/test/runtime/ErrorHandling/CreateCoredumpOnCrash.java Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/test/runtime/ErrorHandling/CreateCoredumpOnCrash.java Fri Jul 31 10:15:02 2015 -0700 @@ -38,7 +38,7 @@ public class CreateCoredumpOnCrash { private static class Crasher { public static void main(String[] args) { - Utils.getUnsafe().getInt(0); + Utils.getUnsafe().putInt(0L, 0); } } diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/test/runtime/RedefineTests/RedefineRunningMethodsWithBacktrace.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/RedefineTests/RedefineRunningMethodsWithBacktrace.java Fri Jul 31 10:15:02 2015 -0700 @@ -0,0 +1,193 @@ +/* + * 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 8087315 + * @summary Get old method's stack trace elements after GC + * @library /testlibrary + * @modules java.compiler + * java.instrument + * jdk.jartool/sun.tools.jar + * @build RedefineClassHelper + * @run main RedefineClassHelper + * @run main/othervm -javaagent:redefineagent.jar RedefineRunningMethodsWithBacktrace + */ + +import static jdk.test.lib.Asserts.*; + +public class RedefineRunningMethodsWithBacktrace { + + public static String newB = + "class RedefineRunningMethodsWithBacktrace$B {" + + " static int count1 = 0;" + + " static int count2 = 0;" + + " public static volatile boolean stop = false;" + + " static void localSleep() { " + + " try{ " + + " Thread.currentThread().sleep(10);" + + " } catch(InterruptedException ie) { " + + " } " + + " } " + + " public static void infinite() { " + + " System.out.println(\"infinite called\");" + + " }" + + " public static void throwable() { " + + " throw new RuntimeException(\"throwable called\");" + + " }" + + "}"; + + public static String evenNewerB = + "class RedefineRunningMethodsWithBacktrace$B {" + + " static int count1 = 0;" + + " static int count2 = 0;" + + " public static volatile boolean stop = false;" + + " static void localSleep() { " + + " try{ " + + " Thread.currentThread().sleep(1);" + + " } catch(InterruptedException ie) { " + + " } " + + " } " + + " public static void infinite() { }" + + " public static void throwable() { " + + " throw new RuntimeException(\"throwable called\");" + + " }" + + "}"; + + static class B { + static int count1 = 0; + static int count2 = 0; + public static volatile boolean stop = false; + static void localSleep() { + try { + Thread.currentThread().sleep(10);//sleep for 10 ms + } catch(InterruptedException ie) { + } + } + + public static void infinite() { + while (!stop) { count1++; localSleep(); } + } + public static void throwable() { + // add some stuff to the original constant pool + String s1 = new String ("string1"); + String s2 = new String ("string2"); + String s3 = new String ("string3"); + String s4 = new String ("string4"); + String s5 = new String ("string5"); + String s6 = new String ("string6"); + String s7 = new String ("string7"); + String s8 = new String ("string8"); + String s9 = new String ("string9"); + String s10 = new String ("string10"); + String s11 = new String ("string11"); + String s12 = new String ("string12"); + String s13 = new String ("string13"); + String s14 = new String ("string14"); + String s15 = new String ("string15"); + String s16 = new String ("string16"); + String s17 = new String ("string17"); + String s18 = new String ("string18"); + String s19 = new String ("string19"); + throw new RuntimeException("throwable called"); + } + } + + private static void touchRedefinedMethodInBacktrace(Throwable throwable) { + System.out.println("touchRedefinedMethodInBacktrace: "); + throwable.printStackTrace(); // this actually crashes with the bug in + // java_lang_StackTraceElement::create() + + // Make sure that we can convert the backtrace, which is referring to + // the redefined method, to a StrackTraceElement[] without crashing. + StackTraceElement[] stackTrace = throwable.getStackTrace(); + for (int i = 0; i < stackTrace.length; i++) { + StackTraceElement frame = stackTrace[i]; + assertNotNull(frame.getClassName(), + "\nTest failed: trace[" + i + "].getClassName() returned null"); + assertNotNull(frame.getMethodName(), + "\nTest failed: trace[" + i + "].getMethodName() returned null"); + } + } + + private static Throwable getThrowableInB() { + Throwable t = null; + try { + B.throwable(); + } catch (Exception e) { + t = e; + // Don't print here because Throwable will cache the constructed stacktrace + // e.printStackTrace(); + } + return t; + } + + + public static void main(String[] args) throws Exception { + + new Thread() { + public void run() { + B.infinite(); + } + }.start(); + + Throwable t1 = getThrowableInB(); + + RedefineClassHelper.redefineClass(B.class, newB); + + System.gc(); + + Throwable t2 = getThrowableInB(); + + B.infinite(); + + for (int i = 0; i < 20 ; i++) { + String s = new String("some garbage"); + System.gc(); + } + + RedefineClassHelper.redefineClass(B.class, evenNewerB); + System.gc(); + + Throwable t3 = getThrowableInB(); + + for (int i = 0; i < 20 ; i++) { + B.infinite(); + String s = new String("some garbage"); + System.gc(); + } + + touchRedefinedMethodInBacktrace(t1); + touchRedefinedMethodInBacktrace(t2); + touchRedefinedMethodInBacktrace(t3); + + // purge should clean everything up. + B.stop = true; + + for (int i = 0; i < 20 ; i++) { + B.infinite(); + String s = new String("some garbage"); + System.gc(); + } + } +} diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/test/runtime/contended/Options.java --- a/hotspot/test/runtime/contended/Options.java Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/test/runtime/contended/Options.java Fri Jul 31 10:15:02 2015 -0700 @@ -55,7 +55,6 @@ output = new OutputAnalyzer(pb.start()); output.shouldContain("ContendedPaddingWidth"); output.shouldContain("outside the allowed range"); - output.shouldContain("must be a multiple of 8"); output.shouldHaveExitValue(1); pb = ProcessTools.createJavaProcessBuilder("-XX:ContendedPaddingWidth=0", "-version"); @@ -90,7 +89,6 @@ output = new OutputAnalyzer(pb.start()); output.shouldContain("ContendedPaddingWidth"); output.shouldContain("outside the allowed range"); - output.shouldContain("must be a multiple of 8"); output.shouldHaveExitValue(1); pb = ProcessTools.createJavaProcessBuilder("-XX:ContendedPaddingWidth=8200", "-version"); // 8192+8 = 8200 diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/test/runtime/verifier/PrimIntArray.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/verifier/PrimIntArray.java Fri Jul 31 10:15:02 2015 -0700 @@ -0,0 +1,55 @@ +/* + * 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 8129895 + * @summary Throw VerifyError when checking assignability of primitive arrays + * that are not identical. For example, [I is not assignable to [B. + * @compile primArray.jasm + * @compile primArray49.jasm + * @run main/othervm -Xverify:all PrimIntArray + */ + +// Test that an int[] is not assignable to byte[]. +public class PrimIntArray { + + public static void main(String args[]) throws Throwable { + System.out.println("Regression test for bug 8129895"); + + try { + Class newClass = Class.forName("primArray"); + throw new RuntimeException("Expected VerifyError exception not thrown with new verifier"); + } catch (java.lang.VerifyError e) { + System.out.println("Test PrimIntArray passed with new verifier"); + } + + try { + Class newClass = Class.forName("primArray49"); + throw new RuntimeException("Expected VerifyError exception not thrown by old verifier"); + } catch (java.lang.VerifyError e) { + System.out.println("Test PrimIntArray passed with old verifier"); + } + } +} diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/test/runtime/verifier/primArray.jasm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/verifier/primArray.jasm Fri Jul 31 10:15:02 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. + * + */ + +// Method castToByteArray() tries to return an array of ints when an array +// of bytes is expected. +super class primArray +version 52:0 +{ + + public Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + public static Method castToByteArray:"([I)[B" + stack 1 locals 1 + { + aload_0; + areturn; + } + +} // end Class primArray diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/test/runtime/verifier/primArray49.jasm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/verifier/primArray49.jasm Fri Jul 31 10:15:02 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. + * + */ + +// Method castToByteArray() tries to return an array of ints when an array +// of bytes is expected. +super class primArray49 +version 49:0 +{ + + public Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + public static Method castToByteArray:"([I)[B" + stack 1 locals 1 + { + aload_0; + areturn; + } + +} // end Class primArray49 diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/test/serviceability/sa/TestStackTrace.java --- a/hotspot/test/serviceability/sa/TestStackTrace.java Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/test/serviceability/sa/TestStackTrace.java Fri Jul 31 10:15:02 2015 -0700 @@ -34,7 +34,6 @@ * @test * @library /../../test/lib/share/classes * @library /testlibrary - * @ignore 8129971 * @build jdk.test.lib.* * @build jdk.test.lib.apps.* * @run main TestStackTrace diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/test/testlibrary/jdk/test/lib/InMemoryJavaCompiler.java --- a/hotspot/test/testlibrary/jdk/test/lib/InMemoryJavaCompiler.java Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/test/testlibrary/jdk/test/lib/InMemoryJavaCompiler.java Fri Jul 31 10:15:02 2015 -0700 @@ -31,11 +31,9 @@ import java.util.Arrays; import javax.tools.ForwardingJavaFileManager; -import javax.tools.ForwardingJavaFileManager; import javax.tools.FileObject; import javax.tools.JavaCompiler; import javax.tools.JavaCompiler.CompilationTask; -import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import javax.tools.JavaFileObject.Kind; import javax.tools.SimpleJavaFileObject; diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/test/testlibrary/jdk/test/lib/Platform.java --- a/hotspot/test/testlibrary/jdk/test/lib/Platform.java Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/test/testlibrary/jdk/test/lib/Platform.java Fri Jul 31 10:15:02 2015 -0700 @@ -24,7 +24,6 @@ package jdk.test.lib; import java.util.regex.Pattern; -import jdk.test.lib.Utils; public class Platform { private static final String osName = System.getProperty("os.name"); diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/test/testlibrary/jdk/test/lib/ProcessTools.java --- a/hotspot/test/testlibrary/jdk/test/lib/ProcessTools.java Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/test/testlibrary/jdk/test/lib/ProcessTools.java Fri Jul 31 10:15:02 2015 -0700 @@ -27,8 +27,6 @@ import java.io.IOException; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.List; diff -r eeea9adfd1e3 -r a9f423dbab9e hotspot/test/testlibrary/jdk/test/lib/Utils.java --- a/hotspot/test/testlibrary/jdk/test/lib/Utils.java Wed Jul 05 20:44:11 2017 +0200 +++ b/hotspot/test/testlibrary/jdk/test/lib/Utils.java Fri Jul 31 10:15:02 2015 -0700 @@ -24,9 +24,6 @@ package jdk.test.lib; import static jdk.test.lib.Asserts.assertTrue; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; import java.io.IOException; import java.lang.reflect.Field; import java.net.InetAddress; @@ -58,12 +55,12 @@ public static final String NEW_LINE = System.getProperty("line.separator"); /** - * Returns the value of 'test.vm.opts'system property. + * Returns the value of 'test.vm.opts' system property. */ public static final String VM_OPTIONS = System.getProperty("test.vm.opts", "").trim(); /** - * Returns the value of 'test.java.opts'system property. + * Returns the value of 'test.java.opts' system property. */ public static final String JAVA_OPTIONS = System.getProperty("test.java.opts", "").trim(); @@ -129,7 +126,7 @@ /** * Returns the default JTReg arguments for a jvm running a test. * This is the combination of JTReg arguments test.vm.opts and test.java.opts. - * @return An array of options, or an empty array if no opptions. + * @return An array of options, or an empty array if no options. */ public static String[] getTestJavaOpts() { List opts = new ArrayList(); @@ -276,7 +273,7 @@ * 12254 /tmp/jdk8/tl/jdk/JTwork/classes/com/sun/tools/attach/Application.jar * * @param key A regular expression to search for. - * @return The found pid, or -1 if Enot found. + * @return The found pid, or -1 if not found. * @throws Exception If multiple matching jvms are found. */ public static int tryFindJvmPid(String key) throws Throwable { @@ -392,7 +389,7 @@ * @param condition, a condition to wait for * @param timeout a time in milliseconds to wait for condition to be true * specifying -1 will wait forever - * @return condition value, to determine if wait was successfull + * @return condition value, to determine if wait was successful */ public static final boolean waitForCondition(BooleanSupplier condition, long timeout) { @@ -406,7 +403,7 @@ * @param timeout a time in milliseconds to wait for condition to be true, * specifying -1 will wait forever * @param sleepTime a time to sleep value in milliseconds - * @return condition value, to determine if wait was successfull + * @return condition value, to determine if wait was successful */ public static final boolean waitForCondition(BooleanSupplier condition, long timeout, long sleepTime) {