# HG changeset patch # User chegar # Date 1383465024 0 # Node ID c31f0cbe6d9e22a0e6f27c7557d3471500ff777e # Parent 6795fcebbf421944dd30a90b067199d3b77c41c1# Parent ddc3758f68db3b1063b34beecd67bff1d2ad50a9 Merge diff -r 6795fcebbf42 -r c31f0cbe6d9e .hgtags --- a/.hgtags Mon Oct 21 14:08:09 2013 +0100 +++ b/.hgtags Sun Nov 03 07:50:24 2013 +0000 @@ -386,3 +386,7 @@ f6962730bbde82f279a0ae3a1c14bc5e58096c6e jdk8-b111 4a845c7a463844cead9e1e1641d6bcfb8a77f1c7 hs25-b54 0ed9a90f45e1b392c671005f9ee22ce1acf02984 jdk8-b112 +23b8db5ea31d3079f1326afde4cd5c67b1dac49c hs25-b55 +4589b398ab03aba6a5da8c06ff53603488d1b8f4 jdk8-b113 +82a9cdbf683e374a76f2009352de53e16bed5a91 hs25-b56 +7fd913010dbbf75260688fd2fa8964763fa49a09 jdk8-b114 diff -r 6795fcebbf42 -r c31f0cbe6d9e agent/src/os/linux/ps_core.c --- a/agent/src/os/linux/ps_core.c Mon Oct 21 14:08:09 2013 +0100 +++ b/agent/src/os/linux/ps_core.c Sun Nov 03 07:50:24 2013 +0000 @@ -719,7 +719,7 @@ ELF_PHDR* phbuf; ELF_PHDR* lib_php = NULL; - int page_size=sysconf(_SC_PAGE_SIZE); + int page_size = sysconf(_SC_PAGE_SIZE); if ((phbuf = read_program_header_table(lib_fd, lib_ehdr)) == NULL) { return false; @@ -736,26 +736,29 @@ if (existing_map == NULL){ if (add_map_info(ph, lib_fd, lib_php->p_offset, - target_vaddr, lib_php->p_filesz) == NULL) { + target_vaddr, lib_php->p_memsz) == NULL) { goto err; } } else { + // Coredump stores value of p_memsz elf field + // rounded up to page boundary. + if ((existing_map->memsz != page_size) && (existing_map->fd != lib_fd) && - (existing_map->memsz != lib_php->p_filesz)){ + (ROUNDUP(existing_map->memsz, page_size) != ROUNDUP(lib_php->p_memsz, page_size))) { - print_debug("address conflict @ 0x%lx (size = %ld, flags = %d\n)", - target_vaddr, lib_php->p_filesz, lib_php->p_flags); + print_debug("address conflict @ 0x%lx (existing map size = %ld, size = %ld, flags = %d)\n", + target_vaddr, existing_map->memsz, lib_php->p_memsz, lib_php->p_flags); goto err; } /* replace PT_LOAD segment with library segment */ print_debug("overwrote with new address mapping (memsz %ld -> %ld)\n", - existing_map->memsz, lib_php->p_filesz); + existing_map->memsz, ROUNDUP(lib_php->p_memsz, page_size)); existing_map->fd = lib_fd; existing_map->offset = lib_php->p_offset; - existing_map->memsz = lib_php->p_filesz; + existing_map->memsz = ROUNDUP(lib_php->p_memsz, page_size); } } diff -r 6795fcebbf42 -r c31f0cbe6d9e agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1HeapRegionTable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1HeapRegionTable.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2013, 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.gc_implementation.g1; + +import java.util.Iterator; +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.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; + +// Mirror class for G1HeapRegionTable. It's essentially an index -> HeapRegion map. + +public class G1HeapRegionTable extends VMObject { + // HeapRegion** _base; + static private AddressField baseField; + // uint _length; + static private CIntegerField lengthField; + // HeapRegion** _biased_base + static private AddressField biasedBaseField; + // size_t _bias + static private CIntegerField biasField; + // uint _shift_by + static private CIntegerField shiftByField; + + 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("G1HeapRegionTable"); + + baseField = type.getAddressField("_base"); + lengthField = type.getCIntegerField("_length"); + biasedBaseField = type.getAddressField("_biased_base"); + biasField = type.getCIntegerField("_bias"); + shiftByField = type.getCIntegerField("_shift_by"); + } + + private HeapRegion at(long index) { + Address arrayAddr = baseField.getValue(addr); + // Offset of &_base[index] + long offset = index * VM.getVM().getAddressSize(); + Address regionAddr = arrayAddr.getAddressAt(offset); + return (HeapRegion) VMObjectFactory.newObject(HeapRegion.class, + regionAddr); + } + + public long length() { + return lengthField.getValue(addr); + } + + public long bias() { + return biasField.getValue(addr); + } + + public long shiftBy() { + return shiftByField.getValue(addr); + } + + private class HeapRegionIterator implements Iterator { + private long index; + private long length; + + @Override + public boolean hasNext() { return index < length; } + + @Override + public HeapRegion next() { return at(index++); } + + @Override + public void remove() { /* not supported */ } + + HeapRegionIterator(Address addr) { + index = 0; + length = length(); + } + } + + public Iterator heapRegionIterator() { + return new HeapRegionIterator(addr); + } + + public G1HeapRegionTable(Address addr) { + super(addr); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSeq.java --- a/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSeq.java Mon Oct 21 14:08:09 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSeq.java Sun Nov 03 07:50:24 2013 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, 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 @@ -37,13 +37,11 @@ import sun.jvm.hotspot.types.Type; import sun.jvm.hotspot.types.TypeDataBase; -// Mirror class for HeapRegionSeq. It's essentially an index -> HeapRegion map. +// Mirror class for HeapRegionSeq. It essentially encapsulates the G1HeapRegionTable. public class HeapRegionSeq extends VMObject { - // HeapRegion** _regions; - static private AddressField regionsField; - // uint _length; - static private CIntegerField lengthField; + // G1HeapRegionTable _regions + static private long regionsFieldOffset; static { VM.registerVMInitializedObserver(new Observer() { @@ -56,44 +54,21 @@ static private synchronized void initialize(TypeDataBase db) { Type type = db.lookupType("HeapRegionSeq"); - regionsField = type.getAddressField("_regions"); - lengthField = type.getCIntegerField("_length"); + regionsFieldOffset = type.getField("_regions").getOffset(); } - private HeapRegion at(long index) { - Address arrayAddr = regionsField.getValue(addr); - // Offset of &_region[index] - long offset = index * VM.getVM().getAddressSize(); - Address regionAddr = arrayAddr.getAddressAt(offset); - return (HeapRegion) VMObjectFactory.newObject(HeapRegion.class, - regionAddr); + private G1HeapRegionTable regions() { + Address regionsAddr = addr.addOffsetTo(regionsFieldOffset); + return (G1HeapRegionTable) VMObjectFactory.newObject(G1HeapRegionTable.class, + regionsAddr); } public long length() { - return lengthField.getValue(addr); - } - - private class HeapRegionIterator implements Iterator { - private long index; - private long length; - - @Override - public boolean hasNext() { return index < length; } - - @Override - public HeapRegion next() { return at(index++); } - - @Override - public void remove() { /* not supported */ } - - HeapRegionIterator(Address addr) { - index = 0; - length = length(); - } + return regions().length(); } public Iterator heapRegionIterator() { - return new HeapRegionIterator(addr); + return regions().heapRegionIterator(); } public HeapRegionSeq(Address addr) { diff -r 6795fcebbf42 -r c31f0cbe6d9e agent/src/share/classes/sun/jvm/hotspot/oops/ConstMethod.java --- a/agent/src/share/classes/sun/jvm/hotspot/oops/ConstMethod.java Mon Oct 21 14:08:09 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/ConstMethod.java Sun Nov 03 07:50:24 2013 +0000 @@ -51,6 +51,7 @@ private static int HAS_GENERIC_SIGNATURE; private static int HAS_METHOD_ANNOTATIONS; private static int HAS_PARAMETER_ANNOTATIONS; + private static int HAS_METHOD_PARAMETERS; private static int HAS_DEFAULT_ANNOTATIONS; private static int HAS_TYPE_ANNOTATIONS; @@ -70,6 +71,7 @@ HAS_GENERIC_SIGNATURE = db.lookupIntConstant("ConstMethod::_has_generic_signature").intValue(); HAS_METHOD_ANNOTATIONS = db.lookupIntConstant("ConstMethod::_has_method_annotations").intValue(); HAS_PARAMETER_ANNOTATIONS = db.lookupIntConstant("ConstMethod::_has_parameter_annotations").intValue(); + HAS_METHOD_PARAMETERS = db.lookupIntConstant("ConstMethod::_has_method_parameters").intValue(); HAS_DEFAULT_ANNOTATIONS = db.lookupIntConstant("ConstMethod::_has_default_annotations").intValue(); HAS_TYPE_ANNOTATIONS = db.lookupIntConstant("ConstMethod::_has_type_annotations").intValue(); @@ -85,6 +87,9 @@ // start of byte code bytecodeOffset = type.getSize(); + type = db.lookupType("MethodParametersElement"); + methodParametersElementSize = type.getSize(); + type = db.lookupType("CheckedExceptionElement"); checkedExceptionElementSize = type.getSize(); @@ -113,7 +118,7 @@ // start of bytecode private static long bytecodeOffset; - + private static long methodParametersElementSize; private static long checkedExceptionElementSize; private static long localVariableTableElementSize; private static long exceptionTableElementSize; @@ -387,6 +392,10 @@ return ret; } + private boolean hasMethodParameters() { + return (getFlags() & HAS_METHOD_PARAMETERS) != 0; + } + private boolean hasGenericSignature() { return (getFlags() & HAS_GENERIC_SIGNATURE) != 0; } @@ -442,11 +451,41 @@ return offsetOfLastU2Element(); } - private long offsetOfCheckedExceptionsLength() { + private long offsetOfMethodParametersLength() { + if (Assert.ASSERTS_ENABLED) { + Assert.that(hasMethodParameters(), "should only be called if table is present"); + } return hasGenericSignature() ? offsetOfLastU2Element() - sizeofShort : offsetOfLastU2Element(); } + private int getMethodParametersLength() { + if (hasMethodParameters()) + return (int) getAddress().getCIntegerAt(offsetOfMethodParametersLength(), 2, true); + else + return 0; + } + + // Offset of start of checked exceptions + private long offsetOfMethodParameters() { + long offset = offsetOfMethodParametersLength(); + long length = getMethodParametersLength(); + if (Assert.ASSERTS_ENABLED) { + Assert.that(length > 0, "should only be called if method parameter information is present"); + } + offset -= length * methodParametersElementSize; + return offset; + } + + private long offsetOfCheckedExceptionsLength() { + if (hasMethodParameters()) + return offsetOfMethodParameters() - sizeofShort; + else { + return hasGenericSignature() ? offsetOfLastU2Element() - sizeofShort : + offsetOfLastU2Element(); + } + } + private int getCheckedExceptionsLength() { if (hasCheckedExceptions()) { return (int) getAddress().getCIntegerAt(offsetOfCheckedExceptionsLength(), 2, true); @@ -496,6 +535,8 @@ return offsetOfExceptionTable() - sizeofShort; } else if (hasCheckedExceptions()) { return offsetOfCheckedExceptions() - sizeofShort; + } else if (hasMethodParameters()) { + return offsetOfMethodParameters() - sizeofShort; } else { return hasGenericSignature() ? offsetOfLastU2Element() - sizeofShort : offsetOfLastU2Element(); @@ -526,6 +567,8 @@ } if (hasCheckedExceptions()) { return offsetOfCheckedExceptions() - sizeofShort; + } else if (hasMethodParameters()) { + return offsetOfMethodParameters() - sizeofShort; } else { return hasGenericSignature() ? offsetOfLastU2Element() - sizeofShort : offsetOfLastU2Element(); diff -r 6795fcebbf42 -r c31f0cbe6d9e agent/src/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java Mon Oct 21 14:08:09 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java Sun Nov 03 07:50:24 2013 +0000 @@ -51,8 +51,7 @@ public static void main(String[] args) { ClassLoaderStats cls = new ClassLoaderStats(); - cls.start(args); - cls.stop(); + cls.execute(args); } private static class ClassData { diff -r 6795fcebbf42 -r c31f0cbe6d9e agent/src/share/classes/sun/jvm/hotspot/tools/FinalizerInfo.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/FinalizerInfo.java Mon Oct 21 14:08:09 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/FinalizerInfo.java Sun Nov 03 07:50:24 2013 +0000 @@ -54,8 +54,7 @@ public static void main(String[] args) { FinalizerInfo finfo = new FinalizerInfo(); - finfo.start(args); - finfo.stop(); + finfo.execute(args); } public void run() { diff -r 6795fcebbf42 -r c31f0cbe6d9e agent/src/share/classes/sun/jvm/hotspot/tools/FlagDumper.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/FlagDumper.java Mon Oct 21 14:08:09 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/FlagDumper.java Sun Nov 03 07:50:24 2013 +0000 @@ -54,7 +54,6 @@ public static void main(String[] args) { FlagDumper fd = new FlagDumper(); - fd.start(args); - fd.stop(); + fd.execute(args); } } diff -r 6795fcebbf42 -r c31f0cbe6d9e agent/src/share/classes/sun/jvm/hotspot/tools/HeapDumper.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/HeapDumper.java Mon Oct 21 14:08:09 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/HeapDumper.java Sun Nov 03 07:50:24 2013 +0000 @@ -80,8 +80,7 @@ } HeapDumper dumper = new HeapDumper(file); - dumper.start(args); - dumper.stop(); + dumper.execute(args); } } diff -r 6795fcebbf42 -r c31f0cbe6d9e agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java Mon Oct 21 14:08:09 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java Sun Nov 03 07:50:24 2013 +0000 @@ -46,8 +46,7 @@ public static void main(String[] args) { HeapSummary hs = new HeapSummary(); - hs.start(args); - hs.stop(); + hs.execute(args); } public void run() { diff -r 6795fcebbf42 -r c31f0cbe6d9e agent/src/share/classes/sun/jvm/hotspot/tools/JInfo.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/JInfo.java Mon Oct 21 14:08:09 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/JInfo.java Sun Nov 03 07:50:24 2013 +0000 @@ -134,8 +134,7 @@ } JInfo jinfo = new JInfo(mode); - jinfo.start(args); - jinfo.stop(); + jinfo.execute(args); } private void printVMFlags() { diff -r 6795fcebbf42 -r c31f0cbe6d9e agent/src/share/classes/sun/jvm/hotspot/tools/JMap.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/JMap.java Mon Oct 21 14:08:09 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/JMap.java Sun Nov 03 07:50:24 2013 +0000 @@ -136,7 +136,9 @@ mode = MODE_HEAP_GRAPH_GXL; } else { System.err.println("unknown heap format:" + format); - return; + + // Exit with error status + System.exit(1); } } else { copyArgs = false; @@ -153,8 +155,7 @@ } JMap jmap = new JMap(mode); - jmap.start(args); - jmap.stop(); + jmap.execute(args); } public boolean writeHeapHprofBin(String fileName) { diff -r 6795fcebbf42 -r c31f0cbe6d9e agent/src/share/classes/sun/jvm/hotspot/tools/JSnap.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/JSnap.java Mon Oct 21 14:08:09 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/JSnap.java Sun Nov 03 07:50:24 2013 +0000 @@ -64,7 +64,6 @@ public static void main(String[] args) { JSnap js = new JSnap(); - js.start(args); - js.stop(); + js.execute(args); } } diff -r 6795fcebbf42 -r c31f0cbe6d9e agent/src/share/classes/sun/jvm/hotspot/tools/JStack.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/JStack.java Mon Oct 21 14:08:09 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/JStack.java Sun Nov 03 07:50:24 2013 +0000 @@ -89,8 +89,7 @@ } JStack jstack = new JStack(mixedMode, concurrentLocks); - jstack.start(args); - jstack.stop(); + jstack.execute(args); } private boolean mixedMode; diff -r 6795fcebbf42 -r c31f0cbe6d9e agent/src/share/classes/sun/jvm/hotspot/tools/ObjectHistogram.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/ObjectHistogram.java Mon Oct 21 14:08:09 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/ObjectHistogram.java Sun Nov 03 07:50:24 2013 +0000 @@ -61,7 +61,6 @@ public static void main(String[] args) { ObjectHistogram oh = new ObjectHistogram(); - oh.start(args); - oh.stop(); + oh.execute(args); } } diff -r 6795fcebbf42 -r c31f0cbe6d9e agent/src/share/classes/sun/jvm/hotspot/tools/PMap.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/PMap.java Mon Oct 21 14:08:09 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/PMap.java Sun Nov 03 07:50:24 2013 +0000 @@ -69,7 +69,6 @@ public static void main(String[] args) throws Exception { PMap t = new PMap(); - t.start(args); - t.stop(); + t.execute(args); } } diff -r 6795fcebbf42 -r c31f0cbe6d9e agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java Mon Oct 21 14:08:09 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java Sun Nov 03 07:50:24 2013 +0000 @@ -182,8 +182,7 @@ public static void main(String[] args) throws Exception { PStack t = new PStack(); - t.start(args); - t.stop(); + t.execute(args); } // -- Internals only below this point diff -r 6795fcebbf42 -r c31f0cbe6d9e agent/src/share/classes/sun/jvm/hotspot/tools/StackTrace.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/StackTrace.java Mon Oct 21 14:08:09 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/StackTrace.java Sun Nov 03 07:50:24 2013 +0000 @@ -137,8 +137,7 @@ public static void main(String[] args) { StackTrace st = new StackTrace(); - st.start(args); - st.stop(); + st.execute(args); } private boolean verbose; diff -r 6795fcebbf42 -r c31f0cbe6d9e agent/src/share/classes/sun/jvm/hotspot/tools/SysPropsDumper.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/SysPropsDumper.java Mon Oct 21 14:08:09 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/SysPropsDumper.java Sun Nov 03 07:50:24 2013 +0000 @@ -58,7 +58,6 @@ public static void main(String[] args) { SysPropsDumper pd = new SysPropsDumper(); - pd.start(args); - pd.stop(); + pd.execute(args); } } diff -r 6795fcebbf42 -r c31f0cbe6d9e agent/src/share/classes/sun/jvm/hotspot/tools/Tool.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/Tool.java Mon Oct 21 14:08:09 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/Tool.java Sun Nov 03 07:50:24 2013 +0000 @@ -26,6 +26,7 @@ import java.io.PrintStream; import java.util.Hashtable; + import sun.jvm.hotspot.*; import sun.jvm.hotspot.runtime.*; import sun.jvm.hotspot.debugger.*; @@ -105,26 +106,44 @@ public static void main(String[] args) { obj = new ; - obj.start(args); + obj.execute(args); } */ - protected void stop() { + protected void execute(String[] args) { + int returnStatus = 1; + + try { + returnStatus = start(args); + } finally { + stop(); + } + + // Exit with 0 or 1 + System.exit(returnStatus); + } + + public void stop() { if (agent != null) { agent.detach(); } } - protected void start(String[] args) { + private int start(String[] args) { + if ((args.length < 1) || (args.length > 2)) { usage(); - return; + return 1; } // Attempt to handle -h or -help or some invalid flag - if (args[0].startsWith("-")) { + if (args[0].startsWith("-h")) { usage(); + return 0; + } else if (args[0].startsWith("-")) { + usage(); + return 1; } PrintStream err = System.err; @@ -154,6 +173,7 @@ default: usage(); + return 1; } agent = new HotSpotAgent(); @@ -191,15 +211,16 @@ break; } if (e.getMessage() != null) { - err.print(e.getMessage()); + err.println(e.getMessage()); e.printStackTrace(); } err.println(); - return; + return 1; } err.println("Debugger attached successfully."); startInternal(); + return 0; } // When using an existing JVMDebugger. diff -r 6795fcebbf42 -r c31f0cbe6d9e agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassDump.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassDump.java Mon Oct 21 14:08:09 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassDump.java Sun Nov 03 07:50:24 2013 +0000 @@ -177,7 +177,6 @@ public static void main(String[] args) { ClassDump cd = new ClassDump(); - cd.start(args); - cd.stop(); + cd.execute(args); } } diff -r 6795fcebbf42 -r c31f0cbe6d9e agent/src/share/classes/sun/jvm/hotspot/tools/soql/JSDB.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/soql/JSDB.java Mon Oct 21 14:08:09 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/soql/JSDB.java Sun Nov 03 07:50:24 2013 +0000 @@ -42,8 +42,7 @@ public static void main(String[] args) { JSDB jsdb = new JSDB(); - jsdb.start(args); - jsdb.stop(); + jsdb.execute(args); } public void run() { diff -r 6795fcebbf42 -r c31f0cbe6d9e agent/src/share/classes/sun/jvm/hotspot/tools/soql/SOQL.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/soql/SOQL.java Mon Oct 21 14:08:09 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/soql/SOQL.java Sun Nov 03 07:50:24 2013 +0000 @@ -40,8 +40,7 @@ public class SOQL extends Tool { public static void main(String[] args) { SOQL soql = new SOQL(); - soql.start(args); - soql.stop(); + soql.execute(args); } public SOQL() { diff -r 6795fcebbf42 -r c31f0cbe6d9e make/Makefile --- a/make/Makefile Mon Oct 21 14:08:09 2013 +0100 +++ b/make/Makefile Sun Nov 03 07:50:24 2013 +0000 @@ -334,6 +334,11 @@ $(install-file) $(EXPORT_SERVER_DIR)/64/%.diz: $(C2_BUILD_DIR)/%.diz $(install-file) +# MacOS X +$(EXPORT_JRE_LIB_ARCH_DIR)/%.dSYM: $(C2_BUILD_DIR)/%.dSYM + $(install-dir) +$(EXPORT_SERVER_DIR)/%.dSYM: $(C2_BUILD_DIR)/%.dSYM + $(install-dir) endif # Client (C1) @@ -379,6 +384,11 @@ $(install-file) $(EXPORT_CLIENT_DIR)/64/%.diz: $(C1_BUILD_DIR)/%.diz $(install-file) +# MacOS X +$(EXPORT_JRE_LIB_ARCH_DIR)/%.dSYM: $(C1_BUILD_DIR)/%.dSYM + $(install-dir) +$(EXPORT_CLIENT_DIR)/%.dSYM: $(C1_BUILD_DIR)/%.dSYM + $(install-dir) endif # Minimal1 @@ -424,6 +434,7 @@ $(install-file) $(EXPORT_MINIMAL_DIR)/64/%.diz: $(MINIMAL1_BUILD_DIR)/%.diz $(install-file) +# MacOS X does not support Minimal1 config endif # Zero @@ -446,6 +457,11 @@ $(install-file) $(EXPORT_SERVER_DIR)/%.diz: $(ZERO_BUILD_DIR)/%.diz $(install-file) +# MacOS X +$(EXPORT_JRE_LIB_ARCH_DIR)/%.dSYM: $(ZERO_BUILD_DIR)/%.dSYM + $(install-dir) +$(EXPORT_SERVER_DIR)/%.dSYM: $(ZERO_BUILD_DIR)/%.dSYM + $(install-dir) endif # Shark @@ -468,6 +484,11 @@ $(install-file) $(EXPORT_SERVER_DIR)/%.diz: $(SHARK_BUILD_DIR)/%.diz $(install-file) +# MacOS X +$(EXPORT_JRE_LIB_ARCH_DIR)/%.dSYM: $(SHARK_BUILD_DIR)/%.dSYM + $(install-dir) +$(EXPORT_SERVER_DIR)/%.dSYM: $(SHARK_BUILD_DIR)/%.dSYM + $(install-dir) endif $(EXPORT_INCLUDE_DIR)/%: $(HS_SRC_DIR)/share/vm/code/% diff -r 6795fcebbf42 -r c31f0cbe6d9e make/bsd/Makefile --- a/make/bsd/Makefile Mon Oct 21 14:08:09 2013 +0100 +++ b/make/bsd/Makefile Sun Nov 03 07:50:24 2013 +0000 @@ -204,6 +204,7 @@ BUILDTREE_MAKE = $(GAMMADIR)/make/$(OSNAME)/makefiles/buildtree.make BUILDTREE_VARS = GAMMADIR=$(GAMMADIR) OS_FAMILY=$(OSNAME) SRCARCH=$(SRCARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH) LIBRARY_SUFFIX=$(LIBRARY_SUFFIX) BUILDTREE_VARS += HOTSPOT_RELEASE_VERSION=$(HOTSPOT_RELEASE_VERSION) HOTSPOT_BUILD_VERSION=$(HOTSPOT_BUILD_VERSION) JRE_RELEASE_VERSION=$(JRE_RELEASE_VERSION) +BUILDTREE_VARS += ENABLE_FULL_DEBUG_SYMBOLS=$(ENABLE_FULL_DEBUG_SYMBOLS) OBJCOPY=$(OBJCOPY) STRIP_POLICY=$(STRIP_POLICY) ZIP_DEBUGINFO_FILES=$(ZIP_DEBUGINFO_FILES) ZIPEXE=$(ZIPEXE) BUILDTREE = $(MAKE) -f $(BUILDTREE_MAKE) $(BUILDTREE_VARS) @@ -337,9 +338,11 @@ # Doc target. This is the same for all build options. # Hence create a docs directory beside ...$(ARCH)_[...] +# We specify 'BUILD_FLAVOR=product' so that the proper +# ENABLE_FULL_DEBUG_SYMBOLS value is used. docs: checks $(QUIETLY) mkdir -p $(SUBDIR_DOCS) - $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/makefiles/jvmti.make $(MFLAGS) $(BUILDTREE_VARS) JvmtiOutDir=$(SUBDIR_DOCS) jvmtidocs + $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/makefiles/jvmti.make $(MFLAGS) $(BUILDTREE_VARS) JvmtiOutDir=$(SUBDIR_DOCS) BUILD_FLAVOR=product jvmtidocs # Synonyms for win32-like targets. compiler2: debug product diff -r 6795fcebbf42 -r c31f0cbe6d9e make/bsd/makefiles/buildtree.make --- a/make/bsd/makefiles/buildtree.make Mon Oct 21 14:08:09 2013 +0100 +++ b/make/bsd/makefiles/buildtree.make Sun Nov 03 07:50:24 2013 +0000 @@ -261,6 +261,16 @@ echo "$(call gamma-path,commonsrc,os/posix/vm)"; \ [ -n "$(CFLAGS_BROWSE)" ] && \ echo && echo "CFLAGS_BROWSE = $(CFLAGS_BROWSE)"; \ + [ -n "$(ENABLE_FULL_DEBUG_SYMBOLS)" ] && \ + echo && echo "ENABLE_FULL_DEBUG_SYMBOLS = $(ENABLE_FULL_DEBUG_SYMBOLS)"; \ + [ -n "$(OBJCOPY)" ] && \ + echo && echo "OBJCOPY = $(OBJCOPY)"; \ + [ -n "$(STRIP_POLICY)" ] && \ + echo && echo "STRIP_POLICY = $(STRIP_POLICY)"; \ + [ -n "$(ZIP_DEBUGINFO_FILES)" ] && \ + echo && echo "ZIP_DEBUGINFO_FILES = $(ZIP_DEBUGINFO_FILES)"; \ + [ -n "$(ZIPEXE)" ] && \ + echo && echo "ZIPEXE = $(ZIPEXE)"; \ [ -n "$(HOTSPOT_EXTRA_SYSDEFS)" ] && \ echo && \ echo "HOTSPOT_EXTRA_SYSDEFS\$$(HOTSPOT_EXTRA_SYSDEFS) = $(HOTSPOT_EXTRA_SYSDEFS)" && \ diff -r 6795fcebbf42 -r c31f0cbe6d9e make/bsd/makefiles/defs.make --- a/make/bsd/makefiles/defs.make Mon Oct 21 14:08:09 2013 +0100 +++ b/make/bsd/makefiles/defs.make Sun Nov 03 07:50:24 2013 +0000 @@ -136,10 +136,127 @@ endif endif +OS_VENDOR:=$(shell uname -s) + +# determine if HotSpot is being built in JDK6 or earlier version +JDK6_OR_EARLIER=0 +ifeq "$(shell expr \( '$(JDK_MAJOR_VERSION)' != '' \& '$(JDK_MINOR_VERSION)' != '' \& '$(JDK_MICRO_VERSION)' != '' \))" "1" + # if the longer variable names (newer build style) are set, then check those + ifeq "$(shell expr \( $(JDK_MAJOR_VERSION) = 1 \& $(JDK_MINOR_VERSION) \< 7 \))" "1" + JDK6_OR_EARLIER=1 + endif +else + # the longer variables aren't set so check the shorter variable names + ifeq "$(shell expr \( '$(JDK_MAJOR_VER)' = 1 \& '$(JDK_MINOR_VER)' \< 7 \))" "1" + JDK6_OR_EARLIER=1 + endif +endif + +ifeq ($(JDK6_OR_EARLIER),0) + # Full Debug Symbols is supported on JDK7 or newer. + # The Full Debug Symbols (FDS) default for BUILD_FLAVOR == product + # builds is enabled with debug info files ZIP'ed to save space. For + # BUILD_FLAVOR != product builds, FDS is always enabled, after all a + # debug build without debug info isn't very useful. + # The ZIP_DEBUGINFO_FILES option only has meaning when FDS is enabled. + # + # If you invoke a build with FULL_DEBUG_SYMBOLS=0, then FDS will be + # disabled for a BUILD_FLAVOR == product build. + # + # Note: Use of a different variable name for the FDS override option + # versus the FDS enabled check is intentional (FULL_DEBUG_SYMBOLS + # versus ENABLE_FULL_DEBUG_SYMBOLS). For auto build systems that pass + # in options via environment variables, use of distinct variables + # prevents strange behaviours. For example, in a BUILD_FLAVOR != + # product build, the FULL_DEBUG_SYMBOLS environment variable will be + # 0, but the ENABLE_FULL_DEBUG_SYMBOLS make variable will be 1. If + # the same variable name is used, then different values can be picked + # up by different parts of the build. Just to be clear, we only need + # two variable names because the incoming option value can be + # overridden in some situations, e.g., a BUILD_FLAVOR != product + # build. + + # Due to the multiple sub-make processes that occur this logic gets + # executed multiple times. We reduce the noise by at least checking that + # BUILD_FLAVOR has been set. + ifneq ($(BUILD_FLAVOR),) + ifeq ($(BUILD_FLAVOR), product) + FULL_DEBUG_SYMBOLS ?= 1 + ENABLE_FULL_DEBUG_SYMBOLS = $(FULL_DEBUG_SYMBOLS) + else + # debug variants always get Full Debug Symbols (if available) + ENABLE_FULL_DEBUG_SYMBOLS = 1 + endif + _JUNK_ := $(shell \ + echo >&2 "INFO: ENABLE_FULL_DEBUG_SYMBOLS=$(ENABLE_FULL_DEBUG_SYMBOLS)") + # since objcopy is optional, we set ZIP_DEBUGINFO_FILES later + + ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) + ifeq ($(OS_VENDOR), Darwin) + # MacOS X doesn't use OBJCOPY or STRIP_POLICY + OBJCOPY= + STRIP_POLICY= + ZIP_DEBUGINFO_FILES ?= 1 + else + # Default OBJCOPY comes from GNU Binutils on BSD + ifeq ($(CROSS_COMPILE_ARCH),) + DEF_OBJCOPY=/usr/bin/objcopy + else + # Assume objcopy is part of the cross-compilation toolset + ifneq ($(ALT_COMPILER_PATH),) + DEF_OBJCOPY=$(ALT_COMPILER_PATH)/objcopy + endif + endif + OBJCOPY=$(shell test -x $(DEF_OBJCOPY) && echo $(DEF_OBJCOPY)) + ifneq ($(ALT_OBJCOPY),) + _JUNK_ := $(shell echo >&2 "INFO: ALT_OBJCOPY=$(ALT_OBJCOPY)") + OBJCOPY=$(shell test -x $(ALT_OBJCOPY) && echo $(ALT_OBJCOPY)) + endif + + ifeq ($(OBJCOPY),) + _JUNK_ := $(shell \ + echo >&2 "INFO: no objcopy cmd found so cannot create .debuginfo" \ + "files. You may need to set ALT_OBJCOPY.") + ENABLE_FULL_DEBUG_SYMBOLS=0 + _JUNK_ := $(shell \ + echo >&2 "INFO:" \ + "ENABLE_FULL_DEBUG_SYMBOLS=$(ENABLE_FULL_DEBUG_SYMBOLS)") + else + _JUNK_ := $(shell \ + echo >&2 "INFO: $(OBJCOPY) cmd found so will create .debuginfo" \ + "files.") + + # Library stripping policies for .debuginfo configs: + # all_strip - strips everything from the library + # min_strip - strips most stuff from the library; leaves + # minimum symbols + # no_strip - does not strip the library at all + # + # Oracle security policy requires "all_strip". A waiver was + # granted on 2011.09.01 that permits using "min_strip" in the + # Java JDK and Java JRE. + # + # Currently, STRIP_POLICY is only used when Full Debug Symbols + # is enabled. + # + STRIP_POLICY ?= min_strip + + _JUNK_ := $(shell \ + echo >&2 "INFO: STRIP_POLICY=$(STRIP_POLICY)") + + ZIP_DEBUGINFO_FILES ?= 1 + endif + + _JUNK_ := $(shell \ + echo >&2 "INFO: ZIP_DEBUGINFO_FILES=$(ZIP_DEBUGINFO_FILES)") + endif + endif # ENABLE_FULL_DEBUG_SYMBOLS=1 + endif # BUILD_FLAVOR +endif # JDK_6_OR_EARLIER + JDK_INCLUDE_SUBDIR=bsd # Library suffix -OS_VENDOR:=$(shell uname -s) ifeq ($(OS_VENDOR),Darwin) LIBRARY_SUFFIX=dylib else @@ -150,6 +267,19 @@ # client and server subdirectories have symbolic links to ../libjsig.so EXPORT_LIST += $(EXPORT_JRE_LIB_ARCH_DIR)/libjsig.$(LIBRARY_SUFFIX) + +ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) + ifeq ($(ZIP_DEBUGINFO_FILES),1) + EXPORT_LIST += $(EXPORT_JRE_LIB_ARCH_DIR)/libjsig.diz + else + ifeq ($(OS_VENDOR), Darwin) + EXPORT_LIST += $(EXPORT_JRE_LIB_ARCH_DIR)/libjsig.$(LIBRARY_SUFFIX).dSYM + else + EXPORT_LIST += $(EXPORT_JRE_LIB_ARCH_DIR)/libjsig.debuginfo + endif + endif +endif + EXPORT_SERVER_DIR = $(EXPORT_JRE_LIB_ARCH_DIR)/server EXPORT_CLIENT_DIR = $(EXPORT_JRE_LIB_ARCH_DIR)/client EXPORT_MINIMAL_DIR = $(EXPORT_JRE_LIB_ARCH_DIR)/minimal @@ -157,34 +287,76 @@ ifeq ($(findstring true, $(JVM_VARIANT_SERVER) $(JVM_VARIANT_ZERO) $(JVM_VARIANT_ZEROSHARK)), true) EXPORT_LIST += $(EXPORT_SERVER_DIR)/Xusage.txt EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm.$(LIBRARY_SUFFIX) + + ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) + ifeq ($(ZIP_DEBUGINFO_FILES),1) + EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm.diz + else + ifeq ($(OS_VENDOR), Darwin) + EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm.$(LIBRARY_SUFFIX).dSYM + else + EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm.debuginfo + endif + endif + endif endif ifeq ($(JVM_VARIANT_CLIENT),true) EXPORT_LIST += $(EXPORT_CLIENT_DIR)/Xusage.txt EXPORT_LIST += $(EXPORT_CLIENT_DIR)/libjvm.$(LIBRARY_SUFFIX) + + ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) + ifeq ($(ZIP_DEBUGINFO_FILES),1) + EXPORT_LIST += $(EXPORT_CLIENT_DIR)/libjvm.diz + else + ifeq ($(OS_VENDOR), Darwin) + EXPORT_LIST += $(EXPORT_CLIENT_DIR)/libjvm.$(LIBRARY_SUFFIX).dSYM + else + EXPORT_LIST += $(EXPORT_CLIENT_DIR)/libjvm.debuginfo + endif + endif + endif endif ifeq ($(JVM_VARIANT_MINIMAL1),true) EXPORT_LIST += $(EXPORT_MINIMAL_DIR)/Xusage.txt EXPORT_LIST += $(EXPORT_MINIMAL_DIR)/libjvm.$(LIBRARY_SUFFIX) - - ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) - ifeq ($(ZIP_DEBUGINFO_FILES),1) - EXPORT_LIST += $(EXPORT_MINIMAL_DIR)/libjvm.diz - else - EXPORT_LIST += $(EXPORT_MINIMAL_DIR)/libjvm.debuginfo - endif - endif endif # Serviceability Binaries # No SA Support for PPC, IA64, ARM or zero ADD_SA_BINARIES/x86 = $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.$(LIBRARY_SUFFIX) \ $(EXPORT_LIB_DIR)/sa-jdi.jar + +ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) + ifeq ($(ZIP_DEBUGINFO_FILES),1) + ADD_SA_BINARIES/x86 += $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.diz + else + ifeq ($(OS_VENDOR), Darwin) + ADD_SA_BINARIES/x86 += $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.$(LIBRARY_SUFFIX).dSYM + else + ADD_SA_BINARIES/x86 += $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.debuginfo + endif + endif +endif + ADD_SA_BINARIES/sparc = $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.$(LIBRARY_SUFFIX) \ $(EXPORT_LIB_DIR)/sa-jdi.jar ADD_SA_BINARIES/universal = $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.$(LIBRARY_SUFFIX) \ $(EXPORT_LIB_DIR)/sa-jdi.jar + +ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) + ifeq ($(ZIP_DEBUGINFO_FILES),1) + ADD_SA_BINARIES/universal += $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.diz + else + ifeq ($(OS_VENDOR), Darwin) + ADD_SA_BINARIES/universal += $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.$(LIBRARY_SUFFIX).dSYM + else + ADD_SA_BINARIES/universal += $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.debuginfo + endif + endif +endif + ADD_SA_BINARIES/ppc = ADD_SA_BINARIES/ia64 = ADD_SA_BINARIES/arm = @@ -225,6 +397,19 @@ # Files to simply copy in place UNIVERSAL_COPY_LIST += $(EXPORT_JRE_LIB_DIR)/server/Xusage.txt UNIVERSAL_COPY_LIST += $(EXPORT_JRE_LIB_DIR)/client/Xusage.txt + ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) + ifeq ($(ZIP_DEBUGINFO_FILES),1) + UNIVERSAL_COPY_LIST += $(EXPORT_JRE_LIB_DIR)/server/libjvm.diz + UNIVERSAL_COPY_LIST += $(EXPORT_JRE_LIB_DIR)/client/libjvm.diz + UNIVERSAL_COPY_LIST += $(EXPORT_JRE_LIB_DIR)/libjsig.diz + UNIVERSAL_COPY_LIST += $(EXPORT_JRE_LIB_DIR)/libsaproc.diz + else + UNIVERSAL_COPY_LIST += $(EXPORT_JRE_LIB_DIR)/server/libjvm.$(LIBRARY_SUFFIX).dSYM + UNIVERSAL_COPY_LIST += $(EXPORT_JRE_LIB_DIR)/client/libjvm.$(LIBRARY_SUFFIX).dSYM + UNIVERSAL_COPY_LIST += $(EXPORT_JRE_LIB_DIR)/libjsig.$(LIBRARY_SUFFIX).dSYM + UNIVERSAL_COPY_LIST += $(EXPORT_JRE_LIB_DIR)/libsaproc.$(LIBRARY_SUFFIX).dSYM + endif + endif endif endif diff -r 6795fcebbf42 -r c31f0cbe6d9e make/bsd/makefiles/dtrace.make --- a/make/bsd/makefiles/dtrace.make Mon Oct 21 14:08:09 2013 +0100 +++ b/make/bsd/makefiles/dtrace.make Sun Nov 03 07:50:24 2013 +0000 @@ -39,9 +39,15 @@ JVM_DB = libjvm_db LIBJVM_DB = libjvm_db.dylib +LIBJVM_DB_DEBUGINFO = libjvm_db.dylib.dSYM +LIBJVM_DB_DIZ = libjvm_db.diz + JVM_DTRACE = jvm_dtrace LIBJVM_DTRACE = libjvm_dtrace.dylib +LIBJVM_DTRACE_DEBUGINFO = libjvm_dtrace.dylib.dSYM +LIBJVM_DTRACE_DIZ = libjvm_dtrace.diz + JVMOFFS = JvmOffsets JVMOFFS.o = $(JVMOFFS).o GENOFFS = generate$(JVMOFFS) @@ -76,21 +82,87 @@ # Making 64/libjvm_db.so: 64-bit version of libjvm_db.so which handles 32-bit libjvm.so ifneq ("${ISA}","${BUILDARCH}") -XLIBJVM_DB = 64/$(LIBJVM_DB) -XLIBJVM_DTRACE = 64/$(LIBJVM_DTRACE) +XLIBJVM_DIR = 64 +XLIBJVM_DB = $(XLIBJVM_DIR)/$(LIBJVM_DB) +XLIBJVM_DTRACE = $(XLIBJVM_DIR)/$(LIBJVM_DTRACE) XARCH = $(subst sparcv9,v9,$(shell echo $(ISA))) +XLIBJVM_DB_DEBUGINFO = $(XLIBJVM_DIR)/$(LIBJVM_DB_DEBUGINFO) +XLIBJVM_DB_DIZ = $(XLIBJVM_DIR)/$(LIBJVM_DB_DIZ) +XLIBJVM_DTRACE_DEBUGINFO = $(XLIBJVM_DIR)/$(LIBJVM_DTRACE_DEBUGINFO) +XLIBJVM_DTRACE_DIZ = $(XLIBJVM_DIR)/$(LIBJVM_DTRACE_DIZ) + $(XLIBJVM_DB): $(DTRACE_SRCDIR)/$(JVM_DB).c $(JVMOFFS).h $(LIBJVM_DB_MAPFILE) @echo Making $@ - $(QUIETLY) mkdir -p 64/ ; \ + $(QUIETLY) mkdir -p $(XLIBJVM_DIR) ; \ $(CC) $(SYMFLAG) -xarch=$(XARCH) -D$(TYPE) -I. -I$(GENERATED) \ $(SHARED_FLAG) $(LFLAGS_JVM_DB) -o $@ $(DTRACE_SRCDIR)/$(JVM_DB).c #-lc +ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) + ifeq ($(OS_VENDOR), Darwin) + $(DSYMUTIL) $@ + ifeq ($(ZIP_DEBUGINFO_FILES),1) + # Do this part in the $(XLIBJVM_DIR) subdir so $(XLIBJVM_DIR) + # is not in the archived name: + ( cd $(XLIBJVM_DIR) && $(ZIPEXE) -q -r -y $(LIBJVM_DB_DIZ) $(LIBJVM_DB_DEBUGINFO) ) + $(RM) -r $(XLIBJVM_DB_DEBUGINFO) + endif + else + $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(XLIBJVM_DB_DEBUGINFO) + # Do this part in the $(XLIBJVM_DIR) subdir so $(XLIBJVM_DIR) + # is not in the link name: + $(QUIETLY) ( cd $(XLIBJVM_DIR) && $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DB_DEBUGINFO) $(LIBJVM_DB) ) + ifeq ($(STRIP_POLICY),all_strip) + $(QUIETLY) $(STRIP) $@ + else + ifeq ($(STRIP_POLICY),min_strip) + $(QUIETLY) $(STRIP) -x $@ + # implied else here is no stripping at all + endif + endif + ifeq ($(ZIP_DEBUGINFO_FILES),1) + # Do this part in the $(XLIBJVM_DIR) subdir so $(XLIBJVM_DIR) + # is not in the archived name: + ( cd $(XLIBJVM_DIR) && $(ZIPEXE) -q -y $(LIBJVM_DB_DIZ) $(LIBJVM_DB_DEBUGINFO) ) + $(RM) $(XLIBJVM_DB_DEBUGINFO) + endif + endif +endif $(XLIBJVM_DTRACE): $(DTRACE_SRCDIR)/$(JVM_DTRACE).c $(DTRACE_SRCDIR)/$(JVM_DTRACE).h $(LIBJVM_DTRACE_MAPFILE) @echo Making $@ - $(QUIETLY) mkdir -p 64/ ; \ + $(QUIETLY) mkdir -p $(XLIBJVM_DIR) ; \ $(CC) $(SYMFLAG) -xarch=$(XARCH) -D$(TYPE) -I. \ $(SHARED_FLAG) $(LFLAGS_JVM_DTRACE) -o $@ $(DTRACE_SRCDIR)/$(JVM_DTRACE).c #-lc -lthread -ldoor +ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) + ifeq ($(OS_VENDOR), Darwin) + $(DSYMUTIL) $@ + ifeq ($(ZIP_DEBUGINFO_FILES),1) + # Do this part in the $(XLIBJVM_DIR) subdir so $(XLIBJVM_DIR) + # is not in the archived name: + ( cd $(XLIBJVM_DIR) && $(ZIPEXE) -q -r -y $(LIBJVM_DTRACE_DIZ) $(LIBJVM_DTRACE_DEBUGINFO) ) + $(RM) -r $(XLIBJVM_DTRACE_DEBUGINFO) + endif + else + $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(XLIBJVM_DTRACE_DEBUGINFO) + # Do this part in the $(XLIBJVM_DIR) subdir so $(XLIBJVM_DIR) + # is not in the link name: + ( cd $(XLIBJVM_DIR) && $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DTRACE_DEBUGINFO) $(LIBJVM_DTRACE) ) + ifeq ($(STRIP_POLICY),all_strip) + $(QUIETLY) $(STRIP) $@ + else + ifeq ($(STRIP_POLICY),min_strip) + $(QUIETLY) $(STRIP) -x $@ + # implied else here is no stripping at all + endif + endif + ifeq ($(ZIP_DEBUGINFO_FILES),1) + # Do this part in the $(XLIBJVM_DIR) subdir so $(XLIBJVM_DIR) + # is not in the archived name: + ( cd $(XLIBJVM_DIR) && $(ZIPEXE) -q -y $(LIBJVM_DTRACE_DIZ) $(LIBJVM_DTRACE_DEBUGINFO) ) + $(RM) $(XLIBJVM_DTRACE_DEBUGINFO) + endif + endif +endif endif # ifneq ("${ISA}","${BUILDARCH}") @@ -134,11 +206,59 @@ @echo Making $@ $(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) -D$(TYPE) -I. -I$(GENERATED) \ $(SHARED_FLAG) $(LFLAGS_JVM_DB) -o $@ $(DTRACE_SRCDIR)/$(JVM_DB).c -Wall # -lc +ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) + ifeq ($(OS_VENDOR), Darwin) + $(DSYMUTIL) $@ + ifeq ($(ZIP_DEBUGINFO_FILES),1) + $(ZIPEXE) -q -r -y $(LIBJVM_DB_DIZ) $(LIBJVM_DB_DEBUGINFO) + $(RM) -r $(LIBJVM_DB_DEBUGINFO) + endif + else + $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBJVM_DB_DEBUGINFO) + $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DB_DEBUGINFO) $@ + ifeq ($(STRIP_POLICY),all_strip) + $(QUIETLY) $(STRIP) $@ + else + ifeq ($(STRIP_POLICY),min_strip) + $(QUIETLY) $(STRIP) -x $@ + # implied else here is no stripping at all + endif + endif + ifeq ($(ZIP_DEBUGINFO_FILES),1) + $(ZIPEXE) -q -y $(LIBJVM_DB_DIZ) $(LIBJVM_DB_DEBUGINFO) + $(RM) $(LIBJVM_DB_DEBUGINFO) + endif + endif +endif $(LIBJVM_DTRACE): $(DTRACE_SRCDIR)/$(JVM_DTRACE).c $(XLIBJVM_DTRACE) $(DTRACE_SRCDIR)/$(JVM_DTRACE).h $(LIBJVM_DTRACE_MAPFILE) @echo Making $@ $(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) -D$(TYPE) -I. \ $(SHARED_FLAG) $(LFLAGS_JVM_DTRACE) -o $@ $(DTRACE_SRCDIR)/$(JVM_DTRACE).c #-lc -lthread -ldoor +ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) + ifeq ($(OS_VENDOR), Darwin) + $(DSYMUTIL) $@ + ifeq ($(ZIP_DEBUGINFO_FILES),1) + $(ZIPEXE) -q -r -y $(LIBJVM_DTRACE_DIZ) $(LIBJVM_DTRACE_DEBUGINFO) + $(RM) -r $(LIBJVM_DTRACE_DEBUGINFO) + endif + else + $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBJVM_DTRACE_DEBUGINFO) + $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DTRACE_DEBUGINFO) $@ + ifeq ($(STRIP_POLICY),all_strip) + $(QUIETLY) $(STRIP) $@ + else + ifeq ($(STRIP_POLICY),min_strip) + $(QUIETLY) $(STRIP) -x $@ + # implied else here is no stripping at all + endif + endif + ifeq ($(ZIP_DEBUGINFO_FILES),1) + $(ZIPEXE) -q -y $(LIBJVM_DTRACE_DIZ) $(LIBJVM_DTRACE_DEBUGINFO) + $(RM) $(LIBJVM_DTRACE_DEBUGINFO) + endif + endif +endif #$(DTRACE).d: $(DTRACE_SRCDIR)/hotspot.d $(DTRACE_SRCDIR)/hotspot_jni.d \ # $(DTRACE_SRCDIR)/hs_private.d $(DTRACE_SRCDIR)/jhelper.d diff -r 6795fcebbf42 -r c31f0cbe6d9e make/bsd/makefiles/gcc.make --- a/make/bsd/makefiles/gcc.make Mon Oct 21 14:08:09 2013 +0100 +++ b/make/bsd/makefiles/gcc.make Sun Nov 03 07:50:24 2013 +0000 @@ -83,6 +83,11 @@ AS = $(CC) -c endif +ifeq ($(OS_VENDOR), Darwin) + ifeq ($(DSYMUTIL),) + DSYMUTIL=dsymutil + endif +endif ifeq ($(USE_CLANG), true) CC_VER_MAJOR := $(shell $(CC) -v 2>&1 | grep version | sed "s/.*version \([0-9]*\.[0-9]*\).*/\1/" | cut -d'.' -f1) @@ -434,6 +439,36 @@ ifeq ($(DEBUG_CFLAGS/$(BUILDARCH)),) DEBUG_CFLAGS += -gstabs endif + + ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) + FASTDEBUG_CFLAGS/ia64 = -g + FASTDEBUG_CFLAGS/amd64 = -g + FASTDEBUG_CFLAGS/arm = -g + FASTDEBUG_CFLAGS/ppc = -g + FASTDEBUG_CFLAGS += $(FASTDEBUG_CFLAGS/$(BUILDARCH)) + ifeq ($(FASTDEBUG_CFLAGS/$(BUILDARCH)),) + ifeq ($(USE_CLANG), true) + # Clang doesn't understand -gstabs + FASTDEBUG_CFLAGS += -g + else + FASTDEBUG_CFLAGS += -gstabs + endif + endif + + OPT_CFLAGS/ia64 = -g + OPT_CFLAGS/amd64 = -g + OPT_CFLAGS/arm = -g + OPT_CFLAGS/ppc = -g + OPT_CFLAGS += $(OPT_CFLAGS/$(BUILDARCH)) + ifeq ($(OPT_CFLAGS/$(BUILDARCH)),) + ifeq ($(USE_CLANG), true) + # Clang doesn't understand -gstabs + OPT_CFLAGS += -g + else + OPT_CFLAGS += -gstabs + endif + endif + endif endif # If we are building HEADLESS, pass on to VM diff -r 6795fcebbf42 -r c31f0cbe6d9e make/bsd/makefiles/jsig.make --- a/make/bsd/makefiles/jsig.make Mon Oct 21 14:08:09 2013 +0100 +++ b/make/bsd/makefiles/jsig.make Sun Nov 03 07:50:24 2013 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -29,13 +29,21 @@ ifeq ($(OS_VENDOR), Darwin) LIBJSIG = lib$(JSIG).dylib + + LIBJSIG_DEBUGINFO = lib$(JSIG).dylib.dSYM + LIBJSIG_DIZ = lib$(JSIG).diz else LIBJSIG = lib$(JSIG).so + + LIBJSIG_DEBUGINFO = lib$(JSIG).debuginfo + LIBJSIG_DIZ = lib$(JSIG).diz endif JSIGSRCDIR = $(GAMMADIR)/src/os/$(Platform_os_family)/vm -DEST_JSIG = $(JDK_LIBDIR)/$(LIBJSIG) +DEST_JSIG = $(JDK_LIBDIR)/$(LIBJSIG) +DEST_JSIG_DEBUGINFO = $(JDK_LIBDIR)/$(LIBJSIG_DEBUGINFO) +DEST_JSIG_DIZ = $(JDK_LIBDIR)/$(LIBJSIG_DIZ) LIBJSIG_MAPFILE = $(MAKEFILES_DIR)/mapfile-vers-jsig @@ -55,9 +63,42 @@ @echo Making signal interposition lib... $(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) $(SHARED_FLAG) $(PICFLAG) \ $(LFLAGS_JSIG) $(JSIG_DEBUG_CFLAGS) -o $@ $< +ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) + ifeq ($(OS_VENDOR), Darwin) + $(DSYMUTIL) $@ + ifeq ($(ZIP_DEBUGINFO_FILES),1) + $(ZIPEXE) -q -r -y $(LIBJSIG_DIZ) $(LIBJSIG_DEBUGINFO) + $(RM) -r $(LIBJSIG_DEBUGINFO) + endif + else + $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBJSIG_DEBUGINFO) + $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBJSIG_DEBUGINFO) $@ + ifeq ($(STRIP_POLICY),all_strip) + $(QUIETLY) $(STRIP) $@ + else + ifeq ($(STRIP_POLICY),min_strip) + $(QUIETLY) $(STRIP) -g $@ + # implied else here is no stripping at all + endif + endif + ifeq ($(ZIP_DEBUGINFO_FILES),1) + $(ZIPEXE) -q -y $(LIBJSIG_DIZ) $(LIBJSIG_DEBUGINFO) + $(RM) $(LIBJSIG_DEBUGINFO) + endif + endif +endif install_jsig: $(LIBJSIG) @echo "Copying $(LIBJSIG) to $(DEST_JSIG)" +ifeq ($(OS_VENDOR), Darwin) + $(QUIETLY) test -d $(LIBJSIG_DEBUGINFO) && \ + cp -f -r $(LIBJSIG_DEBUGINFO) $(DEST_JSIG_DEBUGINFO) +else + $(QUIETLY) test -f $(LIBJSIG_DEBUGINFO) && \ + cp -f $(LIBJSIG_DEBUGINFO) $(DEST_JSIG_DEBUGINFO) +endif + $(QUIETLY) test -f $(LIBJSIG_DIZ) && \ + cp -f $(LIBJSIG_DIZ) $(DEST_JSIG_DIZ) $(QUIETLY) cp -f $(LIBJSIG) $(DEST_JSIG) && echo "Done" .PHONY: install_jsig diff -r 6795fcebbf42 -r c31f0cbe6d9e make/bsd/makefiles/product.make --- a/make/bsd/makefiles/product.make Mon Oct 21 14:08:09 2013 +0100 +++ b/make/bsd/makefiles/product.make Sun Nov 03 07:50:24 2013 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 2013, 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 @@ -43,15 +43,17 @@ SYSDEFS += -DPRODUCT VERSION = optimized -# use -g to strip library as -x will discard its symbol table; -x is fine for -# executables. -ifdef CROSS_COMPILE_ARCH - STRIP = $(ALT_COMPILER_PATH)/strip -else - STRIP = strip +ifneq ($(OS_VENDOR), Darwin) + # use -g to strip library as -x will discard its symbol table; -x is fine for + # executables. + ifdef CROSS_COMPILE_ARCH + STRIP = $(ALT_COMPILER_PATH)/strip + else + STRIP = strip + endif + STRIP_LIBJVM = $(STRIP) -g $@ || exit 1; + STRIP_AOUT = $(STRIP) -x $@ || exit 1; + + # Don't strip in VM build; JDK build will strip libraries later + # LINK_LIB.CXX/POST_HOOK += $(STRIP_$(LINK_INTO)) endif -STRIP_LIBJVM = $(STRIP) -g $@ || exit 1; -STRIP_AOUT = $(STRIP) -x $@ || exit 1; - -# Don't strip in VM build; JDK build will strip libraries later -# LINK_LIB.CXX/POST_HOOK += $(STRIP_$(LINK_INTO)) diff -r 6795fcebbf42 -r c31f0cbe6d9e make/bsd/makefiles/saproc.make --- a/make/bsd/makefiles/saproc.make Mon Oct 21 14:08:09 2013 +0100 +++ b/make/bsd/makefiles/saproc.make Sun Nov 03 07:50:24 2013 +0000 @@ -28,9 +28,15 @@ SAPROC = saproc ifeq ($(OS_VENDOR), Darwin) - LIBSAPROC = lib$(SAPROC).dylib + LIBSAPROC = lib$(SAPROC).dylib + + LIBSAPROC_DEBUGINFO = lib$(SAPROC).dylib.dSYM + LIBSAPROC_DIZ = lib$(SAPROC).diz else - LIBSAPROC = lib$(SAPROC).so + LIBSAPROC = lib$(SAPROC).so + + LIBSAPROC_DEBUGINFO = lib$(SAPROC).debuginfo + LIBSAPROC_DIZ = lib$(SAPROC).diz endif AGENT_DIR = $(GAMMADIR)/agent @@ -70,7 +76,9 @@ SAMAPFILE = $(SASRCDIR)/mapfile -DEST_SAPROC = $(JDK_LIBDIR)/$(LIBSAPROC) +DEST_SAPROC = $(JDK_LIBDIR)/$(LIBSAPROC) +DEST_SAPROC_DEBUGINFO = $(JDK_LIBDIR)/$(LIBSAPROC_DEBUGINFO) +DEST_SAPROC_DIZ = $(JDK_LIBDIR)/$(LIBSAPROC_DIZ) # DEBUG_BINARIES overrides everything, use full -g debug information ifeq ($(DEBUG_BINARIES), true) @@ -117,11 +125,42 @@ $(SA_DEBUG_CFLAGS) \ -o $@ \ $(SALIBS) +ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) + ifeq ($(OS_VENDOR), Darwin) + $(DSYMUTIL) $@ + ifeq ($(ZIP_DEBUGINFO_FILES),1) + $(ZIPEXE) -q -r -y $(LIBSAPROC_DIZ) $(LIBSAPROC_DEBUGINFO) + $(RM) -r $(LIBSAPROC_DEBUGINFO) + endif + else + $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBSAPROC_DEBUGINFO) + $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBSAPROC_DEBUGINFO) $@ + ifeq ($(STRIP_POLICY),all_strip) + $(QUIETLY) $(STRIP) $@ + else + ifeq ($(STRIP_POLICY),min_strip) + $(QUIETLY) $(STRIP) -g $@ + # implied else here is no stripping at all + endif + endif + ifeq ($(ZIP_DEBUGINFO_FILES),1) + $(ZIPEXE) -q -y $(LIBSAPROC_DIZ) $(LIBSAPROC_DEBUGINFO) + $(RM) $(LIBSAPROC_DEBUGINFO) + endif + endif +endif install_saproc: $(BUILDLIBSAPROC) - $(QUIETLY) if [ -e $(LIBSAPROC) ] ; then \ - echo "Copying $(LIBSAPROC) to $(DEST_SAPROC)"; \ - cp -f $(LIBSAPROC) $(DEST_SAPROC) && echo "Done"; \ - fi + @echo "Copying $(LIBSAPROC) to $(DEST_SAPROC)" +ifeq ($(OS_VENDOR), Darwin) + $(QUIETLY) test -d $(LIBSAPROC_DEBUGINFO) && \ + cp -f -r $(LIBSAPROC_DEBUGINFO) $(DEST_SAPROC_DEBUGINFO) +else + $(QUIETLY) test -f $(LIBSAPROC_DEBUGINFO) && \ + cp -f $(LIBSAPROC_DEBUGINFO) $(DEST_SAPROC_DEBUGINFO) +endif + $(QUIETLY) test -f $(LIBSAPROC_DIZ) && \ + cp -f $(LIBSAPROC_DIZ) $(DEST_SAPROC_DIZ) + $(QUIETLY) cp -f $(LIBSAPROC) $(DEST_SAPROC) && echo "Done" .PHONY: install_saproc diff -r 6795fcebbf42 -r c31f0cbe6d9e make/bsd/makefiles/universal.gmk --- a/make/bsd/makefiles/universal.gmk Mon Oct 21 14:08:09 2013 +0100 +++ b/make/bsd/makefiles/universal.gmk Sun Nov 03 07:50:24 2013 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 2013, 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 @@ -19,7 +19,7 @@ # 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. -# +# # # macosx universal builds @@ -35,15 +35,15 @@ all_product_universal: # $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=32 $(COMMON_VM_PRODUCT_TARGETS) $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=64 $(COMMON_VM_PRODUCT_TARGETS) - $(QUIETLY) $(MAKE) EXPORT_SUBDIR= universalize + $(QUIETLY) $(MAKE) BUILD_FLAVOR=product EXPORT_SUBDIR= universalize all_fastdebug_universal: # $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=32 $(COMMON_VM_FASTDEBUG_TARGETS) $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=64 $(COMMON_VM_FASTDEBUG_TARGETS) - $(QUIETLY) $(MAKE) EXPORT_SUBDIR=/fastdebug universalize + $(QUIETLY) $(MAKE) BUILD_FLAVOR=fastdebug EXPORT_SUBDIR=/fastdebug universalize all_debug_universal: # $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=32 $(COMMON_VM_DEBUG_TARGETS) $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=64 $(COMMON_VM_DEBUG_TARGETS) - $(QUIETLY) $(MAKE) EXPORT_SUBDIR=/debug universalize + $(QUIETLY) $(MAKE) BUILD_FLAVOR=debug EXPORT_SUBDIR=/debug universalize # Consolidate architecture builds into a single Universal binary @@ -57,18 +57,18 @@ if [ -n "$${BUILT_LIPO_FILES}" ]; then \ $(MKDIR) -p $(shell dirname $@); \ lipo -create -output $@ $${BUILT_LIPO_FILES}; \ - fi + fi # Copy built non-universal binaries in place +# - copies directories; including empty dirs +# - copies files, symlinks, other non-directory files $(UNIVERSAL_COPY_LIST): - BUILT_COPY_FILES="`find $(EXPORT_JRE_LIB_DIR)/{i386,amd64}/$(subst $(EXPORT_JRE_LIB_DIR)/,,$@) 2>/dev/null`"; \ + BUILT_COPY_FILES="`find $(EXPORT_JRE_LIB_DIR)/{i386,amd64}/$(subst $(EXPORT_JRE_LIB_DIR)/,,$@) -prune 2>/dev/null`"; \ if [ -n "$${BUILT_COPY_FILES}" ]; then \ for i in $${BUILT_COPY_FILES}; do \ - if [ -f $${i} ]; then \ - $(MKDIR) -p $(shell dirname $@); \ - $(CP) $${i} $@; \ - fi; \ + $(MKDIR) -p $(shell dirname $@); \ + $(CP) -R $${i} $@; \ done; \ fi diff -r 6795fcebbf42 -r c31f0cbe6d9e make/bsd/makefiles/vm.make --- a/make/bsd/makefiles/vm.make Mon Oct 21 14:08:09 2013 +0100 +++ b/make/bsd/makefiles/vm.make Sun Nov 03 07:50:24 2013 +0000 @@ -60,10 +60,16 @@ # The order is important for the precompiled headers to work. INCLUDES += $(PRECOMPILED_HEADER_DIR:%=-I%) $(Src_Dirs_I:%=-I%) -ifeq (${VERSION}, debug) +# SYMFLAG is used by {jsig,saproc}.make +ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) + # always build with debug info when we can create .dSYM/.debuginfo files SYMFLAG = -g else - SYMFLAG = + ifeq (${VERSION}, debug) + SYMFLAG = -g + else + SYMFLAG = + endif endif # HOTSPOT_RELEASE_VERSION and HOTSPOT_BUILD_VERSION are defined @@ -147,8 +153,14 @@ ifeq (${VERSION}, $(filter ${VERSION}, debug fastdebug)) CFLAGS += -DALLOW_OPERATOR_NEW_USAGE endif + + LIBJVM_DEBUGINFO = lib$(JVM).dylib.dSYM + LIBJVM_DIZ = lib$(JVM).diz else LIBJVM = lib$(JVM).so + + LIBJVM_DEBUGINFO = lib$(JVM).debuginfo + LIBJVM_DIZ = lib$(JVM).diz endif SPECIAL_PATHS:=adlc c1 gc_implementation opto shark libadt @@ -322,10 +334,47 @@ rm -f $@.1; ln -s $@ $@.1; \ } -DEST_JVM = $(JDK_LIBDIR)/$(VM_SUBDIR)/$(LIBJVM) +ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) + ifeq ($(OS_VENDOR), Darwin) + $(DSYMUTIL) $@ + ifeq ($(ZIP_DEBUGINFO_FILES),1) + $(ZIPEXE) -q -r -y $(LIBJVM_DIZ) $(LIBJVM_DEBUGINFO) + $(RM) -r $(LIBJVM_DEBUGINFO) + endif + else + $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBJVM_DEBUGINFO) + $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DEBUGINFO) $@ + ifeq ($(STRIP_POLICY),all_strip) + $(QUIETLY) $(STRIP) $@ + else + ifeq ($(STRIP_POLICY),min_strip) + $(QUIETLY) $(STRIP) -g $@ + # implied else here is no stripping at all + endif + endif + ifeq ($(ZIP_DEBUGINFO_FILES),1) + $(ZIPEXE) -q -y $(LIBJVM_DIZ) $(LIBJVM_DEBUGINFO) + $(RM) $(LIBJVM_DEBUGINFO) + endif + endif +endif + +DEST_SUBDIR = $(JDK_LIBDIR)/$(VM_SUBDIR) +DEST_JVM = $(DEST_SUBDIR)/$(LIBJVM) +DEST_JVM_DEBUGINFO = $(DEST_SUBDIR)/$(LIBJVM_DEBUGINFO) +DEST_JVM_DIZ = $(DEST_SUBDIR)/$(LIBJVM_DIZ) install_jvm: $(LIBJVM) @echo "Copying $(LIBJVM) to $(DEST_JVM)" +ifeq ($(OS_VENDOR), Darwin) + $(QUIETLY) test -d $(LIBJVM_DEBUGINFO) && \ + cp -f -r $(LIBJVM_DEBUGINFO) $(DEST_JVM_DEBUGINFO) +else + $(QUIETLY) test -f $(LIBJVM_DEBUGINFO) && \ + cp -f $(LIBJVM_DEBUGINFO) $(DEST_JVM_DEBUGINFO) +endif + $(QUIETLY) test -f $(LIBJVM_DIZ) && \ + cp -f $(LIBJVM_DIZ) $(DEST_JVM_DIZ) $(QUIETLY) cp -f $(LIBJVM) $(DEST_JVM) && echo "Done" #---------------------------------------------------------------------- @@ -340,11 +389,8 @@ #---------------------------------------------------------------------- ifeq ($(OS_VENDOR), Darwin) -$(LIBJVM).dSYM: $(LIBJVM) - dsymutil $(LIBJVM) - # no libjvm_db for macosx -build: $(LIBJVM) $(LAUNCHER) $(LIBJSIG) $(BUILDLIBSAPROC) dtraceCheck $(LIBJVM).dSYM +build: $(LIBJVM) $(LAUNCHER) $(LIBJSIG) $(BUILDLIBSAPROC) dtraceCheck echo "Doing vm.make build:" else build: $(LIBJVM) $(LAUNCHER) $(LIBJSIG) $(LIBJVM_DB) $(BUILDLIBSAPROC) diff -r 6795fcebbf42 -r c31f0cbe6d9e make/defs.make --- a/make/defs.make Mon Oct 21 14:08:09 2013 +0100 +++ b/make/defs.make Sun Nov 03 07:50:24 2013 +0000 @@ -77,6 +77,16 @@ @$(RM) $@ $(CP) $< $@ endef + +# MacOS X strongly discourages 'cp -r' and provides 'cp -R' instead. +# May need to have a MacOS X specific definition of install-dir +# sometime in the future. +define install-dir +@$(MKDIR) -p $(@D) +@$(RM) -r $@ +$(CP) -r $< $@ +endef + define prep-target @$(MKDIR) -p $(@D) @$(RM) $@ diff -r 6795fcebbf42 -r c31f0cbe6d9e make/hotspot_version --- a/make/hotspot_version Mon Oct 21 14:08:09 2013 +0100 +++ b/make/hotspot_version Sun Nov 03 07:50:24 2013 +0000 @@ -35,7 +35,7 @@ HS_MAJOR_VER=25 HS_MINOR_VER=0 -HS_BUILD_NUMBER=54 +HS_BUILD_NUMBER=56 JDK_MAJOR_VER=1 JDK_MINOR_VER=8 diff -r 6795fcebbf42 -r c31f0cbe6d9e make/jprt.properties --- a/make/jprt.properties Mon Oct 21 14:08:09 2013 +0100 +++ b/make/jprt.properties Sun Nov 03 07:50:24 2013 +0000 @@ -24,12 +24,7 @@ # Properties for jprt -# All build result bundles are full jdks, so the 64bit testing does not -# need the 32bit sibling bundle installed. -# Note: If the hotspot/make/Makefile changed to only bundle the 64bit files -# when bundling 64bit, and stripped out the 64bit files from any 32bit -# bundles, then this setting would be need to be "true". - +# All build result bundles are full jdks. jprt.need.sibling.build=false # At submit time, the release supplied will be in jprt.submit.release @@ -52,21 +47,11 @@ # sparc etc. # Define the Solaris platforms we want for the various releases -jprt.my.solaris.sparc.jdk8=solaris_sparc_5.10 -jprt.my.solaris.sparc.jdk7=solaris_sparc_5.10 -jprt.my.solaris.sparc.jdk7u8=${jprt.my.solaris.sparc.jdk7} -jprt.my.solaris.sparc=${jprt.my.solaris.sparc.${jprt.tools.default.release}} - jprt.my.solaris.sparcv9.jdk8=solaris_sparcv9_5.10 jprt.my.solaris.sparcv9.jdk7=solaris_sparcv9_5.10 jprt.my.solaris.sparcv9.jdk7u8=${jprt.my.solaris.sparcv9.jdk7} jprt.my.solaris.sparcv9=${jprt.my.solaris.sparcv9.${jprt.tools.default.release}} -jprt.my.solaris.i586.jdk8=solaris_i586_5.10 -jprt.my.solaris.i586.jdk7=solaris_i586_5.10 -jprt.my.solaris.i586.jdk7u8=${jprt.my.solaris.i586.jdk7} -jprt.my.solaris.i586=${jprt.my.solaris.i586.${jprt.tools.default.release}} - jprt.my.solaris.x64.jdk8=solaris_x64_5.10 jprt.my.solaris.x64.jdk7=solaris_x64_5.10 jprt.my.solaris.x64.jdk7u8=${jprt.my.solaris.x64.jdk7} @@ -133,9 +118,7 @@ # Standard list of jprt build targets for this source tree jprt.build.targets.standard= \ - ${jprt.my.solaris.sparc}-{product|fastdebug}, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug|optimized}, \ - ${jprt.my.solaris.i586}-{product|fastdebug}, \ ${jprt.my.solaris.x64}-{product|fastdebug}, \ ${jprt.my.linux.i586}-{product|fastdebug}, \ ${jprt.my.linux.x64}-{product|fastdebug|optimized}, \ @@ -145,7 +128,6 @@ ${jprt.my.linux.armvh}-{product|fastdebug} jprt.build.targets.open= \ - ${jprt.my.solaris.i586}-{productOpen}, \ ${jprt.my.solaris.x64}-{debugOpen}, \ ${jprt.my.linux.x64}-{productOpen} @@ -168,31 +150,6 @@ # Subset lists of test targets for this source tree -jprt.my.solaris.sparc.test.targets= \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jvm98, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-c2-jvm98_nontiered, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-scimark, \ - ${jprt.my.solaris.sparc}-product-{c1|c2}-runThese, \ - ${jprt.my.solaris.sparc}-fastdebug-c1-runThese_Xshare, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_SerialGC, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_ParallelGC, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_ParNewGC, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_CMS, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_G1, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_ParOldGC, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_SerialGC, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_ParallelGC, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_ParNewGC, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_CMS, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_G1, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_ParOldGC, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-c2-jbb_default_nontiered, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_SerialGC, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_ParallelGC, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_CMS, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_G1, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_ParOldGC - jprt.my.solaris.sparcv9.test.targets= \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jvm98, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jvm98_nontiered, \ @@ -242,37 +199,6 @@ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_G1, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_ParOldGC -jprt.my.solaris.i586.test.targets= \ - ${jprt.my.solaris.i586}-{product|fastdebug}-{c1|c2}-jvm98, \ - ${jprt.my.solaris.i586}-{product|fastdebug}-c2-jvm98_nontiered, \ - ${jprt.my.solaris.i586}-{product|fastdebug}-{c1|c2}-scimark, \ - ${jprt.my.solaris.i586}-product-{c1|c2}-runThese_Xcomp, \ - ${jprt.my.solaris.i586}-fastdebug-c1-runThese_Xcomp, \ - ${jprt.my.solaris.i586}-fastdebug-c1-runThese_Xshare, \ - ${jprt.my.solaris.i586}-product-c1-GCBasher_SerialGC, \ - ${jprt.my.solaris.i586}-product-c1-GCBasher_ParallelGC, \ - ${jprt.my.solaris.i586}-product-c1-GCBasher_ParNewGC, \ - ${jprt.my.solaris.i586}-product-c1-GCBasher_CMS, \ - ${jprt.my.solaris.i586}-product-c1-GCBasher_G1, \ - ${jprt.my.solaris.i586}-product-c1-GCBasher_ParOldGC, \ - ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_SerialGC, \ - ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_ParallelGC, \ - ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_ParNewGC, \ - ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_CMS, \ - ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_G1, \ - ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_ParOldGC, \ - ${jprt.my.solaris.i586}-product-c1-GCOld_SerialGC, \ - ${jprt.my.solaris.i586}-product-c1-GCOld_ParallelGC, \ - ${jprt.my.solaris.i586}-product-c1-GCOld_ParNewGC, \ - ${jprt.my.solaris.i586}-product-c1-GCOld_CMS, \ - ${jprt.my.solaris.i586}-product-c1-GCOld_G1, \ - ${jprt.my.solaris.i586}-product-c1-GCOld_ParOldGC, \ - ${jprt.my.solaris.i586}-fastdebug-c2-jbb_default_nontiered, \ - ${jprt.my.solaris.i586}-fastdebug-c2-jbb_ParallelGC, \ - ${jprt.my.solaris.i586}-fastdebug-c2-jbb_CMS, \ - ${jprt.my.solaris.i586}-fastdebug-c2-jbb_G1, \ - ${jprt.my.solaris.i586}-fastdebug-c2-jbb_ParOldGC - jprt.my.linux.i586.test.targets = \ ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-jvm98, \ ${jprt.my.linux.i586}-{product|fastdebug}-c2-jvm98_nontiered, \ @@ -395,7 +321,6 @@ # Some basic "smoke" tests for OpenJDK builds jprt.test.targets.open = \ ${jprt.my.solaris.x64}-{productOpen|fastdebugOpen}-c2-jvm98, \ - ${jprt.my.solaris.i586}-{productOpen|fastdebugOpen}-c2-jvm98, \ ${jprt.my.linux.x64}-{productOpen|fastdebugOpen}-c2-jvm98 # Testing for actual embedded builds is different to standard @@ -407,9 +332,7 @@ jprt.test.targets.standard = \ ${jprt.my.linux.i586.test.targets.embedded}, \ - ${jprt.my.solaris.sparc.test.targets}, \ ${jprt.my.solaris.sparcv9.test.targets}, \ - ${jprt.my.solaris.i586.test.targets}, \ ${jprt.my.solaris.x64.test.targets}, \ ${jprt.my.linux.i586.test.targets}, \ ${jprt.my.linux.x64.test.targets}, \ @@ -420,15 +343,12 @@ jprt.test.targets.embedded= \ ${jprt.my.linux.i586.test.targets.embedded}, \ - ${jprt.my.solaris.sparc.test.targets}, \ ${jprt.my.solaris.sparcv9.test.targets}, \ - ${jprt.my.solaris.i586.test.targets}, \ ${jprt.my.solaris.x64.test.targets}, \ ${jprt.my.linux.x64.test.targets}, \ ${jprt.my.windows.i586.test.targets}, \ ${jprt.my.windows.x64.test.targets} - jprt.test.targets.jdk8=${jprt.test.targets.standard} jprt.test.targets.jdk7=${jprt.test.targets.standard} jprt.test.targets.jdk7u8=${jprt.test.targets.jdk7} @@ -439,15 +359,11 @@ #jprt.make.rule.test.targets=*-product-*-packtest jprt.make.rule.test.targets.standard.client = \ - ${jprt.my.solaris.sparc}-*-c1-clienttest, \ - ${jprt.my.solaris.i586}-*-c1-clienttest, \ ${jprt.my.linux.i586}-*-c1-clienttest, \ ${jprt.my.windows.i586}-*-c1-clienttest jprt.make.rule.test.targets.standard.server = \ - ${jprt.my.solaris.sparc}-*-c2-servertest, \ ${jprt.my.solaris.sparcv9}-*-c2-servertest, \ - ${jprt.my.solaris.i586}-*-c2-servertest, \ ${jprt.my.solaris.x64}-*-c2-servertest, \ ${jprt.my.linux.i586}-*-c2-servertest, \ ${jprt.my.linux.x64}-*-c2-servertest, \ @@ -456,9 +372,7 @@ ${jprt.my.windows.x64}-*-c2-servertest jprt.make.rule.test.targets.standard.internalvmtests = \ - ${jprt.my.solaris.sparc}-fastdebug-c2-internalvmtests, \ ${jprt.my.solaris.sparcv9}-fastdebug-c2-internalvmtests, \ - ${jprt.my.solaris.i586}-fastdebug-c2-internalvmtests, \ ${jprt.my.solaris.x64}-fastdebug-c2-internalvmtests, \ ${jprt.my.linux.i586}-fastdebug-c2-internalvmtests, \ ${jprt.my.linux.x64}-fastdebug-c2-internalvmtests, \ @@ -467,16 +381,12 @@ ${jprt.my.windows.x64}-fastdebug-c2-internalvmtests jprt.make.rule.test.targets.standard.wbapi = \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-c2-wbapitest, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-wbapitest, \ - ${jprt.my.solaris.i586}-{product|fastdebug}-c2-wbapitest, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-wbapitest, \ ${jprt.my.linux.i586}-{product|fastdebug}-c2-wbapitest, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-wbapitest, \ ${jprt.my.windows.i586}-{product|fastdebug}-c2-wbapitest, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-wbapitest, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-c1-wbapitest, \ - ${jprt.my.solaris.i586}-{product|fastdebug}-c1-wbapitest, \ ${jprt.my.linux.i586}-{product|fastdebug}-c1-wbapitest, \ ${jprt.my.windows.i586}-{product|fastdebug}-c1-wbapitest diff -r 6795fcebbf42 -r c31f0cbe6d9e make/windows/makefiles/trace.make --- a/make/windows/makefiles/trace.make Mon Oct 21 14:08:09 2013 +0100 +++ b/make/windows/makefiles/trace.make Sun Nov 03 07:50:24 2013 +0000 @@ -40,8 +40,7 @@ traceEventIds.hpp \ traceTypes.hpp - -!if "$(OPENJDK)" != "true" +!if EXISTS($(TraceAltSrcDir)) TraceGeneratedNames = $(TraceGeneratedNames) \ traceRequestables.hpp \ traceEventControl.hpp \ @@ -56,7 +55,7 @@ $(TraceOutDir)/traceEventIds.hpp \ $(TraceOutDir)/traceTypes.hpp -!if "$(OPENJDK)" != "true" +!if EXISTS($(TraceAltSrcDir)) TraceGeneratedFiles = $(TraceGeneratedFiles) \ $(TraceOutDir)/traceRequestables.hpp \ $(TraceOutDir)/traceEventControl.hpp \ @@ -68,7 +67,7 @@ XML_DEPS = $(TraceSrcDir)/trace.xml $(TraceSrcDir)/tracetypes.xml \ $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod -!if "$(OPENJDK)" != "true" +!if EXISTS($(TraceAltSrcDir)) XML_DEPS = $(XML_DEPS) $(TraceAltSrcDir)/traceevents.xml !endif @@ -87,7 +86,7 @@ @echo Generating $@ @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceSrcDir)/traceTypes.xsl -OUT $(TraceOutDir)/traceTypes.hpp -!if "$(OPENJDK)" == "true" +!if !EXISTS($(TraceAltSrcDir)) $(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS) @echo Generating OpenJDK $@ diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/sparc/vm/c1_FrameMap_sparc.cpp --- a/src/cpu/sparc/vm/c1_FrameMap_sparc.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/sparc/vm/c1_FrameMap_sparc.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -53,6 +53,8 @@ opr = as_long_opr(reg); } else if (type == T_OBJECT || type == T_ARRAY) { opr = as_oop_opr(reg); + } else if (type == T_METADATA) { + opr = as_metadata_opr(reg); } else { opr = as_opr(reg); } diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp --- a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -2565,7 +2565,7 @@ Address receiver_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)) - mdo_offset_bias); __ ld_ptr(receiver_addr, tmp1); - __ verify_oop(tmp1); + __ verify_klass_ptr(tmp1); __ cmp_and_brx_short(recv, tmp1, Assembler::notEqual, Assembler::pt, next_test); Address data_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)) - mdo_offset_bias); @@ -3100,6 +3100,10 @@ } } +void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { + fatal("Type profiling not implemented on this platform"); +} + void LIR_Assembler::align_backward_branch_target() { __ align(OptoLoopAlignment); } diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/sparc/vm/c1_Runtime1_sparc.cpp --- a/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -404,7 +404,9 @@ if (id == fast_new_instance_init_check_id) { // make sure the klass is initialized __ ldub(G5_klass, in_bytes(InstanceKlass::init_state_offset()), G3_t1); - __ cmp_and_br_short(G3_t1, InstanceKlass::fully_initialized, Assembler::notEqual, Assembler::pn, slow_path); + __ cmp(G3_t1, InstanceKlass::fully_initialized); + __ br(Assembler::notEqual, false, Assembler::pn, slow_path); + __ delayed()->nop(); } #ifdef ASSERT // assert object can be fast path allocated @@ -515,7 +517,9 @@ // check that array length is small enough for fast path __ set(C1_MacroAssembler::max_array_allocation_length, G3_t1); - __ cmp_and_br_short(G4_length, G3_t1, Assembler::greaterUnsigned, Assembler::pn, slow_path); + __ cmp(G4_length, G3_t1); + __ br(Assembler::greaterUnsigned, false, Assembler::pn, slow_path); + __ delayed()->nop(); // if we got here then the TLAB allocation failed, so try // refilling the TLAB or allocating directly from eden. @@ -1076,6 +1080,25 @@ __ verify_not_null_oop(Oexception); +#ifdef ASSERT + // check that fields in JavaThread for exception oop and issuing pc are + // empty before writing to them + Label oop_empty; + Register scratch = I7; // We can use I7 here because it's overwritten later anyway. + __ ld_ptr(Address(G2_thread, JavaThread::exception_oop_offset()), scratch); + __ br_null(scratch, false, Assembler::pt, oop_empty); + __ delayed()->nop(); + __ stop("exception oop already set"); + __ bind(oop_empty); + + Label pc_empty; + __ ld_ptr(Address(G2_thread, JavaThread::exception_pc_offset()), scratch); + __ br_null(scratch, false, Assembler::pt, pc_empty); + __ delayed()->nop(); + __ stop("exception pc already set"); + __ bind(pc_empty); +#endif + // save the exception and issuing pc in the thread __ st_ptr(Oexception, G2_thread, in_bytes(JavaThread::exception_oop_offset())); __ st_ptr(Oissuing_pc, G2_thread, in_bytes(JavaThread::exception_pc_offset())); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/sparc/vm/globals_sparc.hpp --- a/src/cpu/sparc/vm/globals_sparc.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/sparc/vm/globals_sparc.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -76,6 +76,8 @@ // GC Ergo Flags define_pd_global(uintx, CMSYoungGenPerWorker, 16*M); // default max size of CMS young gen, per GC worker thread +define_pd_global(uintx, TypeProfileLevel, 0); + #define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \ \ product(intx, UseVIS, 99, \ diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/sparc/vm/macroAssembler_sparc.cpp --- a/src/cpu/sparc/vm/macroAssembler_sparc.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/sparc/vm/macroAssembler_sparc.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -3333,7 +3333,8 @@ if (CMSIncrementalMode || !Universe::heap()->supports_inline_contig_alloc()) { // No allocation in the shared eden. - ba_short(slow_case); + ba(slow_case); + delayed()->nop(); } ld_ptr(G2_thread, in_bytes(JavaThread::tlab_top_offset()), top); @@ -3358,7 +3359,8 @@ add(t2, 1, t2); stw(t2, G2_thread, in_bytes(JavaThread::tlab_slow_allocations_offset())); } - ba_short(try_eden); + ba(try_eden); + delayed()->nop(); bind(discard_tlab); if (TLABStats) { @@ -3420,7 +3422,8 @@ sub(top, ThreadLocalAllocBuffer::alignment_reserve_in_bytes(), top); st_ptr(top, G2_thread, in_bytes(JavaThread::tlab_end_offset())); verify_tlab(); - ba_short(retry); + ba(retry); + delayed()->nop(); } void MacroAssembler::incr_allocated_bytes(RegisterOrConstant size_in_bytes, diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/sparc/vm/sharedRuntime_sparc.cpp --- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -3581,6 +3581,7 @@ // the pending exception will be picked up the interpreter. __ ld_ptr(G2_thread, in_bytes(JavaThread::exception_oop_offset()), Oexception); __ st_ptr(G0, G2_thread, in_bytes(JavaThread::exception_oop_offset())); + __ st_ptr(G0, G2_thread, in_bytes(JavaThread::exception_pc_offset())); __ bind(noException); // deallocate the deoptimization frame taking care to preserve the return values diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/sparc/vm/sparc.ad --- a/src/cpu/sparc/vm/sparc.ad Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/sparc/vm/sparc.ad Sun Nov 03 07:50:24 2013 +0000 @@ -2022,6 +2022,10 @@ return G1_REGI_mask(); } +const RegMask Matcher::mathExactL_result_proj_mask() { + return G1_REGL_mask(); +} + const RegMask Matcher::mathExactI_flags_proj_mask() { return INT_FLAGS_mask(); } diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/x86/vm/assembler_x86.cpp --- a/src/cpu/x86/vm/assembler_x86.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/x86/vm/assembler_x86.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -1405,6 +1405,15 @@ } } +void Assembler::imull(Register dst, Address src) { + InstructionMark im(this); + prefix(src, dst); + emit_int8(0x0F); + emit_int8((unsigned char) 0xAF); + emit_operand(dst, src); +} + + void Assembler::incl(Address dst) { // Don't use it directly. Use MacroAssembler::increment() instead. InstructionMark im(this); @@ -5024,6 +5033,14 @@ } } +void Assembler::imulq(Register dst, Address src) { + InstructionMark im(this); + prefixq(src, dst); + emit_int8(0x0F); + emit_int8((unsigned char) 0xAF); + emit_operand(dst, src); +} + void Assembler::incl(Register dst) { // Don't use it directly. Use MacroAssembler::incrementl() instead. // Use two-byte form (one-byte from is a REX prefix in 64-bit mode) diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/x86/vm/assembler_x86.hpp --- a/src/cpu/x86/vm/assembler_x86.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/x86/vm/assembler_x86.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -1162,9 +1162,13 @@ void imull(Register dst, Register src); void imull(Register dst, Register src, int value); + void imull(Register dst, Address src); void imulq(Register dst, Register src); void imulq(Register dst, Register src, int value); +#ifdef _LP64 + void imulq(Register dst, Address src); +#endif // jcc is the generic conditional branch generator to run- diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/x86/vm/bytecodeInterpreter_x86.cpp --- a/src/cpu/x86/vm/bytecodeInterpreter_x86.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/x86/vm/bytecodeInterpreter_x86.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -40,11 +40,8 @@ #include "runtime/synchronizer.hpp" #include "runtime/vframeArray.hpp" #include "utilities/debug.hpp" -#ifdef TARGET_ARCH_MODEL_x86_32 -# include "interp_masm_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 -# include "interp_masm_x86_64.hpp" +#ifdef TARGET_ARCH_x86 +# include "interp_masm_x86.hpp" #endif #ifdef CC_INTERP diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/x86/vm/c1_FrameMap_x86.cpp --- a/src/cpu/x86/vm/c1_FrameMap_x86.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/x86/vm/c1_FrameMap_x86.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -52,6 +52,8 @@ #endif // _LP64 } else if (type == T_OBJECT || type == T_ARRAY) { opr = as_oop_opr(reg); + } else if (type == T_METADATA) { + opr = as_metadata_opr(reg); } else { opr = as_opr(reg); } diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/x86/vm/c1_LIRAssembler_x86.cpp --- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -432,15 +432,16 @@ int offset = code_offset(); // Fetch the exception from TLS and clear out exception related thread state - __ get_thread(rsi); - __ movptr(rax, Address(rsi, JavaThread::exception_oop_offset())); - __ movptr(Address(rsi, JavaThread::exception_oop_offset()), (intptr_t)NULL_WORD); - __ movptr(Address(rsi, JavaThread::exception_pc_offset()), (intptr_t)NULL_WORD); + Register thread = NOT_LP64(rsi) LP64_ONLY(r15_thread); + NOT_LP64(__ get_thread(rsi)); + __ movptr(rax, Address(thread, JavaThread::exception_oop_offset())); + __ movptr(Address(thread, JavaThread::exception_oop_offset()), (intptr_t)NULL_WORD); + __ movptr(Address(thread, JavaThread::exception_pc_offset()), (intptr_t)NULL_WORD); __ bind(_unwind_handler_entry); __ verify_not_null_oop(rax); if (method()->is_synchronized() || compilation()->env()->dtrace_method_probes()) { - __ mov(rsi, rax); // Preserve the exception + __ mov(rbx, rax); // Preserve the exception (rbx is always callee-saved) } // Preform needed unlocking @@ -448,19 +449,24 @@ if (method()->is_synchronized()) { monitor_address(0, FrameMap::rax_opr); stub = new MonitorExitStub(FrameMap::rax_opr, true, 0); - __ unlock_object(rdi, rbx, rax, *stub->entry()); + __ unlock_object(rdi, rsi, rax, *stub->entry()); __ bind(*stub->continuation()); } if (compilation()->env()->dtrace_method_probes()) { +#ifdef _LP64 + __ mov(rdi, r15_thread); + __ mov_metadata(rsi, method()->constant_encoding()); +#else __ get_thread(rax); __ movptr(Address(rsp, 0), rax); __ mov_metadata(Address(rsp, sizeof(void*)), method()->constant_encoding()); +#endif __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit))); } if (method()->is_synchronized() || compilation()->env()->dtrace_method_probes()) { - __ mov(rax, rsi); // Restore the exception + __ mov(rax, rbx); // Restore the exception } // remove the activation and dispatch to the unwind handler @@ -1206,6 +1212,10 @@ LIR_Address* addr = src->as_address_ptr(); Address from_addr = as_Address(addr); + if (addr->base()->type() == T_OBJECT) { + __ verify_oop(addr->base()->as_pointer_register()); + } + switch (type) { case T_BOOLEAN: // fall through case T_BYTE: // fall through @@ -3632,6 +3642,161 @@ } } +void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { + Register obj = op->obj()->as_register(); + Register tmp = op->tmp()->as_pointer_register(); + Address mdo_addr = as_Address(op->mdp()->as_address_ptr()); + ciKlass* exact_klass = op->exact_klass(); + intptr_t current_klass = op->current_klass(); + bool not_null = op->not_null(); + bool no_conflict = op->no_conflict(); + + Label update, next, none; + + bool do_null = !not_null; + bool exact_klass_set = exact_klass != NULL && ciTypeEntries::valid_ciklass(current_klass) == exact_klass; + bool do_update = !TypeEntries::is_type_unknown(current_klass) && !exact_klass_set; + + assert(do_null || do_update, "why are we here?"); + assert(!TypeEntries::was_null_seen(current_klass) || do_update, "why are we here?"); + + __ verify_oop(obj); + + if (tmp != obj) { + __ mov(tmp, obj); + } + if (do_null) { + __ testptr(tmp, tmp); + __ jccb(Assembler::notZero, update); + if (!TypeEntries::was_null_seen(current_klass)) { + __ orptr(mdo_addr, TypeEntries::null_seen); + } + if (do_update) { +#ifndef ASSERT + __ jmpb(next); + } +#else + __ jmp(next); + } + } else { + __ testptr(tmp, tmp); + __ jccb(Assembler::notZero, update); + __ stop("unexpect null obj"); +#endif + } + + __ bind(update); + + if (do_update) { +#ifdef ASSERT + if (exact_klass != NULL) { + Label ok; + __ load_klass(tmp, tmp); + __ push(tmp); + __ mov_metadata(tmp, exact_klass->constant_encoding()); + __ cmpptr(tmp, Address(rsp, 0)); + __ jccb(Assembler::equal, ok); + __ stop("exact klass and actual klass differ"); + __ bind(ok); + __ pop(tmp); + } +#endif + if (!no_conflict) { + if (exact_klass == NULL || TypeEntries::is_type_none(current_klass)) { + if (exact_klass != NULL) { + __ mov_metadata(tmp, exact_klass->constant_encoding()); + } else { + __ load_klass(tmp, tmp); + } + + __ xorptr(tmp, mdo_addr); + __ testptr(tmp, TypeEntries::type_klass_mask); + // klass seen before, nothing to do. The unknown bit may have been + // set already but no need to check. + __ jccb(Assembler::zero, next); + + __ testptr(tmp, TypeEntries::type_unknown); + __ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore. + + if (TypeEntries::is_type_none(current_klass)) { + __ cmpptr(mdo_addr, 0); + __ jccb(Assembler::equal, none); + __ cmpptr(mdo_addr, TypeEntries::null_seen); + __ jccb(Assembler::equal, none); + // There is a chance that the checks above (re-reading profiling + // data from memory) fail if another thread has just set the + // profiling to this obj's klass + __ xorptr(tmp, mdo_addr); + __ testptr(tmp, TypeEntries::type_klass_mask); + __ jccb(Assembler::zero, next); + } + } else { + assert(ciTypeEntries::valid_ciklass(current_klass) != NULL && + ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "conflict only"); + + __ movptr(tmp, mdo_addr); + __ testptr(tmp, TypeEntries::type_unknown); + __ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore. + } + + // different than before. Cannot keep accurate profile. + __ orptr(mdo_addr, TypeEntries::type_unknown); + + if (TypeEntries::is_type_none(current_klass)) { + __ jmpb(next); + + __ bind(none); + // first time here. Set profile type. + __ movptr(mdo_addr, tmp); + } + } else { + // There's a single possible klass at this profile point + assert(exact_klass != NULL, "should be"); + if (TypeEntries::is_type_none(current_klass)) { + __ mov_metadata(tmp, exact_klass->constant_encoding()); + __ xorptr(tmp, mdo_addr); + __ testptr(tmp, TypeEntries::type_klass_mask); +#ifdef ASSERT + __ jcc(Assembler::zero, next); + + { + Label ok; + __ push(tmp); + __ cmpptr(mdo_addr, 0); + __ jcc(Assembler::equal, ok); + __ cmpptr(mdo_addr, TypeEntries::null_seen); + __ jcc(Assembler::equal, ok); + // may have been set by another thread + __ mov_metadata(tmp, exact_klass->constant_encoding()); + __ xorptr(tmp, mdo_addr); + __ testptr(tmp, TypeEntries::type_mask); + __ jcc(Assembler::zero, ok); + + __ stop("unexpected profiling mismatch"); + __ bind(ok); + __ pop(tmp); + } +#else + __ jccb(Assembler::zero, next); +#endif + // first time here. Set profile type. + __ movptr(mdo_addr, tmp); + } else { + assert(ciTypeEntries::valid_ciklass(current_klass) != NULL && + ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "inconsistent"); + + __ movptr(tmp, mdo_addr); + __ testptr(tmp, TypeEntries::type_unknown); + __ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore. + + __ orptr(mdo_addr, TypeEntries::type_unknown); + } + } + + __ bind(next); + } +} + void LIR_Assembler::emit_delay(LIR_OpDelay*) { Unimplemented(); } diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/x86/vm/globals_x86.hpp --- a/src/cpu/x86/vm/globals_x86.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/x86/vm/globals_x86.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -79,6 +79,8 @@ // GC Ergo Flags define_pd_global(uintx, CMSYoungGenPerWorker, 64*M); // default max size of CMS young gen, per GC worker thread +define_pd_global(uintx, TypeProfileLevel, 111); + #define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \ \ develop(bool, IEEEPrecision, true, \ diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/x86/vm/interp_masm_x86.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cpu/x86/vm/interp_masm_x86.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,229 @@ +/* + * Copyright (c) 1997, 2013, 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 "interp_masm_x86.hpp" +#include "interpreter/interpreter.hpp" +#include "oops/methodData.hpp" + +#ifndef CC_INTERP +void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) { + Label update, next, none; + + verify_oop(obj); + + testptr(obj, obj); + jccb(Assembler::notZero, update); + orptr(mdo_addr, TypeEntries::null_seen); + jmpb(next); + + bind(update); + load_klass(obj, obj); + + xorptr(obj, mdo_addr); + testptr(obj, TypeEntries::type_klass_mask); + jccb(Assembler::zero, next); // klass seen before, nothing to + // do. The unknown bit may have been + // set already but no need to check. + + testptr(obj, TypeEntries::type_unknown); + jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore. + + cmpptr(mdo_addr, 0); + jccb(Assembler::equal, none); + cmpptr(mdo_addr, TypeEntries::null_seen); + jccb(Assembler::equal, none); + // There is a chance that the checks above (re-reading profiling + // data from memory) fail if another thread has just set the + // profiling to this obj's klass + xorptr(obj, mdo_addr); + testptr(obj, TypeEntries::type_klass_mask); + jccb(Assembler::zero, next); + + // different than before. Cannot keep accurate profile. + orptr(mdo_addr, TypeEntries::type_unknown); + jmpb(next); + + bind(none); + // first time here. Set profile type. + movptr(mdo_addr, obj); + + bind(next); +} + +void InterpreterMacroAssembler::profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual) { + if (!ProfileInterpreter) { + return; + } + + if (MethodData::profile_arguments() || MethodData::profile_return()) { + Label profile_continue; + + test_method_data_pointer(mdp, profile_continue); + + int off_to_start = is_virtual ? in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size()); + + cmpb(Address(mdp, in_bytes(DataLayout::tag_offset()) - off_to_start), is_virtual ? DataLayout::virtual_call_type_data_tag : DataLayout::call_type_data_tag); + jcc(Assembler::notEqual, profile_continue); + + if (MethodData::profile_arguments()) { + Label done; + int off_to_args = in_bytes(TypeEntriesAtCall::args_data_offset()); + addptr(mdp, off_to_args); + + for (int i = 0; i < TypeProfileArgsLimit; i++) { + if (i > 0 || MethodData::profile_return()) { + // If return value type is profiled we may have no argument to profile + movptr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args)); + subl(tmp, i*TypeStackSlotEntries::per_arg_count()); + cmpl(tmp, TypeStackSlotEntries::per_arg_count()); + jcc(Assembler::less, done); + } + movptr(tmp, Address(callee, Method::const_offset())); + load_unsigned_short(tmp, Address(tmp, ConstMethod::size_of_parameters_offset())); + // stack offset o (zero based) from the start of the argument + // list, for n arguments translates into offset n - o - 1 from + // the end of the argument list + subptr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::stack_slot_offset(i))-off_to_args)); + subl(tmp, 1); + Address arg_addr = argument_address(tmp); + movptr(tmp, arg_addr); + + Address mdo_arg_addr(mdp, in_bytes(TypeEntriesAtCall::argument_type_offset(i))-off_to_args); + profile_obj_type(tmp, mdo_arg_addr); + + int to_add = in_bytes(TypeStackSlotEntries::per_arg_size()); + addptr(mdp, to_add); + off_to_args += to_add; + } + + if (MethodData::profile_return()) { + movptr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args)); + subl(tmp, TypeProfileArgsLimit*TypeStackSlotEntries::per_arg_count()); + } + + bind(done); + + if (MethodData::profile_return()) { + // We're right after the type profile for the last + // argument. tmp is the number of cell left in the + // CallTypeData/VirtualCallTypeData to reach its end. Non null + // if there's a return to profile. + assert(ReturnTypeEntry::static_cell_count() < TypeStackSlotEntries::per_arg_count(), "can't move past ret type"); + shll(tmp, exact_log2(DataLayout::cell_size)); + addptr(mdp, tmp); + } + movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), mdp); + } else { + assert(MethodData::profile_return(), "either profile call args or call ret"); + update_mdp_by_constant(mdp, in_bytes(ReturnTypeEntry::size())); + } + + // mdp points right after the end of the + // CallTypeData/VirtualCallTypeData, right after the cells for the + // return value type if there's one + + bind(profile_continue); + } +} + +void InterpreterMacroAssembler::profile_return_type(Register mdp, Register ret, Register tmp) { + assert_different_registers(mdp, ret, tmp, _bcp_register); + if (ProfileInterpreter && MethodData::profile_return()) { + Label profile_continue, done; + + test_method_data_pointer(mdp, profile_continue); + + if (MethodData::profile_return_jsr292_only()) { + // If we don't profile all invoke bytecodes we must make sure + // it's a bytecode we indeed profile. We can't go back to the + // begining of the ProfileData we intend to update to check its + // type because we're right after it and we don't known its + // length + Label do_profile; + cmpb(Address(_bcp_register, 0), Bytecodes::_invokedynamic); + jcc(Assembler::equal, do_profile); + cmpb(Address(_bcp_register, 0), Bytecodes::_invokehandle); + jcc(Assembler::equal, do_profile); + get_method(tmp); + cmpb(Address(tmp, Method::intrinsic_id_offset_in_bytes()), vmIntrinsics::_compiledLambdaForm); + jcc(Assembler::notEqual, profile_continue); + + bind(do_profile); + } + + Address mdo_ret_addr(mdp, -in_bytes(ReturnTypeEntry::size())); + mov(tmp, ret); + profile_obj_type(tmp, mdo_ret_addr); + + bind(profile_continue); + } +} + +void InterpreterMacroAssembler::profile_parameters_type(Register mdp, Register tmp1, Register tmp2) { + if (ProfileInterpreter && MethodData::profile_parameters()) { + Label profile_continue, done; + + test_method_data_pointer(mdp, profile_continue); + + // Load the offset of the area within the MDO used for + // parameters. If it's negative we're not profiling any parameters + movl(tmp1, Address(mdp, in_bytes(MethodData::parameters_type_data_di_offset()) - in_bytes(MethodData::data_offset()))); + testl(tmp1, tmp1); + jcc(Assembler::negative, profile_continue); + + // Compute a pointer to the area for parameters from the offset + // and move the pointer to the slot for the last + // parameters. Collect profiling from last parameter down. + // mdo start + parameters offset + array length - 1 + addptr(mdp, tmp1); + movptr(tmp1, Address(mdp, in_bytes(ArrayData::array_len_offset()))); + decrement(tmp1, TypeStackSlotEntries::per_arg_count()); + + Label loop; + bind(loop); + + int off_base = in_bytes(ParametersTypeData::stack_slot_offset(0)); + int type_base = in_bytes(ParametersTypeData::type_offset(0)); + Address::ScaleFactor per_arg_scale = Address::times(DataLayout::cell_size); + Address arg_off(mdp, tmp1, per_arg_scale, off_base); + Address arg_type(mdp, tmp1, per_arg_scale, type_base); + + // load offset on the stack from the slot for this parameter + movptr(tmp2, arg_off); + negptr(tmp2); + // read the parameter from the local area + movptr(tmp2, Address(_locals_register, tmp2, Interpreter::stackElementScale())); + + // profile the parameter + profile_obj_type(tmp2, arg_type); + + // go to next parameter + decrement(tmp1, TypeStackSlotEntries::per_arg_count()); + jcc(Assembler::positive, loop); + + bind(profile_continue); + } +} +#endif diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/x86/vm/interp_masm_x86.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cpu/x86/vm/interp_masm_x86.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013, 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 CPU_X86_VM_INTERP_MASM_X86_HPP +#define CPU_X86_VM_INTERP_MASM_X86_HPP + +#include "asm/macroAssembler.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "interpreter/invocationCounter.hpp" +#include "runtime/frame.hpp" + +// This file specializes the assember with interpreter-specific macros + + +class InterpreterMacroAssembler: public MacroAssembler { + +#ifdef TARGET_ARCH_MODEL_x86_32 +# include "interp_masm_x86_32.hpp" +#endif +#ifdef TARGET_ARCH_MODEL_x86_64 +# include "interp_masm_x86_64.hpp" +#endif + + private: + + Register _locals_register; // register that contains the pointer to the locals + Register _bcp_register; // register that contains the bcp + + public: +#ifndef CC_INTERP + void profile_obj_type(Register obj, const Address& mdo_addr); + void profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual); + void profile_return_type(Register mdp, Register ret, Register tmp); + void profile_parameters_type(Register mdp, Register tmp1, Register tmp2); +#endif /* !CC_INTERP */ + +}; + +#endif // CPU_X86_VM_INTERP_MASM_X86_HPP diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/x86/vm/interp_masm_x86_32.cpp --- a/src/cpu/x86/vm/interp_masm_x86_32.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/x86/vm/interp_masm_x86_32.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -23,7 +23,7 @@ */ #include "precompiled.hpp" -#include "interp_masm_x86_32.hpp" +#include "interp_masm_x86.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" #include "oops/arrayOop.hpp" @@ -1046,7 +1046,6 @@ } } - void InterpreterMacroAssembler::profile_call(Register mdp) { if (ProfileInterpreter) { Label profile_continue; diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/x86/vm/interp_masm_x86_32.hpp --- a/src/cpu/x86/vm/interp_masm_x86_32.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/x86/vm/interp_masm_x86_32.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -22,18 +22,6 @@ * */ -#ifndef CPU_X86_VM_INTERP_MASM_X86_32_HPP -#define CPU_X86_VM_INTERP_MASM_X86_32_HPP - -#include "asm/macroAssembler.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "interpreter/invocationCounter.hpp" -#include "runtime/frame.hpp" - -// This file specializes the assember with interpreter-specific macros - - -class InterpreterMacroAssembler: public MacroAssembler { #ifndef CC_INTERP protected: // Interpreter specific version of call_VM_base @@ -59,7 +47,7 @@ #endif /* CC_INTERP */ public: - InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code) {} + InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code), _locals_register(rdi), _bcp_register(rsi) {} void load_earlyret_value(TosState state); @@ -233,7 +221,3 @@ // support for jvmti void notify_method_entry(); void notify_method_exit(TosState state, NotifyMethodExitMode mode); - -}; - -#endif // CPU_X86_VM_INTERP_MASM_X86_32_HPP diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/x86/vm/interp_masm_x86_64.cpp --- a/src/cpu/x86/vm/interp_masm_x86_64.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/x86/vm/interp_masm_x86_64.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -23,7 +23,7 @@ */ #include "precompiled.hpp" -#include "interp_masm_x86_64.hpp" +#include "interp_masm_x86.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" #include "oops/arrayOop.hpp" @@ -1067,7 +1067,6 @@ } } - void InterpreterMacroAssembler::profile_call(Register mdp) { if (ProfileInterpreter) { Label profile_continue; diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/x86/vm/interp_masm_x86_64.hpp --- a/src/cpu/x86/vm/interp_masm_x86_64.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/x86/vm/interp_masm_x86_64.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -22,18 +22,6 @@ * */ -#ifndef CPU_X86_VM_INTERP_MASM_X86_64_HPP -#define CPU_X86_VM_INTERP_MASM_X86_64_HPP - -#include "asm/macroAssembler.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "interpreter/invocationCounter.hpp" -#include "runtime/frame.hpp" - -// This file specializes the assember with interpreter-specific macros - - -class InterpreterMacroAssembler: public MacroAssembler { #ifndef CC_INTERP protected: // Interpreter specific version of call_VM_base @@ -55,7 +43,7 @@ #endif // CC_INTERP public: - InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code) {} + InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code), _locals_register(r14), _bcp_register(r13) {} void load_earlyret_value(TosState state); @@ -250,6 +238,3 @@ // support for jvmti/dtrace void notify_method_entry(); void notify_method_exit(TosState state, NotifyMethodExitMode mode); -}; - -#endif // CPU_X86_VM_INTERP_MASM_X86_64_HPP diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/x86/vm/macroAssembler_x86.hpp --- a/src/cpu/x86/vm/macroAssembler_x86.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/x86/vm/macroAssembler_x86.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -773,6 +773,7 @@ void orptr(Register dst, Address src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); } void orptr(Register dst, Register src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); } void orptr(Register dst, int32_t src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); } + void orptr(Address dst, int32_t imm32) { LP64_ONLY(orq(dst, imm32)) NOT_LP64(orl(dst, imm32)); } void testptr(Register src, int32_t imm32) { LP64_ONLY(testq(src, imm32)) NOT_LP64(testl(src, imm32)); } void testptr(Register src1, Register src2); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/x86/vm/register_definitions_x86.cpp --- a/src/cpu/x86/vm/register_definitions_x86.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/x86/vm/register_definitions_x86.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -26,11 +26,8 @@ #include "asm/assembler.hpp" #include "asm/register.hpp" #include "register_x86.hpp" -#ifdef TARGET_ARCH_MODEL_x86_32 -# include "interp_masm_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 -# include "interp_masm_x86_64.hpp" +#ifdef TARGET_ARCH_x86 +# include "interp_masm_x86.hpp" #endif REGISTER_DEFINITION(Register, noreg); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/x86/vm/templateInterpreter_x86.hpp --- a/src/cpu/x86/vm/templateInterpreter_x86.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/x86/vm/templateInterpreter_x86.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -34,9 +34,9 @@ // Run with +PrintInterpreter to get the VM to print out the size. // Max size with JVMTI #ifdef AMD64 - const static int InterpreterCodeSize = 208 * 1024; + const static int InterpreterCodeSize = 256 * 1024; #else - const static int InterpreterCodeSize = 176 * 1024; + const static int InterpreterCodeSize = 224 * 1024; #endif // AMD64 #endif // CPU_X86_VM_TEMPLATEINTERPRETER_X86_HPP diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/x86/vm/templateInterpreter_x86_32.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -194,6 +194,12 @@ __ restore_bcp(); __ restore_locals(); + if (incoming_state == atos) { + Register mdp = rbx; + Register tmp = rcx; + __ profile_return_type(mdp, rax, tmp); + } + Label L_got_cache, L_giant_index; if (EnableInvokeDynamic) { __ cmpb(Address(rsi, 0), Bytecodes::_invokedynamic); @@ -1484,6 +1490,7 @@ in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); __ movbool(do_not_unlock_if_synchronized, true); + __ profile_parameters_type(rax, rcx, rdx); // increment invocation count & check for overflow Label invocation_counter_overflow; Label profile_method; diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/x86/vm/templateInterpreter_x86_64.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -177,6 +177,12 @@ __ restore_bcp(); __ restore_locals(); + if (state == atos) { + Register mdp = rbx; + Register tmp = rcx; + __ profile_return_type(mdp, rax, tmp); + } + Label L_got_cache, L_giant_index; if (EnableInvokeDynamic) { __ cmpb(Address(r13, 0), Bytecodes::_invokedynamic); @@ -1491,6 +1497,7 @@ in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); __ movbool(do_not_unlock_if_synchronized, true); + __ profile_parameters_type(rax, rcx, rdx); // increment invocation count & check for overflow Label invocation_counter_overflow; Label profile_method; diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/x86/vm/templateTable_x86_32.cpp --- a/src/cpu/x86/vm/templateTable_x86_32.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/x86/vm/templateTable_x86_32.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -2970,6 +2970,7 @@ // profile this call __ profile_final_call(rax); + __ profile_arguments_type(rax, method, rsi, true); __ jump_from_interpreted(method, rax); @@ -2984,6 +2985,7 @@ // get target Method* & entry point __ lookup_virtual_method(rax, index, method); + __ profile_arguments_type(rdx, method, rsi, true); __ jump_from_interpreted(method, rdx); } @@ -3013,6 +3015,7 @@ __ null_check(rcx); // do the call __ profile_call(rax); + __ profile_arguments_type(rax, rbx, rsi, false); __ jump_from_interpreted(rbx, rax); } @@ -3023,6 +3026,7 @@ prepare_invoke(byte_no, rbx); // get f1 Method* // do the call __ profile_call(rax); + __ profile_arguments_type(rax, rbx, rsi, false); __ jump_from_interpreted(rbx, rax); } @@ -3082,6 +3086,8 @@ __ testptr(rbx, rbx); __ jcc(Assembler::zero, no_such_method); + __ profile_arguments_type(rdx, rbx, rsi, true); + // do the call // rcx: receiver // rbx,: Method* @@ -3138,6 +3144,7 @@ // FIXME: profile the LambdaForm also __ profile_final_call(rax); + __ profile_arguments_type(rdx, rbx_method, rsi, true); __ jump_from_interpreted(rbx_method, rdx); } @@ -3171,6 +3178,7 @@ // %%% should make a type profile for any invokedynamic that takes a ref argument // profile this call __ profile_call(rsi); + __ profile_arguments_type(rdx, rbx, rsi, false); __ verify_oop(rax_callsite); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/x86/vm/templateTable_x86_64.cpp --- a/src/cpu/x86/vm/templateTable_x86_64.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/x86/vm/templateTable_x86_64.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -3026,6 +3026,7 @@ // profile this call __ profile_final_call(rax); + __ profile_arguments_type(rax, method, r13, true); __ jump_from_interpreted(method, rax); @@ -3040,6 +3041,7 @@ // get target Method* & entry point __ lookup_virtual_method(rax, index, method); + __ profile_arguments_type(rdx, method, r13, true); __ jump_from_interpreted(method, rdx); } @@ -3069,6 +3071,7 @@ __ null_check(rcx); // do the call __ profile_call(rax); + __ profile_arguments_type(rax, rbx, r13, false); __ jump_from_interpreted(rbx, rax); } @@ -3079,6 +3082,7 @@ prepare_invoke(byte_no, rbx); // get f1 Method* // do the call __ profile_call(rax); + __ profile_arguments_type(rax, rbx, r13, false); __ jump_from_interpreted(rbx, rax); } @@ -3136,6 +3140,8 @@ __ testptr(rbx, rbx); __ jcc(Assembler::zero, no_such_method); + __ profile_arguments_type(rdx, rbx, r13, true); + // do the call // rcx: receiver // rbx,: Method* @@ -3193,6 +3199,7 @@ // FIXME: profile the LambdaForm also __ profile_final_call(rax); + __ profile_arguments_type(rdx, rbx_method, r13, true); __ jump_from_interpreted(rbx_method, rdx); } @@ -3226,6 +3233,7 @@ // %%% should make a type profile for any invokedynamic that takes a ref argument // profile this call __ profile_call(r13); + __ profile_arguments_type(rdx, rbx_method, r13, false); __ verify_oop(rax_callsite); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/x86/vm/vtableStubs_x86_32.cpp --- a/src/cpu/x86/vm/vtableStubs_x86_32.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/x86/vm/vtableStubs_x86_32.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -25,7 +25,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" #include "code/vtableStubs.hpp" -#include "interp_masm_x86_32.hpp" +#include "interp_masm_x86.hpp" #include "memory/resourceArea.hpp" #include "oops/instanceKlass.hpp" #include "oops/klassVtable.hpp" diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/x86/vm/vtableStubs_x86_64.cpp --- a/src/cpu/x86/vm/vtableStubs_x86_64.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/x86/vm/vtableStubs_x86_64.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -25,7 +25,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" #include "code/vtableStubs.hpp" -#include "interp_masm_x86_64.hpp" +#include "interp_masm_x86.hpp" #include "memory/resourceArea.hpp" #include "oops/instanceKlass.hpp" #include "oops/klassVtable.hpp" diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/x86/vm/x86_32.ad --- a/src/cpu/x86/vm/x86_32.ad Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/x86/vm/x86_32.ad Sun Nov 03 07:50:24 2013 +0000 @@ -1538,6 +1538,11 @@ return EAX_REG_mask(); } +const RegMask Matcher::mathExactL_result_proj_mask() { + ShouldNotReachHere(); + return RegMask(); +} + const RegMask Matcher::mathExactI_flags_proj_mask() { return INT_FLAGS_mask(); } @@ -7519,7 +7524,7 @@ //----------Arithmetic Instructions-------------------------------------------- //----------Addition Instructions---------------------------------------------- -instruct addExactI_rReg(eAXRegI dst, rRegI src, eFlagsReg cr) +instruct addExactI_eReg(eAXRegI dst, rRegI src, eFlagsReg cr) %{ match(AddExactI dst src); effect(DEF cr); @@ -7531,7 +7536,7 @@ ins_pipe(ialu_reg_reg); %} -instruct addExactI_rReg_imm(eAXRegI dst, immI src, eFlagsReg cr) +instruct addExactI_eReg_imm(eAXRegI dst, immI src, eFlagsReg cr) %{ match(AddExactI dst src); effect(DEF cr); @@ -7543,6 +7548,20 @@ ins_pipe(ialu_reg_reg); %} +instruct addExactI_eReg_mem(eAXRegI dst, memory src, eFlagsReg cr) +%{ + match(AddExactI dst (LoadI src)); + effect(DEF cr); + + ins_cost(125); + format %{ "ADD $dst,$src\t# addExact int" %} + ins_encode %{ + __ addl($dst$$Register, $src$$Address); + %} + ins_pipe( ialu_reg_mem ); +%} + + // Integer Addition Instructions instruct addI_eReg(rRegI dst, rRegI src, eFlagsReg cr) %{ match(Set dst (AddI dst src)); @@ -7851,6 +7870,44 @@ %} //----------Subtraction Instructions------------------------------------------- + +instruct subExactI_eReg(eAXRegI dst, rRegI src, eFlagsReg cr) +%{ + match(SubExactI dst src); + effect(DEF cr); + + format %{ "SUB $dst, $src\t# subExact int" %} + ins_encode %{ + __ subl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct subExactI_eReg_imm(eAXRegI dst, immI src, eFlagsReg cr) +%{ + match(SubExactI dst src); + effect(DEF cr); + + format %{ "SUB $dst, $src\t# subExact int" %} + ins_encode %{ + __ subl($dst$$Register, $src$$constant); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct subExactI_eReg_mem(eAXRegI dst, memory src, eFlagsReg cr) +%{ + match(SubExactI dst (LoadI src)); + effect(DEF cr); + + ins_cost(125); + format %{ "SUB $dst,$src\t# subExact int" %} + ins_encode %{ + __ subl($dst$$Register, $src$$Address); + %} + ins_pipe( ialu_reg_mem ); +%} + // Integer Subtraction Instructions instruct subI_eReg(rRegI dst, rRegI src, eFlagsReg cr) %{ match(Set dst (SubI dst src)); @@ -7919,6 +7976,16 @@ ins_pipe( ialu_reg ); %} +instruct negExactI_eReg(eAXRegI dst, eFlagsReg cr) %{ + match(NegExactI dst); + effect(DEF cr); + + format %{ "NEG $dst\t# negExact int"%} + ins_encode %{ + __ negl($dst$$Register); + %} + ins_pipe(ialu_reg); +%} //----------Multiplication/Division Instructions------------------------------- // Integer Multiplication Instructions @@ -8131,6 +8198,46 @@ ins_pipe( pipe_slow ); %} +instruct mulExactI_eReg(eAXRegI dst, rRegI src, eFlagsReg cr) +%{ + match(MulExactI dst src); + effect(DEF cr); + + ins_cost(300); + format %{ "IMUL $dst, $src\t# mulExact int" %} + ins_encode %{ + __ imull($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg_alu0); +%} + +instruct mulExactI_eReg_imm(eAXRegI dst, rRegI src, immI imm, eFlagsReg cr) +%{ + match(MulExactI src imm); + effect(DEF cr); + + ins_cost(300); + format %{ "IMUL $dst, $src, $imm\t# mulExact int" %} + ins_encode %{ + __ imull($dst$$Register, $src$$Register, $imm$$constant); + %} + ins_pipe(ialu_reg_reg_alu0); +%} + +instruct mulExactI_eReg_mem(eAXRegI dst, memory src, eFlagsReg cr) +%{ + match(MulExactI dst (LoadI src)); + effect(DEF cr); + + ins_cost(350); + format %{ "IMUL $dst, $src\t# mulExact int" %} + ins_encode %{ + __ imull($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem_alu0); +%} + + // Integer DIV with Register instruct divI_eReg(eAXRegI rax, eDXRegI rdx, eCXRegI div, eFlagsReg cr) %{ match(Set rax (DivI rax div)); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/cpu/x86/vm/x86_64.ad --- a/src/cpu/x86/vm/x86_64.ad Mon Oct 21 14:08:09 2013 +0100 +++ b/src/cpu/x86/vm/x86_64.ad Sun Nov 03 07:50:24 2013 +0000 @@ -1653,6 +1653,10 @@ return INT_RAX_REG_mask(); } +const RegMask Matcher::mathExactL_result_proj_mask() { + return LONG_RAX_REG_mask(); +} + const RegMask Matcher::mathExactI_flags_proj_mask() { return INT_FLAGS_mask(); } @@ -6962,6 +6966,58 @@ ins_pipe(ialu_reg_reg); %} +instruct addExactI_rReg_mem(rax_RegI dst, memory src, rFlagsReg cr) +%{ + match(AddExactI dst (LoadI src)); + effect(DEF cr); + + ins_cost(125); // XXX + format %{ "addl $dst, $src\t# addExact int" %} + ins_encode %{ + __ addl($dst$$Register, $src$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} + +instruct addExactL_rReg(rax_RegL dst, rRegL src, rFlagsReg cr) +%{ + match(AddExactL dst src); + effect(DEF cr); + + format %{ "addq $dst, $src\t# addExact long" %} + ins_encode %{ + __ addq($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct addExactL_rReg_imm(rax_RegL dst, immL32 src, rFlagsReg cr) +%{ + match(AddExactL dst src); + effect(DEF cr); + + format %{ "addq $dst, $src\t# addExact long" %} + ins_encode %{ + __ addq($dst$$Register, $src$$constant); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct addExactL_rReg_mem(rax_RegL dst, memory src, rFlagsReg cr) +%{ + match(AddExactL dst (LoadL src)); + effect(DEF cr); + + ins_cost(125); // XXX + format %{ "addq $dst, $src\t# addExact long" %} + ins_encode %{ + __ addq($dst$$Register, $src$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} + instruct addI_rReg(rRegI dst, rRegI src, rFlagsReg cr) %{ match(Set dst (AddI dst src)); @@ -7574,6 +7630,80 @@ ins_pipe(ialu_mem_imm); %} +instruct subExactI_rReg(rax_RegI dst, rRegI src, rFlagsReg cr) +%{ + match(SubExactI dst src); + effect(DEF cr); + + format %{ "subl $dst, $src\t# subExact int" %} + ins_encode %{ + __ subl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct subExactI_rReg_imm(rax_RegI dst, immI src, rFlagsReg cr) +%{ + match(SubExactI dst src); + effect(DEF cr); + + format %{ "subl $dst, $src\t# subExact int" %} + ins_encode %{ + __ subl($dst$$Register, $src$$constant); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct subExactI_rReg_mem(rax_RegI dst, memory src, rFlagsReg cr) +%{ + match(SubExactI dst (LoadI src)); + effect(DEF cr); + + ins_cost(125); + format %{ "subl $dst, $src\t# subExact int" %} + ins_encode %{ + __ subl($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct subExactL_rReg(rax_RegL dst, rRegL src, rFlagsReg cr) +%{ + match(SubExactL dst src); + effect(DEF cr); + + format %{ "subq $dst, $src\t# subExact long" %} + ins_encode %{ + __ subq($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct subExactL_rReg_imm(rax_RegL dst, immL32 src, rFlagsReg cr) +%{ + match(SubExactL dst (LoadL src)); + effect(DEF cr); + + format %{ "subq $dst, $src\t# subExact long" %} + ins_encode %{ + __ subq($dst$$Register, $src$$constant); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct subExactL_rReg_mem(rax_RegI dst, memory src, rFlagsReg cr) +%{ + match(SubExactI dst src); + effect(DEF cr); + + ins_cost(125); + format %{ "subq $dst, $src\t# subExact long" %} + ins_encode %{ + __ subq($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + instruct subL_rReg(rRegL dst, rRegL src, rFlagsReg cr) %{ match(Set dst (SubL dst src)); @@ -7690,6 +7820,30 @@ ins_pipe(ialu_reg); %} +instruct negExactI_rReg(rax_RegI dst, rFlagsReg cr) +%{ + match(NegExactI dst); + effect(KILL cr); + + format %{ "negl $dst\t# negExact int" %} + ins_encode %{ + __ negl($dst$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct negExactL_rReg(rax_RegL dst, rFlagsReg cr) +%{ + match(NegExactL dst); + effect(KILL cr); + + format %{ "negq $dst\t# negExact long" %} + ins_encode %{ + __ negq($dst$$Register); + %} + ins_pipe(ialu_reg); +%} + //----------Multiplication/Division Instructions------------------------------- // Integer Multiplication Instructions @@ -7807,6 +7961,86 @@ ins_pipe(ialu_reg_reg_alu0); %} + +instruct mulExactI_rReg(rax_RegI dst, rRegI src, rFlagsReg cr) +%{ + match(MulExactI dst src); + effect(DEF cr); + + ins_cost(300); + format %{ "imull $dst, $src\t# mulExact int" %} + ins_encode %{ + __ imull($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg_alu0); +%} + + +instruct mulExactI_rReg_imm(rax_RegI dst, rRegI src, immI imm, rFlagsReg cr) +%{ + match(MulExactI src imm); + effect(DEF cr); + + ins_cost(300); + format %{ "imull $dst, $src, $imm\t# mulExact int" %} + ins_encode %{ + __ imull($dst$$Register, $src$$Register, $imm$$constant); + %} + ins_pipe(ialu_reg_reg_alu0); +%} + +instruct mulExactI_rReg_mem(rax_RegI dst, memory src, rFlagsReg cr) +%{ + match(MulExactI dst (LoadI src)); + effect(DEF cr); + + ins_cost(350); + format %{ "imull $dst, $src\t# mulExact int" %} + ins_encode %{ + __ imull($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem_alu0); +%} + +instruct mulExactL_rReg(rax_RegL dst, rRegL src, rFlagsReg cr) +%{ + match(MulExactL dst src); + effect(DEF cr); + + ins_cost(300); + format %{ "imulq $dst, $src\t# mulExact long" %} + ins_encode %{ + __ imulq($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg_alu0); +%} + +instruct mulExactL_rReg_imm(rax_RegL dst, rRegL src, immL32 imm, rFlagsReg cr) +%{ + match(MulExactL src imm); + effect(DEF cr); + + ins_cost(300); + format %{ "imulq $dst, $src, $imm\t# mulExact long" %} + ins_encode %{ + __ imulq($dst$$Register, $src$$Register, $imm$$constant); + %} + ins_pipe(ialu_reg_reg_alu0); +%} + +instruct mulExactL_rReg_mem(rax_RegL dst, memory src, rFlagsReg cr) +%{ + match(MulExactL dst (LoadL src)); + effect(DEF cr); + + ins_cost(350); + format %{ "imulq $dst, $src\t# mulExact long" %} + ins_encode %{ + __ imulq($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem_alu0); +%} + instruct divI_rReg(rax_RegI rax, rdx_RegI rdx, no_rax_rdx_RegI div, rFlagsReg cr) %{ diff -r 6795fcebbf42 -r c31f0cbe6d9e src/os/bsd/vm/os_bsd.cpp --- a/src/os/bsd/vm/os_bsd.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/os/bsd/vm/os_bsd.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -159,9 +159,21 @@ return Bsd::available_memory(); } +// available here means free julong os::Bsd::available_memory() { - // XXXBSD: this is just a stopgap implementation - return physical_memory() >> 2; + uint64_t available = physical_memory() >> 2; +#ifdef __APPLE__ + mach_msg_type_number_t count = HOST_VM_INFO64_COUNT; + vm_statistics64_data_t vmstat; + kern_return_t kerr = host_statistics64(mach_host_self(), HOST_VM_INFO64, + (host_info64_t)&vmstat, &count); + assert(kerr == KERN_SUCCESS, + "host_statistics64 failed - check mach_host_self() and count"); + if (kerr == KERN_SUCCESS) { + available = vmstat.free_count * os::vm_page_size(); + } +#endif + return available; } julong os::physical_memory() { @@ -4734,6 +4746,10 @@ // as libawt.so, and renamed libawt_xawt.so // bool os::is_headless_jre() { +#ifdef __APPLE__ + // We no longer build headless-only on Mac OS X + return false; +#else struct stat statbuf; char buf[MAXPATHLEN]; char libmawtpath[MAXPATHLEN]; @@ -4765,6 +4781,7 @@ if (::stat(libmawtpath, &statbuf) == 0) return false; return true; +#endif } // Get the default path to the core file diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/adlc/archDesc.cpp --- a/src/share/vm/adlc/archDesc.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/adlc/archDesc.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -1193,6 +1193,13 @@ || strcmp(idealName,"FastLock") == 0 || strcmp(idealName,"FastUnlock") == 0 || strcmp(idealName,"AddExactI") == 0 + || strcmp(idealName,"AddExactL") == 0 + || strcmp(idealName,"SubExactI") == 0 + || strcmp(idealName,"SubExactL") == 0 + || strcmp(idealName,"MulExactI") == 0 + || strcmp(idealName,"MulExactL") == 0 + || strcmp(idealName,"NegExactI") == 0 + || strcmp(idealName,"NegExactL") == 0 || strcmp(idealName,"FlagsProj") == 0 || strcmp(idealName,"Bool") == 0 || strcmp(idealName,"Binary") == 0 ) { diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/adlc/formssel.cpp --- a/src/share/vm/adlc/formssel.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/adlc/formssel.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -536,12 +536,6 @@ if( data_type != Form::none ) rematerialize = true; - // Ugly: until a better fix is implemented, disable rematerialization for - // negD nodes because they are proved to be problematic. - if (is_ideal_negD()) { - return false; - } - // Constants if( _components.count() == 1 && _components[0]->is(Component::USE_DEF) ) rematerialize = true; diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/c1/c1_Canonicalizer.cpp --- a/src/share/vm/c1/c1_Canonicalizer.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/c1/c1_Canonicalizer.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -935,6 +935,7 @@ void Canonicalizer::do_UnsafePrefetchRead (UnsafePrefetchRead* x) {} void Canonicalizer::do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) {} void Canonicalizer::do_ProfileCall(ProfileCall* x) {} +void Canonicalizer::do_ProfileReturnType(ProfileReturnType* x) {} void Canonicalizer::do_ProfileInvoke(ProfileInvoke* x) {} void Canonicalizer::do_RuntimeCall(RuntimeCall* x) {} void Canonicalizer::do_RangeCheckPredicate(RangeCheckPredicate* x) {} diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/c1/c1_Canonicalizer.hpp --- a/src/share/vm/c1/c1_Canonicalizer.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/c1/c1_Canonicalizer.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -104,6 +104,7 @@ virtual void do_UnsafePrefetchRead (UnsafePrefetchRead* x); virtual void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x); virtual void do_ProfileCall (ProfileCall* x); + virtual void do_ProfileReturnType (ProfileReturnType* x); virtual void do_ProfileInvoke (ProfileInvoke* x); virtual void do_RuntimeCall (RuntimeCall* x); virtual void do_MemBar (MemBar* x); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/c1/c1_Compilation.cpp --- a/src/share/vm/c1/c1_Compilation.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/c1/c1_Compilation.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -601,6 +601,17 @@ } } +ciKlass* Compilation::cha_exact_type(ciType* type) { + if (type != NULL && type->is_loaded() && type->is_instance_klass()) { + ciInstanceKlass* ik = type->as_instance_klass(); + assert(ik->exact_klass() == NULL, "no cha for final klass"); + if (DeoptC1 && UseCHA && !(ik->has_subklass() || ik->is_interface())) { + dependency_recorder()->assert_leaf_type(ik); + return ik; + } + } + return NULL; +} void Compilation::print_timers() { // tty->print_cr(" Native methods : %6.3f s, Average : %2.3f", CompileBroker::_t_native_compilation.seconds(), CompileBroker::_t_native_compilation.seconds() / CompileBroker::_total_native_compile_count); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/c1/c1_Compilation.hpp --- a/src/share/vm/c1/c1_Compilation.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/c1/c1_Compilation.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -238,7 +238,18 @@ return env()->comp_level() == CompLevel_full_profile && C1UpdateMethodData && C1ProfileCheckcasts; } - + bool profile_parameters() { + return env()->comp_level() == CompLevel_full_profile && + C1UpdateMethodData && MethodData::profile_parameters(); + } + bool profile_arguments() { + return env()->comp_level() == CompLevel_full_profile && + C1UpdateMethodData && MethodData::profile_arguments(); + } + bool profile_return() { + return env()->comp_level() == CompLevel_full_profile && + C1UpdateMethodData && MethodData::profile_return(); + } // will compilation make optimistic assumptions that might lead to // deoptimization and that the runtime will account for? bool is_optimistic() const { @@ -246,6 +257,8 @@ (RangeCheckElimination || UseLoopInvariantCodeMotion) && method()->method_data()->trap_count(Deoptimization::Reason_none) == 0; } + + ciKlass* cha_exact_type(ciType* type); }; diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/c1/c1_Compiler.cpp --- a/src/share/vm/c1/c1_Compiler.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/c1/c1_Compiler.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -42,26 +42,16 @@ #include "runtime/interfaceSupport.hpp" #include "runtime/sharedRuntime.hpp" -volatile int Compiler::_runtimes = uninitialized; - -Compiler::Compiler() { -} - -Compiler::~Compiler() { - Unimplemented(); -} +Compiler::Compiler () {} - -void Compiler::initialize_all() { +void Compiler::init_c1_runtime() { BufferBlob* buffer_blob = CompilerThread::current()->get_buffer_blob(); Arena* arena = new (mtCompiler) Arena(); Runtime1::initialize(buffer_blob); FrameMap::initialize(); // initialize data structures ValueType::initialize(arena); - // Instruction::initialize(); - // BlockBegin::initialize(); GraphBuilder::initialize(); // note: to use more than one instance of LinearScan at a time this function call has to // be moved somewhere outside of this constructor: @@ -70,32 +60,33 @@ void Compiler::initialize() { - if (_runtimes != initialized) { - initialize_runtimes( initialize_all, &_runtimes); + // Buffer blob must be allocated per C1 compiler thread at startup + BufferBlob* buffer_blob = init_buffer_blob(); + + if (should_perform_init()) { + if (buffer_blob == NULL) { + // When we come here we are in state 'initializing'; entire C1 compilation + // can be shut down. + set_state(failed); + } else { + init_c1_runtime(); + set_state(initialized); + } } - mark_initialized(); } - -BufferBlob* Compiler::get_buffer_blob(ciEnv* env) { +BufferBlob* Compiler::init_buffer_blob() { // Allocate buffer blob once at startup since allocation for each // compilation seems to be too expensive (at least on Intel win32). - BufferBlob* buffer_blob = CompilerThread::current()->get_buffer_blob(); - if (buffer_blob != NULL) { - return buffer_blob; - } + assert (CompilerThread::current()->get_buffer_blob() == NULL, "Should initialize only once"); // setup CodeBuffer. Preallocate a BufferBlob of size // NMethodSizeLimit plus some extra space for constants. int code_buffer_size = Compilation::desired_max_code_buffer_size() + Compilation::desired_max_constant_size(); - buffer_blob = BufferBlob::create("Compiler1 temporary CodeBuffer", - code_buffer_size); - if (buffer_blob == NULL) { - CompileBroker::handle_full_code_cache(); - env->record_failure("CodeCache is full"); - } else { + BufferBlob* buffer_blob = BufferBlob::create("C1 temporary CodeBuffer", code_buffer_size); + if (buffer_blob != NULL) { CompilerThread::current()->set_buffer_blob(buffer_blob); } @@ -104,15 +95,8 @@ void Compiler::compile_method(ciEnv* env, ciMethod* method, int entry_bci) { - BufferBlob* buffer_blob = Compiler::get_buffer_blob(env); - if (buffer_blob == NULL) { - return; - } - - if (!is_initialized()) { - initialize(); - } - + BufferBlob* buffer_blob = CompilerThread::current()->get_buffer_blob(); + assert(buffer_blob != NULL, "Must exist"); // invoke compilation { // We are nested here because we need for the destructor diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/c1/c1_Compiler.hpp --- a/src/share/vm/c1/c1_Compiler.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/c1/c1_Compiler.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -30,11 +30,9 @@ // There is one instance of the Compiler per CompilerThread. class Compiler: public AbstractCompiler { - private: - - // Tracks whether runtime has been initialized - static volatile int _runtimes; + static void init_c1_runtime(); + BufferBlob* init_buffer_blob(); public: // Creation @@ -46,19 +44,12 @@ virtual bool is_c1() { return true; }; - BufferBlob* get_buffer_blob(ciEnv* env); - // Missing feature tests virtual bool supports_native() { return true; } virtual bool supports_osr () { return true; } - // Customization - virtual bool needs_adapters () { return false; } - virtual bool needs_stubs () { return false; } - // Initialization virtual void initialize(); - static void initialize_all(); // Compilation entry point for methods virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/c1/c1_GraphBuilder.cpp --- a/src/share/vm/c1/c1_GraphBuilder.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/c1/c1_GraphBuilder.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -1466,9 +1466,22 @@ // State at end of inlined method is the state of the caller // without the method parameters on stack, including the // return value, if any, of the inlined method on operand stack. + int invoke_bci = state()->caller_state()->bci(); set_state(state()->caller_state()->copy_for_parsing()); if (x != NULL) { state()->push(x->type(), x); + if (profile_return() && x->type()->is_object_kind()) { + ciMethod* caller = state()->scope()->method(); + ciMethodData* md = caller->method_data_or_null(); + ciProfileData* data = md->bci_to_data(invoke_bci); + if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) { + bool has_return = data->is_CallTypeData() ? ((ciCallTypeData*)data)->has_return() : ((ciVirtualCallTypeData*)data)->has_return(); + // May not be true in case of an inlined call through a method handle intrinsic. + if (has_return) { + profile_return_type(x, method(), caller, invoke_bci); + } + } + } } Goto* goto_callee = new Goto(continuation(), false); @@ -1658,6 +1671,50 @@ return compilation()->dependency_recorder(); } +// How many arguments do we want to profile? +Values* GraphBuilder::args_list_for_profiling(ciMethod* target, int& start, bool may_have_receiver) { + int n = 0; + bool has_receiver = may_have_receiver && Bytecodes::has_receiver(method()->java_code_at_bci(bci())); + start = has_receiver ? 1 : 0; + if (profile_arguments()) { + ciProfileData* data = method()->method_data()->bci_to_data(bci()); + if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) { + n = data->is_CallTypeData() ? data->as_CallTypeData()->number_of_arguments() : data->as_VirtualCallTypeData()->number_of_arguments(); + } + } + // If we are inlining then we need to collect arguments to profile parameters for the target + if (profile_parameters() && target != NULL) { + if (target->method_data() != NULL && target->method_data()->parameters_type_data() != NULL) { + // The receiver is profiled on method entry so it's included in + // the number of parameters but here we're only interested in + // actual arguments. + n = MAX2(n, target->method_data()->parameters_type_data()->number_of_parameters() - start); + } + } + if (n > 0) { + return new Values(n); + } + return NULL; +} + +// Collect arguments that we want to profile in a list +Values* GraphBuilder::collect_args_for_profiling(Values* args, ciMethod* target, bool may_have_receiver) { + int start = 0; + Values* obj_args = args_list_for_profiling(target, start, may_have_receiver); + if (obj_args == NULL) { + return NULL; + } + int s = obj_args->size(); + for (int i = start, j = 0; j < s; i++) { + if (args->at(i)->type()->is_object_kind()) { + obj_args->push(args->at(i)); + j++; + } + } + assert(s == obj_args->length(), "missed on arg?"); + return obj_args; +} + void GraphBuilder::invoke(Bytecodes::Code code) { bool will_link; @@ -1957,7 +2014,7 @@ } else if (exact_target != NULL) { target_klass = exact_target->holder(); } - profile_call(target, recv, target_klass); + profile_call(target, recv, target_klass, collect_args_for_profiling(args, NULL, false), false); } } @@ -1972,6 +2029,9 @@ push(result_type, result); } } + if (profile_return() && result_type->is_object_kind()) { + profile_return_type(result, target); + } } @@ -3509,7 +3569,7 @@ recv = args->at(0); null_check(recv); } - profile_call(callee, recv, NULL); + profile_call(callee, recv, NULL, collect_args_for_profiling(args, callee, true), true); } } } @@ -3520,6 +3580,10 @@ Value value = append_split(result); if (result_type != voidType) push(result_type, value); + if (callee != method() && profile_return() && result_type->is_object_kind()) { + profile_return_type(result, callee); + } + // done return true; } @@ -3704,6 +3768,7 @@ // now perform tests that are based on flag settings if (callee->force_inline()) { + if (inline_level() > MaxForceInlineLevel) INLINE_BAILOUT("MaxForceInlineLevel"); print_inlining(callee, "force inline by annotation"); } else if (callee->should_inline()) { print_inlining(callee, "force inline by CompileOracle"); @@ -3763,7 +3828,28 @@ compilation()->set_would_profile(true); if (profile_calls()) { - profile_call(callee, recv, holder_known ? callee->holder() : NULL); + int start = 0; + Values* obj_args = args_list_for_profiling(callee, start, has_receiver); + if (obj_args != NULL) { + int s = obj_args->size(); + // if called through method handle invoke, some arguments may have been popped + for (int i = args_base+start, j = 0; j < obj_args->size() && i < state()->stack_size(); ) { + Value v = state()->stack_at_inc(i); + if (v->type()->is_object_kind()) { + obj_args->push(v); + j++; + } + } +#ifdef ASSERT + { + bool ignored_will_link; + ciSignature* declared_signature = NULL; + ciMethod* real_target = method()->get_method_at_bci(bci(), ignored_will_link, &declared_signature); + assert(s == obj_args->length() || real_target->is_method_handle_intrinsic(), "missed on arg?"); + } +#endif + } + profile_call(callee, recv, holder_known ? callee->holder() : NULL, obj_args, true); } } @@ -4251,8 +4337,23 @@ } #endif // PRODUCT -void GraphBuilder::profile_call(ciMethod* callee, Value recv, ciKlass* known_holder) { - append(new ProfileCall(method(), bci(), callee, recv, known_holder)); +void GraphBuilder::profile_call(ciMethod* callee, Value recv, ciKlass* known_holder, Values* obj_args, bool inlined) { + append(new ProfileCall(method(), bci(), callee, recv, known_holder, obj_args, inlined)); +} + +void GraphBuilder::profile_return_type(Value ret, ciMethod* callee, ciMethod* m, int invoke_bci) { + assert((m == NULL) == (invoke_bci < 0), "invalid method and invalid bci together"); + if (m == NULL) { + m = method(); + } + if (invoke_bci < 0) { + invoke_bci = bci(); + } + ciMethodData* md = m->method_data_or_null(); + ciProfileData* data = md->bci_to_data(invoke_bci); + if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) { + append(new ProfileReturnType(m , invoke_bci, callee, ret)); + } } void GraphBuilder::profile_invocation(ciMethod* callee, ValueStack* state) { diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/c1/c1_GraphBuilder.hpp --- a/src/share/vm/c1/c1_GraphBuilder.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/c1/c1_GraphBuilder.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -374,7 +374,8 @@ void print_inlining(ciMethod* callee, const char* msg = NULL, bool success = true); - void profile_call(ciMethod* callee, Value recv, ciKlass* predicted_holder); + void profile_call(ciMethod* callee, Value recv, ciKlass* predicted_holder, Values* obj_args, bool inlined); + void profile_return_type(Value ret, ciMethod* callee, ciMethod* m = NULL, int bci = -1); void profile_invocation(ciMethod* inlinee, ValueStack* state); // Shortcuts to profiling control. @@ -385,6 +386,12 @@ bool profile_calls() { return _compilation->profile_calls(); } bool profile_inlined_calls() { return _compilation->profile_inlined_calls(); } bool profile_checkcasts() { return _compilation->profile_checkcasts(); } + bool profile_parameters() { return _compilation->profile_parameters(); } + bool profile_arguments() { return _compilation->profile_arguments(); } + bool profile_return() { return _compilation->profile_return(); } + + Values* args_list_for_profiling(ciMethod* target, int& start, bool may_have_receiver); + Values* collect_args_for_profiling(Values* args, ciMethod* target, bool may_have_receiver); public: NOT_PRODUCT(void print_stats();) diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/c1/c1_Instruction.cpp --- a/src/share/vm/c1/c1_Instruction.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/c1/c1_Instruction.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -104,6 +104,14 @@ } } +ciType* Instruction::exact_type() const { + ciType* t = declared_type(); + if (t != NULL && t->is_klass()) { + return t->as_klass()->exact_klass(); + } + return NULL; +} + #ifndef PRODUCT void Instruction::check_state(ValueStack* state) { @@ -135,9 +143,7 @@ // perform constant and interval tests on index value bool AccessIndexed::compute_needs_range_check() { - if (length()) { - Constant* clength = length()->as_Constant(); Constant* cindex = index()->as_Constant(); if (clength && cindex) { @@ -157,34 +163,8 @@ } -ciType* Local::exact_type() const { - ciType* type = declared_type(); - - // for primitive arrays, the declared type is the exact type - if (type->is_type_array_klass()) { - return type; - } else if (type->is_instance_klass()) { - ciInstanceKlass* ik = (ciInstanceKlass*)type; - if (ik->is_loaded() && ik->is_final() && !ik->is_interface()) { - return type; - } - } else if (type->is_obj_array_klass()) { - ciObjArrayKlass* oak = (ciObjArrayKlass*)type; - ciType* base = oak->base_element_type(); - if (base->is_instance_klass()) { - ciInstanceKlass* ik = base->as_instance_klass(); - if (ik->is_loaded() && ik->is_final()) { - return type; - } - } else if (base->is_primitive_type()) { - return type; - } - } - return NULL; -} - ciType* Constant::exact_type() const { - if (type()->is_object()) { + if (type()->is_object() && type()->as_ObjectType()->is_loaded()) { return type()->as_ObjectType()->exact_type(); } return NULL; @@ -192,19 +172,18 @@ ciType* LoadIndexed::exact_type() const { ciType* array_type = array()->exact_type(); - if (array_type == NULL) { - return NULL; - } - assert(array_type->is_array_klass(), "what else?"); - ciArrayKlass* ak = (ciArrayKlass*)array_type; + if (array_type != NULL) { + assert(array_type->is_array_klass(), "what else?"); + ciArrayKlass* ak = (ciArrayKlass*)array_type; - if (ak->element_type()->is_instance_klass()) { - ciInstanceKlass* ik = (ciInstanceKlass*)ak->element_type(); - if (ik->is_loaded() && ik->is_final()) { - return ik; + if (ak->element_type()->is_instance_klass()) { + ciInstanceKlass* ik = (ciInstanceKlass*)ak->element_type(); + if (ik->is_loaded() && ik->is_final()) { + return ik; + } } } - return NULL; + return Instruction::exact_type(); } @@ -224,22 +203,6 @@ } -ciType* LoadField::exact_type() const { - ciType* type = declared_type(); - // for primitive arrays, the declared type is the exact type - if (type->is_type_array_klass()) { - return type; - } - if (type->is_instance_klass()) { - ciInstanceKlass* ik = (ciInstanceKlass*)type; - if (ik->is_loaded() && ik->is_final()) { - return type; - } - } - return NULL; -} - - ciType* NewTypeArray::exact_type() const { return ciTypeArrayKlass::make(elt_type()); } @@ -264,16 +227,6 @@ return klass(); } -ciType* CheckCast::exact_type() const { - if (klass()->is_instance_klass()) { - ciInstanceKlass* ik = (ciInstanceKlass*)klass(); - if (ik->is_loaded() && ik->is_final()) { - return ik; - } - } - return NULL; -} - // Implementation of ArithmeticOp bool ArithmeticOp::is_commutative() const { diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/c1/c1_Instruction.hpp --- a/src/share/vm/c1/c1_Instruction.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/c1/c1_Instruction.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -107,6 +107,7 @@ class UnsafePrefetchRead; class UnsafePrefetchWrite; class ProfileCall; +class ProfileReturnType; class ProfileInvoke; class RuntimeCall; class MemBar; @@ -211,6 +212,7 @@ virtual void do_UnsafePrefetchRead (UnsafePrefetchRead* x) = 0; virtual void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) = 0; virtual void do_ProfileCall (ProfileCall* x) = 0; + virtual void do_ProfileReturnType (ProfileReturnType* x) = 0; virtual void do_ProfileInvoke (ProfileInvoke* x) = 0; virtual void do_RuntimeCall (RuntimeCall* x) = 0; virtual void do_MemBar (MemBar* x) = 0; @@ -322,6 +324,36 @@ _type = type; } + // Helper class to keep track of which arguments need a null check + class ArgsNonNullState { + private: + int _nonnull_state; // mask identifying which args are nonnull + public: + ArgsNonNullState() + : _nonnull_state(AllBits) {} + + // Does argument number i needs a null check? + bool arg_needs_null_check(int i) const { + // No data is kept for arguments starting at position 33 so + // conservatively assume that they need a null check. + if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) { + return is_set_nth_bit(_nonnull_state, i); + } + return true; + } + + // Set whether argument number i needs a null check or not + void set_arg_needs_null_check(int i, bool check) { + if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) { + if (check) { + _nonnull_state |= nth_bit(i); + } else { + _nonnull_state &= ~(nth_bit(i)); + } + } + } + }; + public: void* operator new(size_t size) throw() { Compilation* c = Compilation::current(); @@ -566,7 +598,7 @@ virtual void other_values_do(ValueVisitor* f) { /* usually no other - override on demand */ } void values_do(ValueVisitor* f) { input_values_do(f); state_values_do(f); other_values_do(f); } - virtual ciType* exact_type() const { return NULL; } + virtual ciType* exact_type() const; virtual ciType* declared_type() const { return NULL; } // hashing @@ -689,7 +721,6 @@ int java_index() const { return _java_index; } virtual ciType* declared_type() const { return _declared_type; } - virtual ciType* exact_type() const; // generic virtual void input_values_do(ValueVisitor* f) { /* no values */ } @@ -806,7 +837,6 @@ {} ciType* declared_type() const; - ciType* exact_type() const; // generic HASHING2(LoadField, !needs_patching() && !field()->is_volatile(), obj()->subst(), offset()) // cannot be eliminated if needs patching or if volatile @@ -1299,6 +1329,7 @@ virtual bool needs_exception_state() const { return false; } + ciType* exact_type() const { return NULL; } ciType* declared_type() const; // generic @@ -1422,7 +1453,6 @@ } ciType* declared_type() const; - ciType* exact_type() const; }; @@ -1490,7 +1520,7 @@ vmIntrinsics::ID _id; Values* _args; Value _recv; - int _nonnull_state; // mask identifying which args are nonnull + ArgsNonNullState _nonnull_state; public: // preserves_state can be set to true for Intrinsics @@ -1511,7 +1541,6 @@ , _id(id) , _args(args) , _recv(NULL) - , _nonnull_state(AllBits) { assert(args != NULL, "args must exist"); ASSERT_VALUES @@ -1537,21 +1566,12 @@ Value receiver() const { assert(has_receiver(), "must have receiver"); return _recv; } bool preserves_state() const { return check_flag(PreservesStateFlag); } - bool arg_needs_null_check(int i) { - if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) { - return is_set_nth_bit(_nonnull_state, i); - } - return true; + bool arg_needs_null_check(int i) const { + return _nonnull_state.arg_needs_null_check(i); } void set_arg_needs_null_check(int i, bool check) { - if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) { - if (check) { - _nonnull_state |= nth_bit(i); - } else { - _nonnull_state &= ~(nth_bit(i)); - } - } + _nonnull_state.set_arg_needs_null_check(i, check); } // generic @@ -2450,34 +2470,87 @@ LEAF(ProfileCall, Instruction) private: - ciMethod* _method; - int _bci_of_invoke; - ciMethod* _callee; // the method that is called at the given bci - Value _recv; - ciKlass* _known_holder; + ciMethod* _method; + int _bci_of_invoke; + ciMethod* _callee; // the method that is called at the given bci + Value _recv; + ciKlass* _known_holder; + Values* _obj_args; // arguments for type profiling + ArgsNonNullState _nonnull_state; // Do we know whether some arguments are never null? + bool _inlined; // Are we profiling a call that is inlined public: - ProfileCall(ciMethod* method, int bci, ciMethod* callee, Value recv, ciKlass* known_holder) + ProfileCall(ciMethod* method, int bci, ciMethod* callee, Value recv, ciKlass* known_holder, Values* obj_args, bool inlined) : Instruction(voidType) , _method(method) , _bci_of_invoke(bci) , _callee(callee) , _recv(recv) , _known_holder(known_holder) + , _obj_args(obj_args) + , _inlined(inlined) { // The ProfileCall has side-effects and must occur precisely where located pin(); } - ciMethod* method() { return _method; } - int bci_of_invoke() { return _bci_of_invoke; } - ciMethod* callee() { return _callee; } - Value recv() { return _recv; } - ciKlass* known_holder() { return _known_holder; } - - virtual void input_values_do(ValueVisitor* f) { if (_recv != NULL) f->visit(&_recv); } + ciMethod* method() const { return _method; } + int bci_of_invoke() const { return _bci_of_invoke; } + ciMethod* callee() const { return _callee; } + Value recv() const { return _recv; } + ciKlass* known_holder() const { return _known_holder; } + int nb_profiled_args() const { return _obj_args == NULL ? 0 : _obj_args->length(); } + Value profiled_arg_at(int i) const { return _obj_args->at(i); } + bool arg_needs_null_check(int i) const { + return _nonnull_state.arg_needs_null_check(i); + } + bool inlined() const { return _inlined; } + + void set_arg_needs_null_check(int i, bool check) { + _nonnull_state.set_arg_needs_null_check(i, check); + } + + virtual void input_values_do(ValueVisitor* f) { + if (_recv != NULL) { + f->visit(&_recv); + } + for (int i = 0; i < nb_profiled_args(); i++) { + f->visit(_obj_args->adr_at(i)); + } + } }; +LEAF(ProfileReturnType, Instruction) + private: + ciMethod* _method; + ciMethod* _callee; + int _bci_of_invoke; + Value _ret; + + public: + ProfileReturnType(ciMethod* method, int bci, ciMethod* callee, Value ret) + : Instruction(voidType) + , _method(method) + , _callee(callee) + , _bci_of_invoke(bci) + , _ret(ret) + { + set_needs_null_check(true); + // The ProfileType has side-effects and must occur precisely where located + pin(); + } + + ciMethod* method() const { return _method; } + ciMethod* callee() const { return _callee; } + int bci_of_invoke() const { return _bci_of_invoke; } + Value ret() const { return _ret; } + + virtual void input_values_do(ValueVisitor* f) { + if (_ret != NULL) { + f->visit(&_ret); + } + } +}; // Call some C runtime function that doesn't safepoint, // optionally passing the current thread as the first argument. diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/c1/c1_InstructionPrinter.cpp --- a/src/share/vm/c1/c1_InstructionPrinter.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/c1/c1_InstructionPrinter.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -892,10 +892,24 @@ if (x->known_holder() != NULL) { output()->print(", "); print_klass(x->known_holder()); + output()->print(" "); + } + for (int i = 0; i < x->nb_profiled_args(); i++) { + if (i > 0) output()->print(", "); + print_value(x->profiled_arg_at(i)); + if (x->arg_needs_null_check(i)) { + output()->print(" [NC]"); + } } output()->put(')'); } +void InstructionPrinter::do_ProfileReturnType(ProfileReturnType* x) { + output()->print("profile ret type "); + print_value(x->ret()); + output()->print(" %s.%s", x->method()->holder()->name()->as_utf8(), x->method()->name()->as_utf8()); + output()->put(')'); +} void InstructionPrinter::do_ProfileInvoke(ProfileInvoke* x) { output()->print("profile_invoke "); output()->print(" %s.%s", x->inlinee()->holder()->name()->as_utf8(), x->inlinee()->name()->as_utf8()); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/c1/c1_InstructionPrinter.hpp --- a/src/share/vm/c1/c1_InstructionPrinter.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/c1/c1_InstructionPrinter.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -132,6 +132,7 @@ virtual void do_UnsafePrefetchRead (UnsafePrefetchRead* x); virtual void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x); virtual void do_ProfileCall (ProfileCall* x); + virtual void do_ProfileReturnType (ProfileReturnType* x); virtual void do_ProfileInvoke (ProfileInvoke* x); virtual void do_RuntimeCall (RuntimeCall* x); virtual void do_MemBar (MemBar* x); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/c1/c1_LIR.cpp --- a/src/share/vm/c1/c1_LIR.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/c1/c1_LIR.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -183,10 +183,10 @@ case T_LONG: case T_OBJECT: case T_ADDRESS: - case T_METADATA: case T_VOID: return ::type2char(t); - + case T_METADATA: + return 'M'; case T_ILLEGAL: return '?'; @@ -1001,6 +1001,17 @@ assert(opProfileCall->_tmp1->is_valid(), "used"); do_temp(opProfileCall->_tmp1); break; } + +// LIR_OpProfileType: + case lir_profile_type: { + assert(op->as_OpProfileType() != NULL, "must be"); + LIR_OpProfileType* opProfileType = (LIR_OpProfileType*)op; + + do_input(opProfileType->_mdp); do_temp(opProfileType->_mdp); + do_input(opProfileType->_obj); + do_temp(opProfileType->_tmp); + break; + } default: ShouldNotReachHere(); } @@ -1151,6 +1162,10 @@ masm->emit_profile_call(this); } +void LIR_OpProfileType::emit_code(LIR_Assembler* masm) { + masm->emit_profile_type(this); +} + // LIR_List LIR_List::LIR_List(Compilation* compilation, BlockBegin* block) : _operations(8) @@ -1803,6 +1818,8 @@ case lir_cas_int: s = "cas_int"; break; // LIR_OpProfileCall case lir_profile_call: s = "profile_call"; break; + // LIR_OpProfileType + case lir_profile_type: s = "profile_type"; break; // LIR_OpAssert #ifdef ASSERT case lir_assert: s = "assert"; break; @@ -2086,6 +2103,15 @@ tmp1()->print(out); out->print(" "); } +// LIR_OpProfileType +void LIR_OpProfileType::print_instr(outputStream* out) const { + out->print("exact = "); exact_klass()->print_name_on(out); + out->print("current = "); ciTypeEntries::print_ciklass(out, current_klass()); + mdp()->print(out); out->print(" "); + obj()->print(out); out->print(" "); + tmp()->print(out); out->print(" "); +} + #endif // PRODUCT // Implementation of LIR_InsertionBuffer diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/c1/c1_LIR.hpp --- a/src/share/vm/c1/c1_LIR.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/c1/c1_LIR.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -882,6 +882,7 @@ class LIR_OpTypeCheck; class LIR_OpCompareAndSwap; class LIR_OpProfileCall; +class LIR_OpProfileType; #ifdef ASSERT class LIR_OpAssert; #endif @@ -1005,6 +1006,7 @@ , end_opCompareAndSwap , begin_opMDOProfile , lir_profile_call + , lir_profile_type , end_opMDOProfile , begin_opAssert , lir_assert @@ -1145,6 +1147,7 @@ virtual LIR_OpTypeCheck* as_OpTypeCheck() { return NULL; } virtual LIR_OpCompareAndSwap* as_OpCompareAndSwap() { return NULL; } virtual LIR_OpProfileCall* as_OpProfileCall() { return NULL; } + virtual LIR_OpProfileType* as_OpProfileType() { return NULL; } #ifdef ASSERT virtual LIR_OpAssert* as_OpAssert() { return NULL; } #endif @@ -1925,8 +1928,8 @@ public: // Destroys recv - LIR_OpProfileCall(LIR_Code code, ciMethod* profiled_method, int profiled_bci, ciMethod* profiled_callee, LIR_Opr mdo, LIR_Opr recv, LIR_Opr t1, ciKlass* known_holder) - : LIR_Op(code, LIR_OprFact::illegalOpr, NULL) // no result, no info + LIR_OpProfileCall(ciMethod* profiled_method, int profiled_bci, ciMethod* profiled_callee, LIR_Opr mdo, LIR_Opr recv, LIR_Opr t1, ciKlass* known_holder) + : LIR_Op(lir_profile_call, LIR_OprFact::illegalOpr, NULL) // no result, no info , _profiled_method(profiled_method) , _profiled_bci(profiled_bci) , _profiled_callee(profiled_callee) @@ -1948,6 +1951,45 @@ virtual void print_instr(outputStream* out) const PRODUCT_RETURN; }; +// LIR_OpProfileType +class LIR_OpProfileType : public LIR_Op { + friend class LIR_OpVisitState; + + private: + LIR_Opr _mdp; + LIR_Opr _obj; + LIR_Opr _tmp; + ciKlass* _exact_klass; // non NULL if we know the klass statically (no need to load it from _obj) + intptr_t _current_klass; // what the profiling currently reports + bool _not_null; // true if we know statically that _obj cannot be null + bool _no_conflict; // true if we're profling parameters, _exact_klass is not NULL and we know + // _exact_klass it the only possible type for this parameter in any context. + + public: + // Destroys recv + LIR_OpProfileType(LIR_Opr mdp, LIR_Opr obj, ciKlass* exact_klass, intptr_t current_klass, LIR_Opr tmp, bool not_null, bool no_conflict) + : LIR_Op(lir_profile_type, LIR_OprFact::illegalOpr, NULL) // no result, no info + , _mdp(mdp) + , _obj(obj) + , _exact_klass(exact_klass) + , _current_klass(current_klass) + , _tmp(tmp) + , _not_null(not_null) + , _no_conflict(no_conflict) { } + + LIR_Opr mdp() const { return _mdp; } + LIR_Opr obj() const { return _obj; } + LIR_Opr tmp() const { return _tmp; } + ciKlass* exact_klass() const { return _exact_klass; } + intptr_t current_klass() const { return _current_klass; } + bool not_null() const { return _not_null; } + bool no_conflict() const { return _no_conflict; } + + virtual void emit_code(LIR_Assembler* masm); + virtual LIR_OpProfileType* as_OpProfileType() { return this; } + virtual void print_instr(outputStream* out) const PRODUCT_RETURN; +}; + class LIR_InsertionBuffer; //--------------------------------LIR_List--------------------------------------------------- @@ -2247,7 +2289,10 @@ ciMethod* profiled_method, int profiled_bci); // MethodData* profiling void profile_call(ciMethod* method, int bci, ciMethod* callee, LIR_Opr mdo, LIR_Opr recv, LIR_Opr t1, ciKlass* cha_klass) { - append(new LIR_OpProfileCall(lir_profile_call, method, bci, callee, mdo, recv, t1, cha_klass)); + append(new LIR_OpProfileCall(method, bci, callee, mdo, recv, t1, cha_klass)); + } + void profile_type(LIR_Address* mdp, LIR_Opr obj, ciKlass* exact_klass, intptr_t current_klass, LIR_Opr tmp, bool not_null, bool no_conflict) { + append(new LIR_OpProfileType(LIR_OprFact::address(mdp), obj, exact_klass, current_klass, tmp, not_null, no_conflict)); } void xadd(LIR_Opr src, LIR_Opr add, LIR_Opr res, LIR_Opr tmp) { append(new LIR_Op2(lir_xadd, src, add, res, tmp)); } diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/c1/c1_LIRAssembler.hpp --- a/src/share/vm/c1/c1_LIRAssembler.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/c1/c1_LIRAssembler.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -208,6 +208,7 @@ void emit_call(LIR_OpJavaCall* op); void emit_rtcall(LIR_OpRTCall* op); void emit_profile_call(LIR_OpProfileCall* op); + void emit_profile_type(LIR_OpProfileType* op); void emit_delay(LIR_OpDelay* op); void arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest, CodeEmitInfo* info, bool pop_fpu_stack); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/c1/c1_LIRGenerator.cpp --- a/src/share/vm/c1/c1_LIRGenerator.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/c1/c1_LIRGenerator.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -1175,7 +1175,7 @@ if (compilation()->env()->dtrace_method_probes()) { BasicTypeList signature; signature.append(LP64_ONLY(T_LONG) NOT_LP64(T_INT)); // thread - signature.append(T_OBJECT); // Method* + signature.append(T_METADATA); // Method* LIR_OprList* args = new LIR_OprList(); args->append(getThreadPointer()); LIR_Opr meth = new_register(T_METADATA); @@ -1265,6 +1265,7 @@ LIRItem rcvr(x->argument_at(0), this); rcvr.load_item(); + LIR_Opr temp = new_register(T_METADATA); LIR_Opr result = rlock_result(x); // need to perform the null check on the rcvr @@ -1272,8 +1273,11 @@ if (x->needs_null_check()) { info = state_for(x); } - __ move(new LIR_Address(rcvr.result(), oopDesc::klass_offset_in_bytes(), T_ADDRESS), result, info); - __ move_wide(new LIR_Address(result, in_bytes(Klass::java_mirror_offset()), T_OBJECT), result); + + // FIXME T_ADDRESS should actually be T_METADATA but it can't because the + // meaning of these two is mixed up (see JDK-8026837). + __ move(new LIR_Address(rcvr.result(), oopDesc::klass_offset_in_bytes(), T_ADDRESS), temp, info); + __ move_wide(new LIR_Address(temp, in_bytes(Klass::java_mirror_offset()), T_OBJECT), result); } @@ -2571,6 +2575,111 @@ } +ciKlass* LIRGenerator::profile_arg_type(ciMethodData* md, int md_base_offset, int md_offset, intptr_t profiled_k, Value arg, LIR_Opr& mdp, bool not_null, ciKlass* signature_k) { + ciKlass* result = NULL; + bool do_null = !not_null && !TypeEntries::was_null_seen(profiled_k); + bool do_update = !TypeEntries::is_type_unknown(profiled_k); + // known not to be null or null bit already set and already set to + // unknown: nothing we can do to improve profiling + if (!do_null && !do_update) { + return result; + } + + ciKlass* exact_klass = NULL; + Compilation* comp = Compilation::current(); + if (do_update) { + // try to find exact type, using CHA if possible, so that loading + // the klass from the object can be avoided + ciType* type = arg->exact_type(); + if (type == NULL) { + type = arg->declared_type(); + type = comp->cha_exact_type(type); + } + assert(type == NULL || type->is_klass(), "type should be class"); + exact_klass = (type != NULL && type->is_loaded()) ? (ciKlass*)type : NULL; + + do_update = exact_klass == NULL || ciTypeEntries::valid_ciklass(profiled_k) != exact_klass; + } + + if (!do_null && !do_update) { + return result; + } + + ciKlass* exact_signature_k = NULL; + if (do_update) { + // Is the type from the signature exact (the only one possible)? + exact_signature_k = signature_k->exact_klass(); + if (exact_signature_k == NULL) { + exact_signature_k = comp->cha_exact_type(signature_k); + } else { + result = exact_signature_k; + do_update = false; + // Known statically. No need to emit any code: prevent + // LIR_Assembler::emit_profile_type() from emitting useless code + profiled_k = ciTypeEntries::with_status(result, profiled_k); + } + if (exact_signature_k != NULL && exact_klass != exact_signature_k) { + assert(exact_klass == NULL, "arg and signature disagree?"); + // sometimes the type of the signature is better than the best type + // the compiler has + exact_klass = exact_signature_k; + do_update = exact_klass == NULL || ciTypeEntries::valid_ciklass(profiled_k) != exact_klass; + } + } + + if (!do_null && !do_update) { + return result; + } + + if (mdp == LIR_OprFact::illegalOpr) { + mdp = new_register(T_METADATA); + __ metadata2reg(md->constant_encoding(), mdp); + if (md_base_offset != 0) { + LIR_Address* base_type_address = new LIR_Address(mdp, md_base_offset, T_ADDRESS); + mdp = new_pointer_register(); + __ leal(LIR_OprFact::address(base_type_address), mdp); + } + } + LIRItem value(arg, this); + value.load_item(); + __ profile_type(new LIR_Address(mdp, md_offset, T_METADATA), + value.result(), exact_klass, profiled_k, new_pointer_register(), not_null, exact_signature_k != NULL); + return result; +} + +// profile parameters on entry to the root of the compilation +void LIRGenerator::profile_parameters(Base* x) { + if (compilation()->profile_parameters()) { + CallingConvention* args = compilation()->frame_map()->incoming_arguments(); + ciMethodData* md = scope()->method()->method_data_or_null(); + assert(md != NULL, "Sanity"); + + if (md->parameters_type_data() != NULL) { + ciParametersTypeData* parameters_type_data = md->parameters_type_data(); + ciTypeStackSlotEntries* parameters = parameters_type_data->parameters(); + LIR_Opr mdp = LIR_OprFact::illegalOpr; + for (int java_index = 0, i = 0, j = 0; j < parameters_type_data->number_of_parameters(); i++) { + LIR_Opr src = args->at(i); + assert(!src->is_illegal(), "check"); + BasicType t = src->type(); + if (t == T_OBJECT || t == T_ARRAY) { + intptr_t profiled_k = parameters->type(j); + Local* local = x->state()->local_at(java_index)->as_Local(); + ciKlass* exact = profile_arg_type(md, md->byte_offset_of_slot(parameters_type_data, ParametersTypeData::type_offset(0)), + in_bytes(ParametersTypeData::type_offset(j)) - in_bytes(ParametersTypeData::type_offset(0)), + profiled_k, local, mdp, false, local->declared_type()->as_klass()); + // If the profile is known statically set it once for all and do not emit any code + if (exact != NULL) { + md->set_parameter_type(j, exact); + } + j++; + } + java_index += type2size[t]; + } + } + } +} + void LIRGenerator::do_Base(Base* x) { __ std_entry(LIR_OprFact::illegalOpr); // Emit moves from physical registers / stack slots to virtual registers @@ -2611,7 +2720,7 @@ if (compilation()->env()->dtrace_method_probes()) { BasicTypeList signature; signature.append(LP64_ONLY(T_LONG) NOT_LP64(T_INT)); // thread - signature.append(T_OBJECT); // Method* + signature.append(T_METADATA); // Method* LIR_OprList* args = new LIR_OprList(); args->append(getThreadPointer()); LIR_Opr meth = new_register(T_METADATA); @@ -2646,6 +2755,7 @@ // increment invocation counters if needed if (!method()->is_accessor()) { // Accessors do not have MDOs, so no counting. + profile_parameters(x); CodeEmitInfo* info = new CodeEmitInfo(scope()->start()->state()->copy(ValueStack::StateBefore, SynchronizationEntryBCI), NULL, false); increment_invocation_counter(info); } @@ -3004,12 +3114,123 @@ } } +void LIRGenerator::profile_arguments(ProfileCall* x) { + if (compilation()->profile_arguments()) { + int bci = x->bci_of_invoke(); + ciMethodData* md = x->method()->method_data_or_null(); + ciProfileData* data = md->bci_to_data(bci); + if ((data->is_CallTypeData() && data->as_CallTypeData()->has_arguments()) || + (data->is_VirtualCallTypeData() && data->as_VirtualCallTypeData()->has_arguments())) { + ByteSize extra = data->is_CallTypeData() ? CallTypeData::args_data_offset() : VirtualCallTypeData::args_data_offset(); + int base_offset = md->byte_offset_of_slot(data, extra); + LIR_Opr mdp = LIR_OprFact::illegalOpr; + ciTypeStackSlotEntries* args = data->is_CallTypeData() ? ((ciCallTypeData*)data)->args() : ((ciVirtualCallTypeData*)data)->args(); + + Bytecodes::Code bc = x->method()->java_code_at_bci(bci); + int start = 0; + int stop = data->is_CallTypeData() ? ((ciCallTypeData*)data)->number_of_arguments() : ((ciVirtualCallTypeData*)data)->number_of_arguments(); + if (x->nb_profiled_args() < stop) { + // if called through method handle invoke, some arguments may have been popped + stop = x->nb_profiled_args(); + } + ciSignature* sig = x->callee()->signature(); + // method handle call to virtual method + bool has_receiver = x->inlined() && !x->callee()->is_static() && !Bytecodes::has_receiver(bc); + ciSignatureStream sig_stream(sig, has_receiver ? x->callee()->holder() : NULL); + for (int i = 0; i < stop; i++) { + int off = in_bytes(TypeEntriesAtCall::argument_type_offset(i)) - in_bytes(TypeEntriesAtCall::args_data_offset()); + ciKlass* exact = profile_arg_type(md, base_offset, off, + args->type(i), x->profiled_arg_at(i+start), mdp, + !x->arg_needs_null_check(i+start), sig_stream.next_klass()); + if (exact != NULL) { + md->set_argument_type(bci, i, exact); + } + } + } else { +#ifdef ASSERT + Bytecodes::Code code = x->method()->raw_code_at_bci(x->bci_of_invoke()); + int n = x->nb_profiled_args(); + assert(MethodData::profile_parameters() && x->inlined() && + ((code == Bytecodes::_invokedynamic && n <= 1) || (code == Bytecodes::_invokehandle && n <= 2)), + "only at JSR292 bytecodes"); +#endif + } + } +} + +// profile parameters on entry to an inlined method +void LIRGenerator::profile_parameters_at_call(ProfileCall* x) { + if (compilation()->profile_parameters() && x->inlined()) { + ciMethodData* md = x->callee()->method_data_or_null(); + if (md != NULL) { + ciParametersTypeData* parameters_type_data = md->parameters_type_data(); + if (parameters_type_data != NULL) { + ciTypeStackSlotEntries* parameters = parameters_type_data->parameters(); + LIR_Opr mdp = LIR_OprFact::illegalOpr; + bool has_receiver = !x->callee()->is_static(); + ciSignature* sig = x->callee()->signature(); + ciSignatureStream sig_stream(sig, has_receiver ? x->callee()->holder() : NULL); + int i = 0; // to iterate on the Instructions + Value arg = x->recv(); + bool not_null = false; + int bci = x->bci_of_invoke(); + Bytecodes::Code bc = x->method()->java_code_at_bci(bci); + // The first parameter is the receiver so that's what we start + // with if it exists. On exception if method handle call to + // virtual method has receiver in the args list + if (arg == NULL || !Bytecodes::has_receiver(bc)) { + i = 1; + arg = x->profiled_arg_at(0); + not_null = !x->arg_needs_null_check(0); + } + int k = 0; // to iterate on the profile data + for (;;) { + intptr_t profiled_k = parameters->type(k); + ciKlass* exact = profile_arg_type(md, md->byte_offset_of_slot(parameters_type_data, ParametersTypeData::type_offset(0)), + in_bytes(ParametersTypeData::type_offset(k)) - in_bytes(ParametersTypeData::type_offset(0)), + profiled_k, arg, mdp, not_null, sig_stream.next_klass()); + // If the profile is known statically set it once for all and do not emit any code + if (exact != NULL) { + md->set_parameter_type(k, exact); + } + k++; + if (k >= parameters_type_data->number_of_parameters()) { +#ifdef ASSERT + int extra = 0; + if (MethodData::profile_arguments() && TypeProfileParmsLimit != -1 && + x->nb_profiled_args() >= TypeProfileParmsLimit && + x->recv() != NULL && Bytecodes::has_receiver(bc)) { + extra += 1; + } + assert(i == x->nb_profiled_args() - extra || (TypeProfileParmsLimit != -1 && TypeProfileArgsLimit > TypeProfileParmsLimit), "unused parameters?"); +#endif + break; + } + arg = x->profiled_arg_at(i); + not_null = !x->arg_needs_null_check(i); + i++; + } + } + } + } +} + void LIRGenerator::do_ProfileCall(ProfileCall* x) { // Need recv in a temporary register so it interferes with the other temporaries LIR_Opr recv = LIR_OprFact::illegalOpr; LIR_Opr mdo = new_register(T_OBJECT); // tmp is used to hold the counters on SPARC LIR_Opr tmp = new_pointer_register(); + + if (x->nb_profiled_args() > 0) { + profile_arguments(x); + } + + // profile parameters on inlined method entry including receiver + if (x->recv() != NULL || x->nb_profiled_args() > 0) { + profile_parameters_at_call(x); + } + if (x->recv() != NULL) { LIRItem value(x->recv(), this); value.load_item(); @@ -3019,6 +3240,21 @@ __ profile_call(x->method(), x->bci_of_invoke(), x->callee(), mdo, recv, tmp, x->known_holder()); } +void LIRGenerator::do_ProfileReturnType(ProfileReturnType* x) { + int bci = x->bci_of_invoke(); + ciMethodData* md = x->method()->method_data_or_null(); + ciProfileData* data = md->bci_to_data(bci); + assert(data->is_CallTypeData() || data->is_VirtualCallTypeData(), "wrong profile data type"); + ciReturnTypeEntry* ret = data->is_CallTypeData() ? ((ciCallTypeData*)data)->ret() : ((ciVirtualCallTypeData*)data)->ret(); + LIR_Opr mdp = LIR_OprFact::illegalOpr; + ciKlass* exact = profile_arg_type(md, 0, md->byte_offset_of_slot(data, ret->type_offset()), + ret->type(), x->ret(), mdp, + !x->needs_null_check(), x->callee()->signature()->return_type()->as_klass()); + if (exact != NULL) { + md->set_return_type(bci, exact); + } +} + void LIRGenerator::do_ProfileInvoke(ProfileInvoke* x) { // We can safely ignore accessors here, since c2 will inline them anyway, // accessors are also always mature. @@ -3053,7 +3289,11 @@ int offset = -1; LIR_Opr counter_holder; if (level == CompLevel_limited_profile) { - address counters_adr = method->ensure_method_counters(); + MethodCounters* counters_adr = method->ensure_method_counters(); + if (counters_adr == NULL) { + bailout("method counters allocation failed"); + return; + } counter_holder = new_pointer_register(); __ move(LIR_OprFact::intptrConst(counters_adr), counter_holder); offset = in_bytes(backedge ? MethodCounters::backedge_counter_offset() : @@ -3091,7 +3331,7 @@ BasicTypeList* signature = new BasicTypeList(x->number_of_arguments()); if (x->pass_thread()) { - signature->append(T_ADDRESS); + signature->append(LP64_ONLY(T_LONG) NOT_LP64(T_INT)); // thread args->append(getThreadPointer()); } diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/c1/c1_LIRGenerator.hpp --- a/src/share/vm/c1/c1_LIRGenerator.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/c1/c1_LIRGenerator.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -434,6 +434,10 @@ void do_ThreadIDIntrinsic(Intrinsic* x); void do_ClassIDIntrinsic(Intrinsic* x); #endif + ciKlass* profile_arg_type(ciMethodData* md, int md_first_offset, int md_offset, intptr_t profiled_k, Value arg, LIR_Opr& mdp, bool not_null, ciKlass* signature_k); + void profile_arguments(ProfileCall* x); + void profile_parameters(Base* x); + void profile_parameters_at_call(ProfileCall* x); public: Compilation* compilation() const { return _compilation; } @@ -534,6 +538,7 @@ virtual void do_UnsafePrefetchRead (UnsafePrefetchRead* x); virtual void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x); virtual void do_ProfileCall (ProfileCall* x); + virtual void do_ProfileReturnType (ProfileReturnType* x); virtual void do_ProfileInvoke (ProfileInvoke* x); virtual void do_RuntimeCall (RuntimeCall* x); virtual void do_MemBar (MemBar* x); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/c1/c1_LinearScan.cpp --- a/src/share/vm/c1/c1_LinearScan.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/c1/c1_LinearScan.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -75,9 +75,9 @@ // Map BasicType to spill size in 32-bit words, matching VMReg's notion of words #ifdef _LP64 -static int type2spill_size[T_CONFLICT+1]={ -1, 0, 0, 0, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 0, 1, -1}; +static int type2spill_size[T_CONFLICT+1]={ -1, 0, 0, 0, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 0, 2, 1, 2, 1, -1}; #else -static int type2spill_size[T_CONFLICT+1]={ -1, 0, 0, 0, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 0, 1, -1}; +static int type2spill_size[T_CONFLICT+1]={ -1, 0, 0, 0, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 0, 1, -1, 1, 1, -1}; #endif diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/c1/c1_Optimizer.cpp --- a/src/share/vm/c1/c1_Optimizer.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/c1/c1_Optimizer.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -531,6 +531,7 @@ void do_UnsafePrefetchRead (UnsafePrefetchRead* x); void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x); void do_ProfileCall (ProfileCall* x); + void do_ProfileReturnType (ProfileReturnType* x); void do_ProfileInvoke (ProfileInvoke* x); void do_RuntimeCall (RuntimeCall* x); void do_MemBar (MemBar* x); @@ -657,6 +658,8 @@ void handle_Intrinsic (Intrinsic* x); void handle_ExceptionObject (ExceptionObject* x); void handle_Phi (Phi* x); + void handle_ProfileCall (ProfileCall* x); + void handle_ProfileReturnType (ProfileReturnType* x); }; @@ -715,7 +718,9 @@ void NullCheckVisitor::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) {} void NullCheckVisitor::do_UnsafePrefetchRead (UnsafePrefetchRead* x) {} void NullCheckVisitor::do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) {} -void NullCheckVisitor::do_ProfileCall (ProfileCall* x) { nce()->clear_last_explicit_null_check(); } +void NullCheckVisitor::do_ProfileCall (ProfileCall* x) { nce()->clear_last_explicit_null_check(); + nce()->handle_ProfileCall(x); } +void NullCheckVisitor::do_ProfileReturnType (ProfileReturnType* x) { nce()->handle_ProfileReturnType(x); } void NullCheckVisitor::do_ProfileInvoke (ProfileInvoke* x) {} void NullCheckVisitor::do_RuntimeCall (RuntimeCall* x) {} void NullCheckVisitor::do_MemBar (MemBar* x) {} @@ -1134,6 +1139,15 @@ } } +void NullCheckEliminator::handle_ProfileCall(ProfileCall* x) { + for (int i = 0; i < x->nb_profiled_args(); i++) { + x->set_arg_needs_null_check(i, !set_contains(x->profiled_arg_at(i))); + } +} + +void NullCheckEliminator::handle_ProfileReturnType(ProfileReturnType* x) { + x->set_needs_null_check(!set_contains(x->ret())); +} void Optimizer::eliminate_null_checks() { ResourceMark rm; diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/c1/c1_RangeCheckElimination.hpp --- a/src/share/vm/c1/c1_RangeCheckElimination.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/c1/c1_RangeCheckElimination.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -162,7 +162,8 @@ void do_UnsafePrefetchRead (UnsafePrefetchRead* x) { /* nothing to do */ }; void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) { /* nothing to do */ }; void do_ProfileCall (ProfileCall* x) { /* nothing to do */ }; - void do_ProfileInvoke (ProfileInvoke* x) { /* nothing to do */ }; + void do_ProfileReturnType (ProfileReturnType* x) { /* nothing to do */ }; + void do_ProfileInvoke (ProfileInvoke* x) { /* nothing to do */ }; void do_RuntimeCall (RuntimeCall* x) { /* nothing to do */ }; void do_MemBar (MemBar* x) { /* nothing to do */ }; void do_RangeCheckPredicate(RangeCheckPredicate* x) { /* nothing to do */ }; diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/c1/c1_Runtime1.cpp --- a/src/share/vm/c1/c1_Runtime1.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/c1/c1_Runtime1.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -542,8 +542,7 @@ // exception handler can cause class loading, which might throw an // exception and those fields are expected to be clear during // normal bytecode execution. - thread->set_exception_oop(NULL); - thread->set_exception_pc(NULL); + thread->clear_exception_oop_and_pc(); continuation = SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, false, false); // If an exception was thrown during exception dispatch, the exception oop may have changed diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/c1/c1_ValueMap.hpp --- a/src/share/vm/c1/c1_ValueMap.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/c1/c1_ValueMap.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -203,6 +203,7 @@ void do_UnsafePrefetchRead (UnsafePrefetchRead* x) { /* nothing to do */ } void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) { /* nothing to do */ } void do_ProfileCall (ProfileCall* x) { /* nothing to do */ } + void do_ProfileReturnType (ProfileReturnType* x) { /* nothing to do */ } void do_ProfileInvoke (ProfileInvoke* x) { /* nothing to do */ }; void do_RuntimeCall (RuntimeCall* x) { /* nothing to do */ }; void do_MemBar (MemBar* x) { /* nothing to do */ }; diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/c1/c1_globals.hpp --- a/src/share/vm/c1/c1_globals.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/c1/c1_globals.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -341,6 +341,8 @@ diagnostic(bool, C1PatchInvokeDynamic, true, \ "Patch invokedynamic appendix not known at compile time") \ \ + develop(intx, MaxForceInlineLevel, 100, \ + "maximum number of nested @ForceInline calls that are inlined") \ \ diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/ci/ciClassList.hpp --- a/src/share/vm/ci/ciClassList.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/ci/ciClassList.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -102,6 +102,7 @@ friend class ciMethodHandle; \ friend class ciMethodType; \ friend class ciReceiverTypeData; \ +friend class ciTypeEntries; \ friend class ciSymbol; \ friend class ciArray; \ friend class ciObjArray; \ diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/ci/ciEnv.cpp --- a/src/share/vm/ci/ciEnv.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/ci/ciEnv.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -483,8 +483,7 @@ { // We have to lock the cpool to keep the oop from being resolved // while we are accessing it. - oop cplock = cpool->lock(); - ObjectLocker ol(cplock, THREAD, cplock != NULL); + MonitorLockerEx ml(cpool->lock()); constantTag tag = cpool->tag_at(index); if (tag.is_klass()) { // The klass has been inserted into the constant pool @@ -1154,9 +1153,12 @@ GUARDED_VM_ENTRY(return _factory->get_unloaded_object_constant();) } -void ciEnv::dump_replay_data(outputStream* out) { - VM_ENTRY_MARK; - MutexLocker ml(Compile_lock); +// ------------------------------------------------------------------ +// ciEnv::dump_replay_data* + +// Don't change thread state and acquire any locks. +// Safe to call from VM error reporter. +void ciEnv::dump_replay_data_unsafe(outputStream* out) { ResourceMark rm; #if INCLUDE_JVMTI out->print_cr("JvmtiExport can_access_local_variables %d", _jvmti_can_access_local_variables); @@ -1181,3 +1183,10 @@ entry_bci, comp_level); out->flush(); } + +void ciEnv::dump_replay_data(outputStream* out) { + GUARDED_VM_ENTRY( + MutexLocker ml(Compile_lock); + dump_replay_data_unsafe(out); + ) +} diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/ci/ciEnv.hpp --- a/src/share/vm/ci/ciEnv.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/ci/ciEnv.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -452,6 +452,7 @@ // Dump the compilation replay data for the ciEnv to the stream. void dump_replay_data(outputStream* out); + void dump_replay_data_unsafe(outputStream* out); }; #endif // SHARE_VM_CI_CIENV_HPP diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/ci/ciInstanceKlass.cpp --- a/src/share/vm/ci/ciInstanceKlass.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/ci/ciInstanceKlass.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -671,7 +671,6 @@ void ciInstanceKlass::dump_replay_data(outputStream* out) { - ASSERT_IN_VM; ResourceMark rm; InstanceKlass* ik = get_instanceKlass(); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/ci/ciInstanceKlass.hpp --- a/src/share/vm/ci/ciInstanceKlass.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/ci/ciInstanceKlass.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -235,6 +235,13 @@ bool is_instance_klass() const { return true; } bool is_java_klass() const { return true; } + virtual ciKlass* exact_klass() { + if (is_loaded() && is_final() && !is_interface()) { + return this; + } + return NULL; + } + // Dump the current state of this klass for compilation replay. virtual void dump_replay_data(outputStream* out); }; diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/ci/ciKlass.cpp --- a/src/share/vm/ci/ciKlass.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/ci/ciKlass.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -66,7 +66,9 @@ // ------------------------------------------------------------------ // ciKlass::is_subtype_of bool ciKlass::is_subtype_of(ciKlass* that) { - assert(is_loaded() && that->is_loaded(), "must be loaded"); + assert(this->is_loaded(), err_msg("must be loaded: %s", this->name()->as_quoted_ascii())); + assert(that->is_loaded(), err_msg("must be loaded: %s", that->name()->as_quoted_ascii())); + // Check to see if the klasses are identical. if (this == that) { return true; @@ -83,8 +85,8 @@ // ------------------------------------------------------------------ // ciKlass::is_subclass_of bool ciKlass::is_subclass_of(ciKlass* that) { - assert(is_loaded() && that->is_loaded(), "must be loaded"); - // Check to see if the klasses are identical. + assert(this->is_loaded(), err_msg("must be loaded: %s", this->name()->as_quoted_ascii())); + assert(that->is_loaded(), err_msg("must be loaded: %s", that->name()->as_quoted_ascii())); VM_ENTRY_MARK; Klass* this_klass = get_Klass(); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/ci/ciKlass.hpp --- a/src/share/vm/ci/ciKlass.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/ci/ciKlass.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -41,6 +41,7 @@ friend class ciEnv; friend class ciField; friend class ciMethod; + friend class ciMethodData; friend class ciObjArrayKlass; private: @@ -121,6 +122,8 @@ // What kind of ciObject is this? bool is_klass() const { return true; } + virtual ciKlass* exact_klass() = 0; + void print_name_on(outputStream* st); }; diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/ci/ciMethod.cpp --- a/src/share/vm/ci/ciMethod.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/ci/ciMethod.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -565,6 +565,116 @@ if (_limit < MorphismLimit) _limit++; } + +void ciMethod::assert_virtual_call_type_ok(int bci) { + assert(java_code_at_bci(bci) == Bytecodes::_invokevirtual || + java_code_at_bci(bci) == Bytecodes::_invokeinterface, err_msg("unexpected bytecode %s", Bytecodes::name(java_code_at_bci(bci)))); +} + +void ciMethod::assert_call_type_ok(int bci) { + assert(java_code_at_bci(bci) == Bytecodes::_invokestatic || + java_code_at_bci(bci) == Bytecodes::_invokespecial || + java_code_at_bci(bci) == Bytecodes::_invokedynamic, err_msg("unexpected bytecode %s", Bytecodes::name(java_code_at_bci(bci)))); +} + +/** + * Check whether profiling provides a type for the argument i to the + * call at bci bci + * + * @param bci bci of the call + * @param i argument number + * @return profiled type + * + * If the profile reports that the argument may be null, return false + * at least for now. + */ +ciKlass* ciMethod::argument_profiled_type(int bci, int i) { + if (MethodData::profile_parameters() && method_data() != NULL && method_data()->is_mature()) { + ciProfileData* data = method_data()->bci_to_data(bci); + if (data != NULL) { + if (data->is_VirtualCallTypeData()) { + assert_virtual_call_type_ok(bci); + ciVirtualCallTypeData* call = (ciVirtualCallTypeData*)data->as_VirtualCallTypeData(); + if (i >= call->number_of_arguments()) { + return NULL; + } + ciKlass* type = call->valid_argument_type(i); + if (type != NULL && !call->argument_maybe_null(i)) { + return type; + } + } else if (data->is_CallTypeData()) { + assert_call_type_ok(bci); + ciCallTypeData* call = (ciCallTypeData*)data->as_CallTypeData(); + if (i >= call->number_of_arguments()) { + return NULL; + } + ciKlass* type = call->valid_argument_type(i); + if (type != NULL && !call->argument_maybe_null(i)) { + return type; + } + } + } + } + return NULL; +} + +/** + * Check whether profiling provides a type for the return value from + * the call at bci bci + * + * @param bci bci of the call + * @return profiled type + * + * If the profile reports that the argument may be null, return false + * at least for now. + */ +ciKlass* ciMethod::return_profiled_type(int bci) { + if (MethodData::profile_return() && method_data() != NULL && method_data()->is_mature()) { + ciProfileData* data = method_data()->bci_to_data(bci); + if (data != NULL) { + if (data->is_VirtualCallTypeData()) { + assert_virtual_call_type_ok(bci); + ciVirtualCallTypeData* call = (ciVirtualCallTypeData*)data->as_VirtualCallTypeData(); + ciKlass* type = call->valid_return_type(); + if (type != NULL && !call->return_maybe_null()) { + return type; + } + } else if (data->is_CallTypeData()) { + assert_call_type_ok(bci); + ciCallTypeData* call = (ciCallTypeData*)data->as_CallTypeData(); + ciKlass* type = call->valid_return_type(); + if (type != NULL && !call->return_maybe_null()) { + return type; + } + } + } + } + return NULL; +} + +/** + * Check whether profiling provides a type for the parameter i + * + * @param i parameter number + * @return profiled type + * + * If the profile reports that the argument may be null, return false + * at least for now. + */ +ciKlass* ciMethod::parameter_profiled_type(int i) { + if (MethodData::profile_parameters() && method_data() != NULL && method_data()->is_mature()) { + ciParametersTypeData* parameters = method_data()->parameters_type_data(); + if (parameters != NULL && i < parameters->number_of_parameters()) { + ciKlass* type = parameters->valid_parameter_type(i); + if (type != NULL && !parameters->parameter_maybe_null(i)) { + return type; + } + } + } + return NULL; +} + + // ------------------------------------------------------------------ // ciMethod::find_monomorphic_target // @@ -846,7 +956,9 @@ // Return true if allocation was successful or no MDO is required. bool ciMethod::ensure_method_data(methodHandle h_m) { EXCEPTION_CONTEXT; - if (is_native() || is_abstract() || h_m()->is_accessor()) return true; + if (is_native() || is_abstract() || h_m()->is_accessor()) { + return true; + } if (h_m()->method_data() == NULL) { Method::build_interpreter_method_data(h_m, THREAD); if (HAS_PENDING_EXCEPTION) { @@ -903,22 +1015,21 @@ // NULL otherwise. ciMethodData* ciMethod::method_data_or_null() { ciMethodData *md = method_data(); - if (md->is_empty()) return NULL; + if (md->is_empty()) { + return NULL; + } return md; } // ------------------------------------------------------------------ // ciMethod::ensure_method_counters // -address ciMethod::ensure_method_counters() { +MethodCounters* ciMethod::ensure_method_counters() { check_is_loaded(); VM_ENTRY_MARK; methodHandle mh(THREAD, get_Method()); - MethodCounters *counter = mh->method_counters(); - if (counter == NULL) { - counter = Method::build_method_counters(mh(), CHECK_AND_CLEAR_NULL); - } - return (address)counter; + MethodCounters* method_counters = mh->get_method_counters(CHECK_NULL); + return method_counters; } // ------------------------------------------------------------------ @@ -1247,7 +1358,6 @@ #undef FETCH_FLAG_FROM_VM void ciMethod::dump_replay_data(outputStream* st) { - ASSERT_IN_VM; ResourceMark rm; Method* method = get_Method(); MethodCounters* mcs = method->method_counters(); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/ci/ciMethod.hpp --- a/src/share/vm/ci/ciMethod.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/ci/ciMethod.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -117,6 +117,10 @@ *bcp = code; } + // Check bytecode and profile data collected are compatible + void assert_virtual_call_type_ok(int bci); + void assert_call_type_ok(int bci); + public: // Basic method information. ciFlags flags() const { check_is_loaded(); return _flags; } @@ -230,6 +234,11 @@ ciCallProfile call_profile_at_bci(int bci); int interpreter_call_site_count(int bci); + // Does type profiling provide a useful type at this point? + ciKlass* argument_profiled_type(int bci, int i); + ciKlass* parameter_profiled_type(int i); + ciKlass* return_profiled_type(int bci); + ciField* get_field_at_bci( int bci, bool &will_link); ciMethod* get_method_at_bci(int bci, bool &will_link, ciSignature* *declared_signature); @@ -265,7 +274,7 @@ bool is_klass_loaded(int refinfo_index, bool must_be_resolved) const; bool check_call(int refinfo_index, bool is_static) const; bool ensure_method_data(); // make sure it exists in the VM also - address ensure_method_counters(); + MethodCounters* ensure_method_counters(); int instructions_size(); int scale_count(int count, float prof_factor = 1.); // make MDO count commensurate with IIC diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/ci/ciMethodData.cpp --- a/src/share/vm/ci/ciMethodData.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/ci/ciMethodData.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -53,6 +53,7 @@ _hint_di = first_di(); // Initialize the escape information (to "don't know."); _eflags = _arg_local = _arg_stack = _arg_returned = 0; + _parameters = NULL; } // ------------------------------------------------------------------ @@ -74,11 +75,14 @@ _hint_di = first_di(); // Initialize the escape information (to "don't know."); _eflags = _arg_local = _arg_stack = _arg_returned = 0; + _parameters = NULL; } void ciMethodData::load_data() { MethodData* mdo = get_MethodData(); - if (mdo == NULL) return; + if (mdo == NULL) { + return; + } // To do: don't copy the data if it is not "ripe" -- require a minimum # // of invocations. @@ -106,6 +110,12 @@ ci_data = next_data(ci_data); data = mdo->next_data(data); } + if (mdo->parameters_type_data() != NULL) { + _parameters = data_layout_at(mdo->parameters_type_data_di()); + ciParametersTypeData* parameters = new ciParametersTypeData(_parameters); + parameters->translate_from(mdo->parameters_type_data()); + } + // Note: Extra data are all BitData, and do not need translation. _current_mileage = MethodData::mileage_of(mdo->method()); _invocation_counter = mdo->invocation_count(); @@ -123,7 +133,7 @@ #endif } -void ciReceiverTypeData::translate_receiver_data_from(ProfileData* data) { +void ciReceiverTypeData::translate_receiver_data_from(const ProfileData* data) { for (uint row = 0; row < row_limit(); row++) { Klass* k = data->as_ReceiverTypeData()->receiver(row); if (k != NULL) { @@ -134,6 +144,18 @@ } +void ciTypeStackSlotEntries::translate_type_data_from(const TypeStackSlotEntries* entries) { + for (int i = 0; i < _number_of_entries; i++) { + intptr_t k = entries->type(i); + TypeStackSlotEntries::set_type(i, translate_klass(k)); + } +} + +void ciReturnTypeEntry::translate_type_data_from(const ReturnTypeEntry* ret) { + intptr_t k = ret->type(); + set_type(translate_klass(k)); +} + // Get the data at an arbitrary (sort of) data index. ciProfileData* ciMethodData::data_at(int data_index) { if (out_of_bounds(data_index)) { @@ -164,6 +186,12 @@ return new ciMultiBranchData(data_layout); case DataLayout::arg_info_data_tag: return new ciArgInfoData(data_layout); + case DataLayout::call_type_data_tag: + return new ciCallTypeData(data_layout); + case DataLayout::virtual_call_type_data_tag: + return new ciVirtualCallTypeData(data_layout); + case DataLayout::parameters_type_data_tag: + return new ciParametersTypeData(data_layout); }; } @@ -286,6 +314,42 @@ } } +void ciMethodData::set_argument_type(int bci, int i, ciKlass* k) { + VM_ENTRY_MARK; + MethodData* mdo = get_MethodData(); + if (mdo != NULL) { + ProfileData* data = mdo->bci_to_data(bci); + if (data->is_CallTypeData()) { + data->as_CallTypeData()->set_argument_type(i, k->get_Klass()); + } else { + assert(data->is_VirtualCallTypeData(), "no arguments!"); + data->as_VirtualCallTypeData()->set_argument_type(i, k->get_Klass()); + } + } +} + +void ciMethodData::set_parameter_type(int i, ciKlass* k) { + VM_ENTRY_MARK; + MethodData* mdo = get_MethodData(); + if (mdo != NULL) { + mdo->parameters_type_data()->set_type(i, k->get_Klass()); + } +} + +void ciMethodData::set_return_type(int bci, ciKlass* k) { + VM_ENTRY_MARK; + MethodData* mdo = get_MethodData(); + if (mdo != NULL) { + ProfileData* data = mdo->bci_to_data(bci); + if (data->is_CallTypeData()) { + data->as_CallTypeData()->set_return_type(k->get_Klass()); + } else { + assert(data->is_VirtualCallTypeData(), "no arguments!"); + data->as_VirtualCallTypeData()->set_return_type(k->get_Klass()); + } + } +} + bool ciMethodData::has_escape_info() { return eflag_set(MethodData::estimated); } @@ -373,7 +437,6 @@ } void ciMethodData::dump_replay_data(outputStream* out) { - ASSERT_IN_VM; ResourceMark rm; MethodData* mdo = get_MethodData(); Method* method = mdo->method(); @@ -477,7 +540,50 @@ } } -void ciReceiverTypeData::print_receiver_data_on(outputStream* st) { +void ciTypeEntries::print_ciklass(outputStream* st, intptr_t k) { + if (TypeEntries::is_type_none(k)) { + st->print("none"); + } else if (TypeEntries::is_type_unknown(k)) { + st->print("unknown"); + } else { + valid_ciklass(k)->print_name_on(st); + } + if (TypeEntries::was_null_seen(k)) { + st->print(" (null seen)"); + } +} + +void ciTypeStackSlotEntries::print_data_on(outputStream* st) const { + for (int i = 0; i < _number_of_entries; i++) { + _pd->tab(st); + st->print("%d: stack (%u) ", i, stack_slot(i)); + print_ciklass(st, type(i)); + st->cr(); + } +} + +void ciReturnTypeEntry::print_data_on(outputStream* st) const { + _pd->tab(st); + st->print("ret "); + print_ciklass(st, type()); + st->cr(); +} + +void ciCallTypeData::print_data_on(outputStream* st) const { + print_shared(st, "ciCallTypeData"); + if (has_arguments()) { + tab(st, true); + st->print("argument types"); + args()->print_data_on(st); + } + if (has_return()) { + tab(st, true); + st->print("return type"); + ret()->print_data_on(st); + } +} + +void ciReceiverTypeData::print_receiver_data_on(outputStream* st) const { uint row; int entries = 0; for (row = 0; row < row_limit(); row++) { @@ -493,13 +599,33 @@ } } -void ciReceiverTypeData::print_data_on(outputStream* st) { +void ciReceiverTypeData::print_data_on(outputStream* st) const { print_shared(st, "ciReceiverTypeData"); print_receiver_data_on(st); } -void ciVirtualCallData::print_data_on(outputStream* st) { +void ciVirtualCallData::print_data_on(outputStream* st) const { print_shared(st, "ciVirtualCallData"); rtd_super()->print_receiver_data_on(st); } + +void ciVirtualCallTypeData::print_data_on(outputStream* st) const { + print_shared(st, "ciVirtualCallTypeData"); + rtd_super()->print_receiver_data_on(st); + if (has_arguments()) { + tab(st, true); + st->print("argument types"); + args()->print_data_on(st); + } + if (has_return()) { + tab(st, true); + st->print("return type"); + ret()->print_data_on(st); + } +} + +void ciParametersTypeData::print_data_on(outputStream* st) const { + st->print_cr("Parametertypes"); + parameters()->print_data_on(st); +} #endif diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/ci/ciMethodData.hpp --- a/src/share/vm/ci/ciMethodData.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/ci/ciMethodData.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -41,6 +41,9 @@ class ciArrayData; class ciMultiBranchData; class ciArgInfoData; +class ciCallTypeData; +class ciVirtualCallTypeData; +class ciParametersTypeData; typedef ProfileData ciProfileData; @@ -59,6 +62,119 @@ ciJumpData(DataLayout* layout) : JumpData(layout) {}; }; +class ciTypeEntries { +protected: + static intptr_t translate_klass(intptr_t k) { + Klass* v = TypeEntries::valid_klass(k); + if (v != NULL) { + ciKlass* klass = CURRENT_ENV->get_klass(v); + return with_status(klass, k); + } + return with_status(NULL, k); + } + +public: + static ciKlass* valid_ciklass(intptr_t k) { + if (!TypeEntries::is_type_none(k) && + !TypeEntries::is_type_unknown(k)) { + return (ciKlass*)TypeEntries::klass_part(k); + } else { + return NULL; + } + } + + static intptr_t with_status(ciKlass* k, intptr_t in) { + return TypeEntries::with_status((intptr_t)k, in); + } + +#ifndef PRODUCT + static void print_ciklass(outputStream* st, intptr_t k); +#endif +}; + +class ciTypeStackSlotEntries : public TypeStackSlotEntries, ciTypeEntries { +public: + void translate_type_data_from(const TypeStackSlotEntries* args); + + ciKlass* valid_type(int i) const { + return valid_ciklass(type(i)); + } + + bool maybe_null(int i) const { + return was_null_seen(type(i)); + } + +#ifndef PRODUCT + void print_data_on(outputStream* st) const; +#endif +}; + +class ciReturnTypeEntry : public ReturnTypeEntry, ciTypeEntries { +public: + void translate_type_data_from(const ReturnTypeEntry* ret); + + ciKlass* valid_type() const { + return valid_ciklass(type()); + } + + bool maybe_null() const { + return was_null_seen(type()); + } + +#ifndef PRODUCT + void print_data_on(outputStream* st) const; +#endif +}; + +class ciCallTypeData : public CallTypeData { +public: + ciCallTypeData(DataLayout* layout) : CallTypeData(layout) {} + + ciTypeStackSlotEntries* args() const { return (ciTypeStackSlotEntries*)CallTypeData::args(); } + ciReturnTypeEntry* ret() const { return (ciReturnTypeEntry*)CallTypeData::ret(); } + + void translate_from(const ProfileData* data) { + if (has_arguments()) { + args()->translate_type_data_from(data->as_CallTypeData()->args()); + } + if (has_return()) { + ret()->translate_type_data_from(data->as_CallTypeData()->ret()); + } + } + + intptr_t argument_type(int i) const { + assert(has_arguments(), "no arg type profiling data"); + return args()->type(i); + } + + ciKlass* valid_argument_type(int i) const { + assert(has_arguments(), "no arg type profiling data"); + return args()->valid_type(i); + } + + intptr_t return_type() const { + assert(has_return(), "no ret type profiling data"); + return ret()->type(); + } + + ciKlass* valid_return_type() const { + assert(has_return(), "no ret type profiling data"); + return ret()->valid_type(); + } + + bool argument_maybe_null(int i) const { + return args()->maybe_null(i); + } + + bool return_maybe_null() const { + return ret()->maybe_null(); + } + +#ifndef PRODUCT + void print_data_on(outputStream* st) const; +#endif +}; + class ciReceiverTypeData : public ReceiverTypeData { public: ciReceiverTypeData(DataLayout* layout) : ReceiverTypeData(layout) {}; @@ -69,7 +185,7 @@ (intptr_t) recv); } - ciKlass* receiver(uint row) { + ciKlass* receiver(uint row) const { assert((uint)row < row_limit(), "oob"); ciKlass* recv = (ciKlass*)intptr_at(receiver0_offset + row * receiver_type_row_cell_count); assert(recv == NULL || recv->is_klass(), "wrong type"); @@ -77,19 +193,19 @@ } // Copy & translate from oop based ReceiverTypeData - virtual void translate_from(ProfileData* data) { + virtual void translate_from(const ProfileData* data) { translate_receiver_data_from(data); } - void translate_receiver_data_from(ProfileData* data); + void translate_receiver_data_from(const ProfileData* data); #ifndef PRODUCT - void print_data_on(outputStream* st); - void print_receiver_data_on(outputStream* st); + void print_data_on(outputStream* st) const; + void print_receiver_data_on(outputStream* st) const; #endif }; class ciVirtualCallData : public VirtualCallData { // Fake multiple inheritance... It's a ciReceiverTypeData also. - ciReceiverTypeData* rtd_super() { return (ciReceiverTypeData*) this; } + ciReceiverTypeData* rtd_super() const { return (ciReceiverTypeData*) this; } public: ciVirtualCallData(DataLayout* layout) : VirtualCallData(layout) {}; @@ -103,11 +219,73 @@ } // Copy & translate from oop based VirtualCallData - virtual void translate_from(ProfileData* data) { + virtual void translate_from(const ProfileData* data) { rtd_super()->translate_receiver_data_from(data); } #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; +#endif +}; + +class ciVirtualCallTypeData : public VirtualCallTypeData { +private: + // Fake multiple inheritance... It's a ciReceiverTypeData also. + ciReceiverTypeData* rtd_super() const { return (ciReceiverTypeData*) this; } +public: + ciVirtualCallTypeData(DataLayout* layout) : VirtualCallTypeData(layout) {} + + void set_receiver(uint row, ciKlass* recv) { + rtd_super()->set_receiver(row, recv); + } + + ciKlass* receiver(uint row) const { + return rtd_super()->receiver(row); + } + + ciTypeStackSlotEntries* args() const { return (ciTypeStackSlotEntries*)VirtualCallTypeData::args(); } + ciReturnTypeEntry* ret() const { return (ciReturnTypeEntry*)VirtualCallTypeData::ret(); } + + // Copy & translate from oop based VirtualCallData + virtual void translate_from(const ProfileData* data) { + rtd_super()->translate_receiver_data_from(data); + if (has_arguments()) { + args()->translate_type_data_from(data->as_VirtualCallTypeData()->args()); + } + if (has_return()) { + ret()->translate_type_data_from(data->as_VirtualCallTypeData()->ret()); + } + } + + intptr_t argument_type(int i) const { + assert(has_arguments(), "no arg type profiling data"); + return args()->type(i); + } + + ciKlass* valid_argument_type(int i) const { + assert(has_arguments(), "no arg type profiling data"); + return args()->valid_type(i); + } + + intptr_t return_type() const { + assert(has_return(), "no ret type profiling data"); + return ret()->type(); + } + + ciKlass* valid_return_type() const { + assert(has_return(), "no ret type profiling data"); + return ret()->valid_type(); + } + + bool argument_maybe_null(int i) const { + return args()->maybe_null(i); + } + + bool return_maybe_null() const { + return ret()->maybe_null(); + } + +#ifndef PRODUCT + void print_data_on(outputStream* st) const; #endif }; @@ -137,6 +315,29 @@ ciArgInfoData(DataLayout* layout) : ArgInfoData(layout) {}; }; +class ciParametersTypeData : public ParametersTypeData { +public: + ciParametersTypeData(DataLayout* layout) : ParametersTypeData(layout) {} + + virtual void translate_from(const ProfileData* data) { + parameters()->translate_type_data_from(data->as_ParametersTypeData()->parameters()); + } + + ciTypeStackSlotEntries* parameters() const { return (ciTypeStackSlotEntries*)ParametersTypeData::parameters(); } + + ciKlass* valid_parameter_type(int i) const { + return parameters()->valid_type(i); + } + + bool parameter_maybe_null(int i) const { + return parameters()->maybe_null(i); + } + +#ifndef PRODUCT + void print_data_on(outputStream* st) const; +#endif +}; + // ciMethodData // // This class represents a MethodData* in the HotSpot virtual @@ -182,6 +383,10 @@ // Coherent snapshot of original header. MethodData _orig; + // Dedicated area dedicated to parameters. Null if no parameter + // profiling for this method. + DataLayout* _parameters; + ciMethodData(MethodData* md); ciMethodData(); @@ -232,8 +437,6 @@ public: bool is_method_data() const { return true; } - void set_mature() { _state = mature_state; } - bool is_empty() { return _state == empty_state; } bool is_mature() { return _state == mature_state; } @@ -249,6 +452,11 @@ // Also set the numer of loops and blocks in the method. // Again, this is used to determine if a method is trivial. void set_compilation_stats(short loops, short blocks); + // If the compiler finds a profiled type that is known statically + // for sure, set it in the MethodData + void set_argument_type(int bci, int i, ciKlass* k); + void set_parameter_type(int i, ciKlass* k); + void set_return_type(int bci, ciKlass* k); void load_data(); @@ -312,6 +520,10 @@ bool is_arg_returned(int i) const; uint arg_modified(int arg) const; + ciParametersTypeData* parameters_type_data() const { + return _parameters != NULL ? new ciParametersTypeData(_parameters) : NULL; + } + // Code generation helper ByteSize offset_of_slot(ciProfileData* data, ByteSize slot_offset_in_data); int byte_offset_of_slot(ciProfileData* data, ByteSize slot_offset_in_data) { return in_bytes(offset_of_slot(data, slot_offset_in_data)); } diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/ci/ciObjArrayKlass.cpp --- a/src/share/vm/ci/ciObjArrayKlass.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/ci/ciObjArrayKlass.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -179,3 +179,16 @@ ciObjArrayKlass* ciObjArrayKlass::make(ciKlass* element_klass) { GUARDED_VM_ENTRY(return make_impl(element_klass);) } + +ciKlass* ciObjArrayKlass::exact_klass() { + ciType* base = base_element_type(); + if (base->is_instance_klass()) { + ciInstanceKlass* ik = base->as_instance_klass(); + if (ik->exact_klass() != NULL) { + return this; + } + } else if (base->is_primitive_type()) { + return this; + } + return NULL; +} diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/ci/ciObjArrayKlass.hpp --- a/src/share/vm/ci/ciObjArrayKlass.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/ci/ciObjArrayKlass.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -73,6 +73,8 @@ bool is_obj_array_klass() const { return true; } static ciObjArrayKlass* make(ciKlass* element_klass); + + virtual ciKlass* exact_klass(); }; #endif // SHARE_VM_CI_CIOBJARRAYKLASS_HPP diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/ci/ciReplay.cpp --- a/src/share/vm/ci/ciReplay.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/ci/ciReplay.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -965,14 +965,12 @@ tty->cr(); } else { EXCEPTION_CONTEXT; - MethodCounters* mcs = method->method_counters(); // m->_instructions_size = rec->instructions_size; m->_instructions_size = -1; m->_interpreter_invocation_count = rec->interpreter_invocation_count; m->_interpreter_throwout_count = rec->interpreter_throwout_count; - if (mcs == NULL) { - mcs = Method::build_method_counters(method, CHECK_AND_CLEAR); - } + MethodCounters* mcs = method->get_method_counters(CHECK_AND_CLEAR); + guarantee(mcs != NULL, "method counters allocation failed"); mcs->invocation_counter()->_counter = rec->invocation_counter; mcs->backedge_counter()->_counter = rec->backedge_counter; } diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/ci/ciStreams.hpp --- a/src/share/vm/ci/ciStreams.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/ci/ciStreams.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -277,11 +277,14 @@ class ciSignatureStream : public StackObj { private: ciSignature* _sig; - int _pos; + int _pos; + // holder is a method's holder + ciKlass* _holder; public: - ciSignatureStream(ciSignature* signature) { + ciSignatureStream(ciSignature* signature, ciKlass* holder = NULL) { _sig = signature; _pos = 0; + _holder = holder; } bool at_return_type() { return _pos == _sig->count(); } @@ -301,6 +304,23 @@ return _sig->type_at(_pos); } } + + // next klass in the signature + ciKlass* next_klass() { + ciKlass* sig_k; + if (_holder != NULL) { + sig_k = _holder; + _holder = NULL; + } else { + while (!type()->is_klass()) { + next(); + } + assert(!at_return_type(), "passed end of signature"); + sig_k = type()->as_klass(); + next(); + } + return sig_k; + } }; diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/ci/ciTypeArrayKlass.hpp --- a/src/share/vm/ci/ciTypeArrayKlass.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/ci/ciTypeArrayKlass.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -57,6 +57,10 @@ // Make an array klass corresponding to the specified primitive type. static ciTypeArrayKlass* make(BasicType type); + + virtual ciKlass* exact_klass() { + return this; + } }; #endif // SHARE_VM_CI_CITYPEARRAYKLASS_HPP diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/classfile/defaultMethods.cpp --- a/src/share/vm/classfile/defaultMethods.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/classfile/defaultMethods.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -857,7 +857,6 @@ m->set_max_locals(params); m->constMethod()->set_stackmap_data(NULL); m->set_code(code_start); - m->set_force_inline(true); return m; } diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/classfile/systemDictionary.cpp --- a/src/share/vm/classfile/systemDictionary.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/classfile/systemDictionary.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -2360,6 +2360,11 @@ objArrayHandle appendix_box = oopFactory::new_objArray(SystemDictionary::Object_klass(), 1, CHECK_(empty)); assert(appendix_box->obj_at(0) == NULL, ""); + // This should not happen. JDK code should take care of that. + if (accessing_klass.is_null() || method_type.is_null()) { + THROW_MSG_(vmSymbols::java_lang_InternalError(), "bad invokehandle", empty); + } + // call java.lang.invoke.MethodHandleNatives::linkMethod(... String, MethodType) -> MemberName JavaCallArguments args; args.push_oop(accessing_klass()->java_mirror()); @@ -2485,6 +2490,9 @@ Handle type; if (signature->utf8_length() > 0 && signature->byte_at(0) == '(') { type = find_method_handle_type(signature, caller, CHECK_(empty)); + } else if (caller.is_null()) { + // This should not happen. JDK code should take care of that. + THROW_MSG_(vmSymbols::java_lang_InternalError(), "bad MH constant", empty); } else { ResourceMark rm(THREAD); SignatureStream ss(signature, false); @@ -2548,6 +2556,11 @@ Handle method_name = java_lang_String::create_from_symbol(name, CHECK_(empty)); Handle method_type = find_method_handle_type(type, caller, CHECK_(empty)); + // This should not happen. JDK code should take care of that. + if (caller.is_null() || method_type.is_null()) { + THROW_MSG_(vmSymbols::java_lang_InternalError(), "bad invokedynamic", empty); + } + objArrayHandle appendix_box = oopFactory::new_objArray(SystemDictionary::Object_klass(), 1, CHECK_(empty)); assert(appendix_box->obj_at(0) == NULL, ""); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/classfile/vmSymbols.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -624,6 +624,7 @@ do_class(java_lang_StrictMath, "java/lang/StrictMath") \ do_signature(double2_double_signature, "(DD)D") \ do_signature(int2_int_signature, "(II)I") \ + do_signature(long2_long_signature, "(JJ)J") \ \ /* here are the math names, all together: */ \ do_name(abs_name,"abs") do_name(sin_name,"sin") do_name(cos_name,"cos") \ @@ -632,8 +633,11 @@ do_name(exp_name,"exp") do_name(min_name,"min") do_name(max_name,"max") \ \ do_name(addExact_name,"addExact") \ + do_name(decrementExact_name,"decrementExact") \ + do_name(incrementExact_name,"incrementExact") \ + do_name(multiplyExact_name,"multiplyExact") \ + do_name(negateExact_name,"negateExact") \ do_name(subtractExact_name,"subtractExact") \ - do_name(multiplyExact_name,"multiplyExact") \ \ do_intrinsic(_dabs, java_lang_Math, abs_name, double_double_signature, F_S) \ do_intrinsic(_dsin, java_lang_Math, sin_name, double_double_signature, F_S) \ @@ -647,7 +651,18 @@ do_intrinsic(_dexp, java_lang_Math, exp_name, double_double_signature, F_S) \ do_intrinsic(_min, java_lang_Math, min_name, int2_int_signature, F_S) \ do_intrinsic(_max, java_lang_Math, max_name, int2_int_signature, F_S) \ - do_intrinsic(_addExact, java_lang_Math, addExact_name, int2_int_signature, F_S) \ + do_intrinsic(_addExactI, java_lang_Math, addExact_name, int2_int_signature, F_S) \ + do_intrinsic(_addExactL, java_lang_Math, addExact_name, long2_long_signature, F_S) \ + do_intrinsic(_decrementExactI, java_lang_Math, decrementExact_name, int_int_signature, F_S) \ + do_intrinsic(_decrementExactL, java_lang_Math, decrementExact_name, long2_long_signature, F_S) \ + do_intrinsic(_incrementExactI, java_lang_Math, incrementExact_name, int_int_signature, F_S) \ + do_intrinsic(_incrementExactL, java_lang_Math, incrementExact_name, long2_long_signature, F_S) \ + do_intrinsic(_multiplyExactI, java_lang_Math, multiplyExact_name, int2_int_signature, F_S) \ + do_intrinsic(_multiplyExactL, java_lang_Math, multiplyExact_name, long2_long_signature, F_S) \ + do_intrinsic(_negateExactI, java_lang_Math, negateExact_name, int_int_signature, F_S) \ + do_intrinsic(_negateExactL, java_lang_Math, negateExact_name, long_long_signature, F_S) \ + do_intrinsic(_subtractExactI, java_lang_Math, subtractExact_name, int2_int_signature, F_S) \ + do_intrinsic(_subtractExactL, java_lang_Math, subtractExact_name, long2_long_signature, F_S) \ \ do_intrinsic(_floatToRawIntBits, java_lang_Float, floatToRawIntBits_name, float_int_signature, F_S) \ do_name( floatToRawIntBits_name, "floatToRawIntBits") \ diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/code/codeBlob.cpp --- a/src/share/vm/code/codeBlob.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/code/codeBlob.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -245,8 +245,8 @@ } -void* BufferBlob::operator new(size_t s, unsigned size) throw() { - void* p = CodeCache::allocate(size); +void* BufferBlob::operator new(size_t s, unsigned size, bool is_critical) throw() { + void* p = CodeCache::allocate(size, is_critical); return p; } @@ -277,7 +277,10 @@ unsigned int size = allocation_size(cb, sizeof(AdapterBlob)); { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - blob = new (size) AdapterBlob(size, cb); + // The parameter 'true' indicates a critical memory allocation. + // This means that CodeCacheMinimumFreeSpace is used, if necessary + const bool is_critical = true; + blob = new (size, is_critical) AdapterBlob(size, cb); } // Track memory usage statistic after releasing CodeCache_lock MemoryService::track_code_cache_memory_usage(); @@ -299,7 +302,10 @@ size += round_to(buffer_size, oopSize); { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - blob = new (size) MethodHandlesAdapterBlob(size); + // The parameter 'true' indicates a critical memory allocation. + // This means that CodeCacheMinimumFreeSpace is used, if necessary + const bool is_critical = true; + blob = new (size, is_critical) MethodHandlesAdapterBlob(size); } // Track memory usage statistic after releasing CodeCache_lock MemoryService::track_code_cache_memory_usage(); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/code/codeBlob.hpp --- a/src/share/vm/code/codeBlob.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/code/codeBlob.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -209,7 +209,7 @@ BufferBlob(const char* name, int size); BufferBlob(const char* name, int size, CodeBuffer* cb); - void* operator new(size_t s, unsigned size) throw(); + void* operator new(size_t s, unsigned size, bool is_critical = false) throw(); public: // Creation @@ -253,7 +253,6 @@ class MethodHandlesAdapterBlob: public BufferBlob { private: MethodHandlesAdapterBlob(int size) : BufferBlob("MethodHandles adapters", size) {} - MethodHandlesAdapterBlob(int size, CodeBuffer* cb) : BufferBlob("MethodHandles adapters", size, cb) {} public: // Creation diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/compiler/abstractCompiler.cpp --- a/src/share/vm/compiler/abstractCompiler.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/compiler/abstractCompiler.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -24,41 +24,42 @@ #include "precompiled.hpp" #include "compiler/abstractCompiler.hpp" +#include "compiler/compileBroker.hpp" #include "runtime/mutexLocker.hpp" -void AbstractCompiler::initialize_runtimes(initializer f, volatile int* state) { - if (*state != initialized) { + +bool AbstractCompiler::should_perform_init() { + if (_compiler_state != initialized) { + MutexLocker only_one(CompileThread_lock); - // We are thread in native here... - CompilerThread* thread = CompilerThread::current(); - bool do_initialization = false; - { - ThreadInVMfromNative tv(thread); - ResetNoHandleMark rnhm; - MutexLocker only_one(CompileThread_lock, thread); - if ( *state == uninitialized) { - do_initialization = true; - *state = initializing; - } else { - while (*state == initializing ) { - CompileThread_lock->wait(); - } + if (_compiler_state == uninitialized) { + _compiler_state = initializing; + return true; + } else { + while (_compiler_state == initializing) { + CompileThread_lock->wait(); } } - if (do_initialization) { - // We can not hold any locks here since JVMTI events may call agents + } + return false; +} - // Compiler(s) run as native - - (*f)(); - - // To in_vm so we can use the lock +bool AbstractCompiler::should_perform_shutdown() { + // Since this method can be called by multiple threads, the lock ensures atomicity of + // decrementing '_num_compiler_threads' and the following operations. + MutexLocker only_one(CompileThread_lock); + _num_compiler_threads--; + assert (CompileBroker::is_compilation_disabled_forever(), "Must be set, otherwise thread waits forever"); - ThreadInVMfromNative tv(thread); - ResetNoHandleMark rnhm; - MutexLocker only_one(CompileThread_lock, thread); - assert(*state == initializing, "wrong state"); - *state = initialized; - CompileThread_lock->notify_all(); - } + // Only the last thread will perform shutdown operations + if (_num_compiler_threads == 0) { + return true; } + return false; } + +void AbstractCompiler::set_state(int state) { + // Ensure that ste is only set by one thread at a time + MutexLocker only_one(CompileThread_lock); + _compiler_state = state; + CompileThread_lock->notify_all(); +} diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/compiler/abstractCompiler.hpp --- a/src/share/vm/compiler/abstractCompiler.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/compiler/abstractCompiler.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -27,22 +27,25 @@ #include "ci/compilerInterface.hpp" -typedef void (*initializer)(void); - class AbstractCompiler : public CHeapObj { private: - bool _is_initialized; // Mark whether compiler object is initialized + volatile int _num_compiler_threads; protected: + volatile int _compiler_state; // Used for tracking global state of compiler runtime initialization - enum { uninitialized, initializing, initialized }; + enum { uninitialized, initializing, initialized, failed, shut_down }; - // This method will call the initialization method "f" once (per compiler class/subclass) - // and do so without holding any locks - void initialize_runtimes(initializer f, volatile int* state); + // This method returns true for the first compiler thread that reaches that methods. + // This thread will initialize the compiler runtime. + bool should_perform_init(); public: - AbstractCompiler() : _is_initialized(false) {} + AbstractCompiler() : _compiler_state(uninitialized), _num_compiler_threads(0) {} + + // This function determines the compiler thread that will perform the + // shutdown of the corresponding compiler runtime. + bool should_perform_shutdown(); // Name of this compiler virtual const char* name() = 0; @@ -74,17 +77,18 @@ #endif // TIERED // Customization - virtual bool needs_stubs () = 0; + virtual void initialize () = 0; - void mark_initialized() { _is_initialized = true; } - bool is_initialized() { return _is_initialized; } + void set_num_compiler_threads(int num) { _num_compiler_threads = num; } + int num_compiler_threads() { return _num_compiler_threads; } - virtual void initialize() = 0; - + // Get/set state of compiler objects + bool is_initialized() { return _compiler_state == initialized; } + bool is_failed () { return _compiler_state == failed;} + void set_state (int state); + void set_shut_down () { set_state(shut_down); } // Compilation entry point for methods - virtual void compile_method(ciEnv* env, - ciMethod* target, - int entry_bci) { + virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci) { ShouldNotReachHere(); } diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/compiler/compileBroker.cpp --- a/src/share/vm/compiler/compileBroker.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/compiler/compileBroker.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -186,7 +186,7 @@ CompileQueue* CompileBroker::_c1_method_queue = NULL; CompileTask* CompileBroker::_task_free_list = NULL; -GrowableArray* CompileBroker::_method_threads = NULL; +GrowableArray* CompileBroker::_compiler_threads = NULL; class CompilationLog : public StringEventLog { @@ -587,9 +587,6 @@ -// ------------------------------------------------------------------ -// CompileQueue::add -// // Add a CompileTask to a CompileQueue void CompileQueue::add(CompileTask* task) { assert(lock()->owned_by_self(), "must own lock"); @@ -626,6 +623,16 @@ lock()->notify_all(); } +void CompileQueue::delete_all() { + assert(lock()->owned_by_self(), "must own lock"); + if (_first != NULL) { + for (CompileTask* task = _first; task != NULL; task = task->next()) { + delete task; + } + _first = NULL; + } +} + // ------------------------------------------------------------------ // CompileQueue::get // @@ -640,6 +647,11 @@ // case we perform code cache sweeps to free memory such that we can re-enable // compilation. while (_first == NULL) { + // Exit loop if compilation is disabled forever + if (CompileBroker::is_compilation_disabled_forever()) { + return NULL; + } + if (UseCodeCacheFlushing && !CompileBroker::should_compile_new_jobs()) { // Wait a certain amount of time to possibly do another sweep. // We must wait until stack scanning has happened so that we can @@ -664,9 +676,17 @@ // remains unchanged. This behavior is desired, since we want to keep // the stable state, i.e., we do not want to evict methods from the // code cache if it is unnecessary. - lock()->wait(); + // We need a timed wait here, since compiler threads can exit if compilation + // is disabled forever. We use 5 seconds wait time; the exiting of compiler threads + // is not critical and we do not want idle compiler threads to wake up too often. + lock()->wait(!Mutex::_no_safepoint_check_flag, 5*1000); } } + + if (CompileBroker::is_compilation_disabled_forever()) { + return NULL; + } + CompileTask* task = CompilationPolicy::policy()->select_task(this); remove(task); return task; @@ -891,10 +911,8 @@ } - -// ------------------------------------------------------------------ -// CompileBroker::make_compiler_thread -CompilerThread* CompileBroker::make_compiler_thread(const char* name, CompileQueue* queue, CompilerCounters* counters, TRAPS) { +CompilerThread* CompileBroker::make_compiler_thread(const char* name, CompileQueue* queue, CompilerCounters* counters, + AbstractCompiler* comp, TRAPS) { CompilerThread* compiler_thread = NULL; Klass* k = @@ -961,6 +979,7 @@ java_lang_Thread::set_daemon(thread_oop()); compiler_thread->set_threadObj(thread_oop()); + compiler_thread->set_compiler(comp); Threads::add(compiler_thread); Thread::start(compiler_thread); } @@ -972,25 +991,24 @@ } -// ------------------------------------------------------------------ -// CompileBroker::init_compiler_threads -// -// Initialize the compilation queue void CompileBroker::init_compiler_threads(int c1_compiler_count, int c2_compiler_count) { EXCEPTION_MARK; #if !defined(ZERO) && !defined(SHARK) assert(c2_compiler_count > 0 || c1_compiler_count > 0, "No compilers?"); #endif // !ZERO && !SHARK + // Initialize the compilation queue if (c2_compiler_count > 0) { _c2_method_queue = new CompileQueue("C2MethodQueue", MethodCompileQueue_lock); + _compilers[1]->set_num_compiler_threads(c2_compiler_count); } if (c1_compiler_count > 0) { _c1_method_queue = new CompileQueue("C1MethodQueue", MethodCompileQueue_lock); + _compilers[0]->set_num_compiler_threads(c1_compiler_count); } int compiler_count = c1_compiler_count + c2_compiler_count; - _method_threads = + _compiler_threads = new (ResourceObj::C_HEAP, mtCompiler) GrowableArray(compiler_count, true); char name_buffer[256]; @@ -998,21 +1016,22 @@ // Create a name for our thread. sprintf(name_buffer, "C2 CompilerThread%d", i); CompilerCounters* counters = new CompilerCounters("compilerThread", i, CHECK); - CompilerThread* new_thread = make_compiler_thread(name_buffer, _c2_method_queue, counters, CHECK); - _method_threads->append(new_thread); + // Shark and C2 + CompilerThread* new_thread = make_compiler_thread(name_buffer, _c2_method_queue, counters, _compilers[1], CHECK); + _compiler_threads->append(new_thread); } for (int i = c2_compiler_count; i < compiler_count; i++) { // Create a name for our thread. sprintf(name_buffer, "C1 CompilerThread%d", i); CompilerCounters* counters = new CompilerCounters("compilerThread", i, CHECK); - CompilerThread* new_thread = make_compiler_thread(name_buffer, _c1_method_queue, counters, CHECK); - _method_threads->append(new_thread); + // C1 + CompilerThread* new_thread = make_compiler_thread(name_buffer, _c1_method_queue, counters, _compilers[0], CHECK); + _compiler_threads->append(new_thread); } if (UsePerfData) { - PerfDataManager::create_constant(SUN_CI, "threads", PerfData::U_Bytes, - compiler_count, CHECK); + PerfDataManager::create_constant(SUN_CI, "threads", PerfData::U_Bytes, compiler_count, CHECK); } } @@ -1029,27 +1048,6 @@ } // ------------------------------------------------------------------ -// CompileBroker::is_idle -bool CompileBroker::is_idle() { - if (_c2_method_queue != NULL && !_c2_method_queue->is_empty()) { - return false; - } else if (_c1_method_queue != NULL && !_c1_method_queue->is_empty()) { - return false; - } else { - int num_threads = _method_threads->length(); - for (int i=0; iat(i)->task() != NULL) { - return false; - } - } - - // No pending or active compilations. - return true; - } -} - - -// ------------------------------------------------------------------ // CompileBroker::compile_method // // Request compilation of a method. @@ -1299,13 +1297,6 @@ method->jmethod_id(); } - // If the compiler is shut off due to code cache getting full - // fail out now so blocking compiles dont hang the java thread - if (!should_compile_new_jobs()) { - CompilationPolicy::policy()->delay_compilation(method()); - return NULL; - } - // do the compilation if (method->is_native()) { if (!PreferInterpreterNativeStubs || method->is_method_handle_intrinsic()) { @@ -1315,11 +1306,22 @@ MutexLocker locker(MethodCompileQueue_lock, THREAD); compile_id = assign_compile_id(method, standard_entry_bci); } + // To properly handle the appendix argument for out-of-line calls we are using a small trampoline that + // pops off the appendix argument and jumps to the target (see gen_special_dispatch in SharedRuntime). + // + // Since normal compiled-to-compiled calls are not able to handle such a thing we MUST generate an adapter + // in this case. If we can't generate one and use it we can not execute the out-of-line method handle calls. (void) AdapterHandlerLibrary::create_native_wrapper(method, compile_id); } else { return NULL; } } else { + // If the compiler is shut off due to code cache getting full + // fail out now so blocking compiles dont hang the java thread + if (!should_compile_new_jobs()) { + CompilationPolicy::policy()->delay_compilation(method()); + return NULL; + } compile_method_base(method, osr_bci, comp_level, hot_method, hot_count, comment, THREAD); } @@ -1551,6 +1553,101 @@ free_task(task); } +// Initialize compiler thread(s) + compiler object(s). The postcondition +// of this function is that the compiler runtimes are initialized and that +//compiler threads can start compiling. +bool CompileBroker::init_compiler_runtime() { + CompilerThread* thread = CompilerThread::current(); + AbstractCompiler* comp = thread->compiler(); + // Final sanity check - the compiler object must exist + guarantee(comp != NULL, "Compiler object must exist"); + + int system_dictionary_modification_counter; + { + MutexLocker locker(Compile_lock, thread); + system_dictionary_modification_counter = SystemDictionary::number_of_modifications(); + } + + { + // Must switch to native to allocate ci_env + ThreadToNativeFromVM ttn(thread); + ciEnv ci_env(NULL, system_dictionary_modification_counter); + // Cache Jvmti state + ci_env.cache_jvmti_state(); + // Cache DTrace flags + ci_env.cache_dtrace_flags(); + + // Switch back to VM state to do compiler initialization + ThreadInVMfromNative tv(thread); + ResetNoHandleMark rnhm; + + + if (!comp->is_shark()) { + // Perform per-thread and global initializations + comp->initialize(); + } + } + + if (comp->is_failed()) { + disable_compilation_forever(); + // If compiler initialization failed, no compiler thread that is specific to a + // particular compiler runtime will ever start to compile methods. + + shutdown_compiler_runtime(comp, thread); + return false; + } + + // C1 specific check + if (comp->is_c1() && (thread->get_buffer_blob() == NULL)) { + warning("Initialization of %s thread failed (no space to run compilers)", thread->name()); + return false; + } + + return true; +} + +// If C1 and/or C2 initialization failed, we shut down all compilation. +// We do this to keep things simple. This can be changed if it ever turns out to be +// a problem. +void CompileBroker::shutdown_compiler_runtime(AbstractCompiler* comp, CompilerThread* thread) { + // Free buffer blob, if allocated + if (thread->get_buffer_blob() != NULL) { + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + CodeCache::free(thread->get_buffer_blob()); + } + + if (comp->should_perform_shutdown()) { + // There are two reasons for shutting down the compiler + // 1) compiler runtime initialization failed + // 2) The code cache is full and the following flag is set: -XX:-UseCodeCacheFlushing + warning("Shutting down compiler %s (no space to run compilers)", comp->name()); + + // Only one thread per compiler runtime object enters here + // Set state to shut down + comp->set_shut_down(); + + MutexLocker mu(MethodCompileQueue_lock, thread); + CompileQueue* queue; + if (_c1_method_queue != NULL) { + _c1_method_queue->delete_all(); + queue = _c1_method_queue; + _c1_method_queue = NULL; + delete _c1_method_queue; + } + + if (_c2_method_queue != NULL) { + _c2_method_queue->delete_all(); + queue = _c2_method_queue; + _c2_method_queue = NULL; + delete _c2_method_queue; + } + + // We could delete compiler runtimes also. However, there are references to + // the compiler runtime(s) (e.g., nmethod::is_compiled_by_c1()) which then + // fail. This can be done later if necessary. + } +} + // ------------------------------------------------------------------ // CompileBroker::compiler_thread_loop // @@ -1558,7 +1655,6 @@ void CompileBroker::compiler_thread_loop() { CompilerThread* thread = CompilerThread::current(); CompileQueue* queue = thread->queue(); - // For the thread that initializes the ciObjectFactory // this resource mark holds all the shared objects ResourceMark rm; @@ -1587,65 +1683,78 @@ log->end_elem(); } - while (true) { - { - // We need this HandleMark to avoid leaking VM handles. - HandleMark hm(thread); + // If compiler thread/runtime initialization fails, exit the compiler thread + if (!init_compiler_runtime()) { + return; + } - if (CodeCache::unallocated_capacity() < CodeCacheMinimumFreeSpace) { - // the code cache is really full - handle_full_code_cache(); - } + // Poll for new compilation tasks as long as the JVM runs. Compilation + // should only be disabled if something went wrong while initializing the + // compiler runtimes. This, in turn, should not happen. The only known case + // when compiler runtime initialization fails is if there is not enough free + // space in the code cache to generate the necessary stubs, etc. + while (!is_compilation_disabled_forever()) { + // We need this HandleMark to avoid leaking VM handles. + HandleMark hm(thread); - CompileTask* task = queue->get(); + if (CodeCache::unallocated_capacity() < CodeCacheMinimumFreeSpace) { + // the code cache is really full + handle_full_code_cache(); + } - // Give compiler threads an extra quanta. They tend to be bursty and - // this helps the compiler to finish up the job. - if( CompilerThreadHintNoPreempt ) - os::hint_no_preempt(); + CompileTask* task = queue->get(); + if (task == NULL) { + continue; + } - // trace per thread time and compile statistics - CompilerCounters* counters = ((CompilerThread*)thread)->counters(); - PerfTraceTimedEvent(counters->time_counter(), counters->compile_counter()); + // Give compiler threads an extra quanta. They tend to be bursty and + // this helps the compiler to finish up the job. + if( CompilerThreadHintNoPreempt ) + os::hint_no_preempt(); - // Assign the task to the current thread. Mark this compilation - // thread as active for the profiler. - CompileTaskWrapper ctw(task); - nmethodLocker result_handle; // (handle for the nmethod produced by this task) - task->set_code_handle(&result_handle); - methodHandle method(thread, task->method()); + // trace per thread time and compile statistics + CompilerCounters* counters = ((CompilerThread*)thread)->counters(); + PerfTraceTimedEvent(counters->time_counter(), counters->compile_counter()); - // Never compile a method if breakpoints are present in it - if (method()->number_of_breakpoints() == 0) { - // Compile the method. - if ((UseCompiler || AlwaysCompileLoopMethods) && CompileBroker::should_compile_new_jobs()) { + // Assign the task to the current thread. Mark this compilation + // thread as active for the profiler. + CompileTaskWrapper ctw(task); + nmethodLocker result_handle; // (handle for the nmethod produced by this task) + task->set_code_handle(&result_handle); + methodHandle method(thread, task->method()); + + // Never compile a method if breakpoints are present in it + if (method()->number_of_breakpoints() == 0) { + // Compile the method. + if ((UseCompiler || AlwaysCompileLoopMethods) && CompileBroker::should_compile_new_jobs()) { #ifdef COMPILER1 - // Allow repeating compilations for the purpose of benchmarking - // compile speed. This is not useful for customers. - if (CompilationRepeat != 0) { - int compile_count = CompilationRepeat; - while (compile_count > 0) { - invoke_compiler_on_method(task); - nmethod* nm = method->code(); - if (nm != NULL) { - nm->make_zombie(); - method->clear_code(); - } - compile_count--; + // Allow repeating compilations for the purpose of benchmarking + // compile speed. This is not useful for customers. + if (CompilationRepeat != 0) { + int compile_count = CompilationRepeat; + while (compile_count > 0) { + invoke_compiler_on_method(task); + nmethod* nm = method->code(); + if (nm != NULL) { + nm->make_zombie(); + method->clear_code(); } + compile_count--; } + } #endif /* COMPILER1 */ - invoke_compiler_on_method(task); - } else { - // After compilation is disabled, remove remaining methods from queue - method->clear_queued_for_compilation(); - } + invoke_compiler_on_method(task); + } else { + // After compilation is disabled, remove remaining methods from queue + method->clear_queued_for_compilation(); } } } + + // Shut down compiler runtime + shutdown_compiler_runtime(thread->compiler(), thread); } - // ------------------------------------------------------------------ // CompileBroker::init_compiler_thread_log // @@ -1953,11 +2062,14 @@ // Since code cache is full, immediately stop new compiles if (CompileBroker::set_should_compile_new_jobs(CompileBroker::stop_compilation)) { NMethodSweeper::log_sweep("disable_compiler"); + + // Switch to 'vm_state'. This ensures that possibly_sweep() can be called + // without having to consider the state in which the current thread is. + ThreadInVMfromUnknown in_vm; NMethodSweeper::possibly_sweep(); } } else { - UseCompiler = false; - AlwaysCompileLoopMethods = false; + disable_compilation_forever(); } } codecache_print(/* detailed= */ true); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/compiler/compileBroker.hpp --- a/src/share/vm/compiler/compileBroker.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/compiler/compileBroker.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -213,8 +213,12 @@ // Redefine Classes support void mark_on_stack(); + void delete_all(); + void print(); - void print(); + ~CompileQueue() { + assert (is_empty(), " Compile Queue must be empty"); + } }; // CompileTaskWrapper @@ -266,7 +270,7 @@ static CompileQueue* _c1_method_queue; static CompileTask* _task_free_list; - static GrowableArray* _method_threads; + static GrowableArray* _compiler_threads; // performance counters static PerfCounter* _perf_total_compilation; @@ -311,7 +315,7 @@ static int _sum_nmethod_code_size; static long _peak_compilation_time; - static CompilerThread* make_compiler_thread(const char* name, CompileQueue* queue, CompilerCounters* counters, TRAPS); + static CompilerThread* make_compiler_thread(const char* name, CompileQueue* queue, CompilerCounters* counters, AbstractCompiler* comp, TRAPS); static void init_compiler_threads(int c1_compiler_count, int c2_compiler_count); static bool compilation_is_complete (methodHandle method, int osr_bci, int comp_level); static bool compilation_is_prohibited(methodHandle method, int osr_bci, int comp_level); @@ -351,6 +355,9 @@ if (is_c1_compile(comp_level)) return _c1_method_queue; return NULL; } + static bool init_compiler_runtime(); + static void shutdown_compiler_runtime(AbstractCompiler* comp, CompilerThread* thread); + public: enum { // The entry bci used for non-OSR compilations. @@ -378,9 +385,7 @@ const char* comment, Thread* thread); static void compiler_thread_loop(); - static uint get_compilation_id() { return _compilation_id; } - static bool is_idle(); // Set _should_block. // Call this from the VM, with Threads_lock held and a safepoint requested. @@ -391,8 +396,9 @@ enum { // Flags for toggling compiler activity - stop_compilation = 0, - run_compilation = 1 + stop_compilation = 0, + run_compilation = 1, + shutdown_compilaton = 2 }; static bool should_compile_new_jobs() { return UseCompiler && (_should_compile_new_jobs == run_compilation); } @@ -401,6 +407,16 @@ jint old = Atomic::cmpxchg(new_state, &_should_compile_new_jobs, 1-new_state); return (old == (1-new_state)); } + + static void disable_compilation_forever() { + UseCompiler = false; + AlwaysCompileLoopMethods = false; + Atomic::xchg(shutdown_compilaton, &_should_compile_new_jobs); + } + + static bool is_compilation_disabled_forever() { + return _should_compile_new_jobs == shutdown_compilaton; + } static void handle_full_code_cache(); // Return total compilation ticks diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/gc_implementation/g1/g1AllocRegion.hpp --- a/src/share/vm/gc_implementation/g1/g1AllocRegion.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/g1AllocRegion.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -55,7 +55,7 @@ // then _alloc_region is NULL and this object should not be used to // satisfy allocation requests (it was done this way to force the // correct use of init() and release()). - HeapRegion* _alloc_region; + HeapRegion* volatile _alloc_region; // It keeps track of the distinct number of regions that are used // for allocation in the active interval of this object, i.e., @@ -132,8 +132,9 @@ static void setup(G1CollectedHeap* g1h, HeapRegion* dummy_region); HeapRegion* get() const { + HeapRegion * hr = _alloc_region; // Make sure that the dummy region does not escape this class. - return (_alloc_region == _dummy_region) ? NULL : _alloc_region; + return (hr == _dummy_region) ? NULL : hr; } uint count() { return _count; } diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -344,6 +344,10 @@ } } + if (FLAG_IS_CMDLINE(NewSize) && FLAG_IS_CMDLINE(MaxNewSize) && NewSize > MaxNewSize) { + vm_exit_during_initialization("Initial young gen size set larger than the maximum young gen size"); + } + if (FLAG_IS_CMDLINE(NewSize)) { _min_desired_young_length = MAX2((uint) (NewSize / HeapRegion::GrainBytes), 1U); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp --- a/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -187,19 +187,23 @@ size_t code_root_elems() const { return _code_root_elems; } void print_rs_mem_info_on(outputStream * out, size_t total) { - out->print_cr(" %8dK (%5.1f%%) by %zd %s regions", round_to_K(rs_mem_size()), rs_mem_size_percent_of(total), amount(), _name); + out->print_cr(" "SIZE_FORMAT_W(8)"K (%5.1f%%) by "SIZE_FORMAT" %s regions", + round_to_K(rs_mem_size()), rs_mem_size_percent_of(total), amount(), _name); } void print_cards_occupied_info_on(outputStream * out, size_t total) { - out->print_cr(" %8d (%5.1f%%) entries by %zd %s regions", cards_occupied(), cards_occupied_percent_of(total), amount(), _name); + out->print_cr(" "SIZE_FORMAT_W(8)" (%5.1f%%) entries by "SIZE_FORMAT" %s regions", + cards_occupied(), cards_occupied_percent_of(total), amount(), _name); } void print_code_root_mem_info_on(outputStream * out, size_t total) { - out->print_cr(" %8dK (%5.1f%%) by %zd %s regions", round_to_K(code_root_mem_size()), code_root_mem_size_percent_of(total), amount(), _name); + out->print_cr(" "SIZE_FORMAT_W(8)"K (%5.1f%%) by "SIZE_FORMAT" %s regions", + round_to_K(code_root_mem_size()), code_root_mem_size_percent_of(total), amount(), _name); } void print_code_root_elems_info_on(outputStream * out, size_t total) { - out->print_cr(" %8d (%5.1f%%) elements by %zd %s regions", code_root_elems(), code_root_elems_percent_of(total), amount(), _name); + out->print_cr(" "SIZE_FORMAT_W(8)" (%5.1f%%) elements by "SIZE_FORMAT" %s regions", + code_root_elems(), code_root_elems_percent_of(total), amount(), _name); } }; @@ -327,14 +331,14 @@ out->print_cr("\n Recent concurrent refinement statistics"); out->print_cr(" Processed "SIZE_FORMAT" cards", num_concurrent_refined_cards()); - out->print_cr(" Of %d completed buffers:", num_processed_buf_total()); - out->print_cr(" %8d (%5.1f%%) by concurrent RS threads.", + out->print_cr(" Of "SIZE_FORMAT" completed buffers:", num_processed_buf_total()); + out->print_cr(" "SIZE_FORMAT_W(8)" (%5.1f%%) by concurrent RS threads.", num_processed_buf_total(), percent_of(num_processed_buf_rs_threads(), num_processed_buf_total())); - out->print_cr(" %8d (%5.1f%%) by mutator threads.", + out->print_cr(" "SIZE_FORMAT_W(8)" (%5.1f%%) by mutator threads.", num_processed_buf_mutator(), percent_of(num_processed_buf_mutator(), num_processed_buf_total())); - out->print_cr(" Did %d coarsenings.", num_coarsenings()); + out->print_cr(" Did "SIZE_FORMAT" coarsenings.", num_coarsenings()); out->print_cr(" Concurrent RS threads times (s)"); out->print(" "); for (uint i = 0; i < _num_vtimes; i++) { diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/gc_implementation/shared/vmGCOperations.cpp --- a/src/share/vm/gc_implementation/shared/vmGCOperations.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/gc_implementation/shared/vmGCOperations.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -211,7 +211,7 @@ // a GC that freed space for the allocation. if (!MetadataAllocationFailALot) { _result = _loader_data->metaspace_non_null()->allocate(_size, _mdtype); - } + } if (_result == NULL) { if (UseConcMarkSweepGC) { @@ -223,9 +223,7 @@ _loader_data->metaspace_non_null()->expand_and_allocate(_size, _mdtype); } if (_result == NULL) { - // Don't clear the soft refs. This GC is for reclaiming metadata - // and is unrelated to the fullness of the Java heap which should - // be the criteria for clearing SoftReferences. + // Don't clear the soft refs yet. if (Verbose && PrintGCDetails && UseConcMarkSweepGC) { gclog_or_tty->print_cr("\nCMS full GC for Metaspace"); } @@ -235,7 +233,7 @@ _result = _loader_data->metaspace_non_null()->allocate(_size, _mdtype); } - if (_result == NULL && !UseConcMarkSweepGC /* CMS already tried */) { + if (_result == NULL) { // If still failing, allow the Metaspace to expand. // See delta_capacity_until_GC() for explanation of the // amount of the expansion. @@ -243,7 +241,16 @@ // or a MaxMetaspaceSize has been specified on the command line. _result = _loader_data->metaspace_non_null()->expand_and_allocate(_size, _mdtype); - + if (_result == NULL) { + // If expansion failed, do a last-ditch collection and try allocating + // again. A last-ditch collection will clear softrefs. This + // behavior is similar to the last-ditch collection done for perm + // gen when it was full and a collection for failed allocation + // did not free perm gen space. + heap->collect_as_vm_thread(GCCause::_last_ditch_collection); + _result = + _loader_data->metaspace_non_null()->allocate(_size, _mdtype); + } } if (Verbose && PrintGCDetails && _result == NULL) { gclog_or_tty->print_cr("\nAfter Metaspace GC failed to allocate size " diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/interpreter/abstractInterpreter.hpp --- a/src/share/vm/interpreter/abstractInterpreter.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/interpreter/abstractInterpreter.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -30,11 +30,8 @@ #include "runtime/thread.inline.hpp" #include "runtime/vmThread.hpp" #include "utilities/top.hpp" -#ifdef TARGET_ARCH_MODEL_x86_32 -# include "interp_masm_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 -# include "interp_masm_x86_64.hpp" +#ifdef TARGET_ARCH_x86 +# include "interp_masm_x86.hpp" #endif #ifdef TARGET_ARCH_MODEL_sparc # include "interp_masm_sparc.hpp" diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/interpreter/linkResolver.cpp --- a/src/share/vm/interpreter/linkResolver.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/interpreter/linkResolver.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -158,6 +158,22 @@ index = vt->index_of_miranda(resolved_method->name(), resolved_method->signature()); kind = CallInfo::vtable_call; + } else if (resolved_method->has_vtable_index()) { + // Can occur if an interface redeclares a method of Object. + +#ifdef ASSERT + // Ensure that this is really the case. + KlassHandle object_klass = SystemDictionary::Object_klass(); + Method * object_resolved_method = object_klass()->vtable()->method_at(index); + assert(object_resolved_method->name() == resolved_method->name(), + err_msg("Object and interface method names should match at vtable index %d, %s != %s", + index, object_resolved_method->name()->as_C_string(), resolved_method->name()->as_C_string())); + assert(object_resolved_method->signature() == resolved_method->signature(), + err_msg("Object and interface method signatures should match at vtable index %d, %s != %s", + index, object_resolved_method->signature()->as_C_string(), resolved_method->signature()->as_C_string())); +#endif // ASSERT + + kind = CallInfo::vtable_call; } else { // A regular interface call. kind = CallInfo::itable_call; @@ -248,7 +264,7 @@ void LinkResolver::lookup_instance_method_in_klasses(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) { Method* result_oop = klass->uncached_lookup_method(name, signature); result = methodHandle(THREAD, result_oop); - while (!result.is_null() && result->is_static()) { + while (!result.is_null() && result->is_static() && result->method_holder()->super() != NULL) { klass = KlassHandle(THREAD, result->method_holder()->super()); result = methodHandle(THREAD, klass->uncached_lookup_method(name, signature)); } @@ -402,18 +418,28 @@ AccessFlags flags = sel_method->access_flags(); - // Special case: arrays always override "clone". JVMS 2.15. + // Special case #1: arrays always override "clone". JVMS 2.15. // If the resolved klass is an array class, and the declaring class // is java.lang.Object and the method is "clone", set the flags // to public. + // Special case #2: If the resolved klass is an interface, and + // the declaring class is java.lang.Object, and the method is + // "clone" or "finalize", set the flags to public. If the + // resolved interface does not contain "clone" or "finalize" + // methods, the method/interface method resolution looks to + // the interface's super class, java.lang.Object. With JDK 8 + // interface accessability check requirement, special casing + // this scenario is necessary to avoid an IAE. // - // We'll check for the method name first, as that's most likely - // to be false (so we'll short-circuit out of these tests). - if (sel_method->name() == vmSymbols::clone_name() && - sel_klass() == SystemDictionary::Object_klass() && - resolved_klass->oop_is_array()) { + // We'll check for each method name first and then java.lang.Object + // to best short-circuit out of these tests. + if (((sel_method->name() == vmSymbols::clone_name() && + (resolved_klass->oop_is_array() || resolved_klass->is_interface())) || + (sel_method->name() == vmSymbols::finalize_method_name() && + resolved_klass->is_interface())) && + sel_klass() == SystemDictionary::Object_klass()) { // We need to change "protected" to "public". - assert(flags.is_protected(), "clone not protected?"); + assert(flags.is_protected(), "clone or finalize not protected?"); jint new_flags = flags.as_int(); new_flags = new_flags & (~JVM_ACC_PROTECTED); new_flags = new_flags | JVM_ACC_PUBLIC; @@ -454,7 +480,7 @@ Symbol* method_name = vmSymbols::invoke_name(); Symbol* method_signature = pool->signature_ref_at(index); KlassHandle current_klass(THREAD, pool->pool_holder()); - resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, CHECK); + resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, false, CHECK); return; } @@ -476,22 +502,34 @@ if (code == Bytecodes::_invokeinterface) { resolve_interface_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, CHECK); + } else if (code == Bytecodes::_invokevirtual) { + resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, true, CHECK); } else { - resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, CHECK); + resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, false, CHECK); } } void LinkResolver::resolve_method(methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, - KlassHandle current_klass, bool check_access, TRAPS) { + KlassHandle current_klass, bool check_access, + bool require_methodref, TRAPS) { Handle nested_exception; - // 1. lookup method in resolved klass and its super klasses + // 1. check if methodref required, that resolved_klass is not interfacemethodref + if (require_methodref && resolved_klass->is_interface()) { + ResourceMark rm(THREAD); + char buf[200]; + jio_snprintf(buf, sizeof(buf), "Found interface %s, but class was expected", + resolved_klass()->external_name()); + THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + } + + // 2. lookup method in resolved klass and its super klasses lookup_method_in_klasses(resolved_method, resolved_klass, method_name, method_signature, CHECK); if (resolved_method.is_null()) { // not found in the class hierarchy - // 2. lookup method in all the interfaces implemented by the resolved klass + // 3. lookup method in all the interfaces implemented by the resolved klass lookup_method_in_interfaces(resolved_method, resolved_klass, method_name, method_signature, CHECK); if (resolved_method.is_null()) { @@ -505,7 +543,7 @@ } if (resolved_method.is_null()) { - // 3. method lookup failed + // 4. method lookup failed ResourceMark rm(THREAD); THROW_MSG_CAUSE(vmSymbols::java_lang_NoSuchMethodError(), Method::name_and_sig_as_C_string(resolved_klass(), @@ -515,15 +553,6 @@ } } - // 4. check if klass is not interface - if (resolved_klass->is_interface() && resolved_method->is_abstract()) { - ResourceMark rm(THREAD); - char buf[200]; - jio_snprintf(buf, sizeof(buf), "Found interface %s, but class was expected", - resolved_klass()->external_name()); - THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); - } - // 5. check if method is concrete if (resolved_method->is_abstract() && !resolved_klass->is_abstract()) { ResourceMark rm(THREAD); @@ -833,7 +862,7 @@ Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS) { - resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK); + resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, false, CHECK); assert(resolved_method->name() != vmSymbols::class_initializer_name(), "should have been checked in verifier"); // check if static @@ -867,7 +896,7 @@ // and the selected method is recalculated relative to the direct superclass // superinterface.method, which explicitly does not check shadowing - resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK); + resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, false, CHECK); // check if method name is , that it is found in same klass as static type if (resolved_method->name() == vmSymbols::object_initializer_name() && @@ -1013,7 +1042,7 @@ Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS) { // normal method resolution - resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK); + resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, true, CHECK); assert(resolved_method->name() != vmSymbols::object_initializer_name(), "should have been checked in verifier"); assert(resolved_method->name() != vmSymbols::class_initializer_name (), "should have been checked in verifier"); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/interpreter/linkResolver.hpp --- a/src/share/vm/interpreter/linkResolver.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/interpreter/linkResolver.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -136,7 +136,7 @@ static void resolve_pool (KlassHandle& resolved_klass, Symbol*& method_name, Symbol*& method_signature, KlassHandle& current_klass, constantPoolHandle pool, int index, TRAPS); static void resolve_interface_method(methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS); - static void resolve_method (methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS); + static void resolve_method (methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, bool require_methodref, TRAPS); static void linktime_resolve_static_method (methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS); static void linktime_resolve_special_method (methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/interpreter/templateTable.hpp --- a/src/share/vm/interpreter/templateTable.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/interpreter/templateTable.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -28,11 +28,8 @@ #include "interpreter/bytecodes.hpp" #include "memory/allocation.hpp" #include "runtime/frame.hpp" -#ifdef TARGET_ARCH_MODEL_x86_32 -# include "interp_masm_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 -# include "interp_masm_x86_64.hpp" +#ifdef TARGET_ARCH_x86 +# include "interp_masm_x86.hpp" #endif #ifdef TARGET_ARCH_MODEL_sparc # include "interp_masm_sparc.hpp" diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/memory/binaryTreeDictionary.cpp --- a/src/share/vm/memory/binaryTreeDictionary.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/memory/binaryTreeDictionary.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -28,7 +28,6 @@ #include "memory/binaryTreeDictionary.hpp" #include "memory/freeList.hpp" #include "memory/freeBlockDictionary.hpp" -#include "memory/metablock.hpp" #include "memory/metachunk.hpp" #include "runtime/globals.hpp" #include "utilities/ostream.hpp" diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/memory/freeBlockDictionary.cpp --- a/src/share/vm/memory/freeBlockDictionary.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/memory/freeBlockDictionary.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -28,7 +28,6 @@ #include "gc_implementation/concurrentMarkSweep/freeChunk.hpp" #endif // INCLUDE_ALL_GCS #include "memory/freeBlockDictionary.hpp" -#include "memory/metablock.hpp" #include "memory/metachunk.hpp" #include "runtime/thread.inline.hpp" #include "utilities/macros.hpp" diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/memory/freeList.cpp --- a/src/share/vm/memory/freeList.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/memory/freeList.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -25,7 +25,6 @@ #include "precompiled.hpp" #include "memory/freeBlockDictionary.hpp" #include "memory/freeList.hpp" -#include "memory/metablock.hpp" #include "memory/metachunk.hpp" #include "memory/sharedHeap.hpp" #include "runtime/globals.hpp" diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/memory/metablock.cpp --- a/src/share/vm/memory/metablock.cpp Mon Oct 21 14:08:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2012, 2013, 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 "memory/allocation.hpp" -#include "memory/metablock.hpp" -#include "utilities/copy.hpp" -#include "utilities/debug.hpp" - -// Blocks of space for metadata are allocated out of Metachunks. -// -// Metachunk are allocated out of MetadataVirtualspaces and once -// allocated there is no explicit link between a Metachunk and -// the MetadataVirtualspaces from which it was allocated. -// -// Each SpaceManager maintains a -// list of the chunks it is using and the current chunk. The current -// chunk is the chunk from which allocations are done. Space freed in -// a chunk is placed on the free list of blocks (BlockFreelist) and -// reused from there. -// -// Future modification -// -// The Metachunk can conceivable be replaced by the Chunk in -// allocation.hpp. Note that the latter Chunk is the space for -// allocation (allocations from the chunk are out of the space in -// the Chunk after the header for the Chunk) where as Metachunks -// point to space in a VirtualSpace. To replace Metachunks with -// Chunks, change Chunks so that they can be allocated out of a VirtualSpace. -size_t Metablock::_min_block_byte_size = sizeof(Metablock); - -// New blocks returned by the Metaspace are zero initialized. -// We should fix the constructors to not assume this instead. -Metablock* Metablock::initialize(MetaWord* p, size_t word_size) { - if (p == NULL) { - return NULL; - } - - Metablock* result = (Metablock*) p; - - // Clear the memory - Copy::fill_to_aligned_words((HeapWord*)result, word_size); -#ifdef ASSERT - result->set_word_size(word_size); -#endif - return result; -} diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/memory/metablock.hpp --- a/src/share/vm/memory/metablock.hpp Mon Oct 21 14:08:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2012, 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_MEMORY_METABLOCK_HPP -#define SHARE_VM_MEMORY_METABLOCK_HPP - -// Metablock are the unit of allocation from a Chunk. It is initialized -// with the size of the requested allocation. That size is overwritten -// once the allocation returns. -// -// A Metablock may be reused by its SpaceManager but are never moved between -// SpaceManagers. There is no explicit link to the Metachunk -// from which it was allocated. Metablock may be deallocated and -// put on a freelist but the space is never freed, rather -// the Metachunk it is a part of will be deallocated when it's -// associated class loader is collected. - -class Metablock VALUE_OBJ_CLASS_SPEC { - friend class VMStructs; - private: - // Used to align the allocation (see below). - union block_t { - void* _data[3]; - struct header_t { - size_t _word_size; - Metablock* _next; - Metablock* _prev; - } _header; - } _block; - static size_t _min_block_byte_size; - - typedef union block_t Block; - typedef struct header_t Header; - const Block* block() const { return &_block; } - const Block::header_t* header() const { return &(block()->_header); } - public: - - static Metablock* initialize(MetaWord* p, size_t word_size); - - // This places the body of the block at a 2 word boundary - // because every block starts on a 2 word boundary. Work out - // how to make the body on a 2 word boundary if the block - // starts on a arbitrary boundary. JJJ - - size_t word_size() const { return header()->_word_size; } - void set_word_size(size_t v) { _block._header._word_size = v; } - size_t size() const volatile { return _block._header._word_size; } - void set_size(size_t v) { _block._header._word_size = v; } - Metablock* next() const { return header()->_next; } - void set_next(Metablock* v) { _block._header._next = v; } - Metablock* prev() const { return header()->_prev; } - void set_prev(Metablock* v) { _block._header._prev = v; } - - static size_t min_block_byte_size() { return _min_block_byte_size; } - - bool is_free() { return header()->_word_size != 0; } - void clear_next() { set_next(NULL); } - void link_prev(Metablock* ptr) { set_prev(ptr); } - uintptr_t* end() { return ((uintptr_t*) this) + size(); } - bool cantCoalesce() const { return false; } - void link_next(Metablock* ptr) { set_next(ptr); } - void link_after(Metablock* ptr){ - link_next(ptr); - if (ptr != NULL) ptr->link_prev(this); - } - - // Should not be needed in a free list of Metablocks - void markNotFree() { ShouldNotReachHere(); } - - // Debug support -#ifdef ASSERT - void* prev_addr() const { return (void*)&_block._header._prev; } - void* next_addr() const { return (void*)&_block._header._next; } - void* size_addr() const { return (void*)&_block._header._word_size; } -#endif - bool verify_chunk_in_free_list(Metablock* tc) const { return true; } - bool verify_par_locked() { return true; } - - void assert_is_mangled() const {/* Don't check "\*/} -}; -#endif // SHARE_VM_MEMORY_METABLOCK_HPP diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/memory/metachunk.cpp --- a/src/share/vm/memory/metachunk.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/memory/metachunk.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,42 +29,39 @@ #include "utilities/debug.hpp" class VirtualSpaceNode; -// -// Future modification -// -// The Metachunk can conceivable be replaced by the Chunk in -// allocation.hpp. Note that the latter Chunk is the space for -// allocation (allocations from the chunk are out of the space in -// the Chunk after the header for the Chunk) where as Metachunks -// point to space in a VirtualSpace. To replace Metachunks with -// Chunks, change Chunks so that they can be allocated out of a VirtualSpace. const size_t metadata_chunk_initialize = 0xf7f7f7f7; -size_t Metachunk::_overhead = - Chunk::aligned_overhead_size(sizeof(Metachunk)) / BytesPerWord; +size_t Metachunk::object_alignment() { + // Must align pointers and sizes to 8, + // so that 64 bit types get correctly aligned. + const size_t alignment = 8; + + // Make sure that the Klass alignment also agree. + STATIC_ASSERT(alignment == (size_t)KlassAlignmentInBytes); + + return alignment; +} + +size_t Metachunk::overhead() { + return align_size_up(sizeof(Metachunk), object_alignment()) / BytesPerWord; +} // Metachunk methods Metachunk::Metachunk(size_t word_size, - VirtualSpaceNode* container) : - _word_size(word_size), - _bottom(NULL), - _end(NULL), + VirtualSpaceNode* container) + : Metabase(word_size), _top(NULL), - _next(NULL), - _prev(NULL), _container(container) { - _bottom = (MetaWord*)this; - _top = (MetaWord*)this + _overhead; - _end = (MetaWord*)this + word_size; + _top = initial_top(); #ifdef ASSERT - set_is_free(false); + set_is_tagged_free(false); size_t data_word_size = pointer_delta(end(), - top(), + _top, sizeof(MetaWord)); - Copy::fill_to_words((HeapWord*) top(), + Copy::fill_to_words((HeapWord*)_top, data_word_size, metadata_chunk_initialize); #endif @@ -82,22 +79,18 @@ // _bottom points to the start of the chunk including the overhead. size_t Metachunk::used_word_size() const { - return pointer_delta(_top, _bottom, sizeof(MetaWord)); + return pointer_delta(_top, bottom(), sizeof(MetaWord)); } size_t Metachunk::free_word_size() const { - return pointer_delta(_end, _top, sizeof(MetaWord)); -} - -size_t Metachunk::capacity_word_size() const { - return pointer_delta(_end, _bottom, sizeof(MetaWord)); + return pointer_delta(end(), _top, sizeof(MetaWord)); } void Metachunk::print_on(outputStream* st) const { st->print_cr("Metachunk:" " bottom " PTR_FORMAT " top " PTR_FORMAT " end " PTR_FORMAT " size " SIZE_FORMAT, - bottom(), top(), end(), word_size()); + bottom(), _top, end(), word_size()); if (Verbose) { st->print_cr(" used " SIZE_FORMAT " free " SIZE_FORMAT, used_word_size(), free_word_size()); @@ -109,8 +102,8 @@ // Mangle the payload of the chunk and not the links that // maintain list of chunks. HeapWord* start = (HeapWord*)(bottom() + overhead()); - size_t word_size = capacity_word_size() - overhead(); - Copy::fill_to_words(start, word_size, metadata_chunk_initialize); + size_t size = word_size() - overhead(); + Copy::fill_to_words(start, size, metadata_chunk_initialize); } #endif // PRODUCT @@ -118,9 +111,68 @@ #ifdef ASSERT // Cannot walk through the blocks unless the blocks have // headers with sizes. - assert(_bottom <= _top && - _top <= _end, + assert(bottom() <= _top && + _top <= (MetaWord*)end(), "Chunk has been smashed"); #endif return; } + +/////////////// Unit tests /////////////// + +#ifndef PRODUCT + +class TestMetachunk { + public: + static void test() { + size_t size = 2 * 1024 * 1024; + void* memory = malloc(size); + assert(memory != NULL, "Failed to malloc 2MB"); + + Metachunk* metachunk = ::new (memory) Metachunk(size / BytesPerWord, NULL); + + assert(metachunk->bottom() == (MetaWord*)metachunk, "assert"); + assert(metachunk->end() == (uintptr_t*)metachunk + metachunk->size(), "assert"); + + // Check sizes + assert(metachunk->size() == metachunk->word_size(), "assert"); + assert(metachunk->word_size() == pointer_delta(metachunk->end(), metachunk->bottom(), + sizeof(MetaWord*)), "assert"); + + // Check usage + assert(metachunk->used_word_size() == metachunk->overhead(), "assert"); + assert(metachunk->free_word_size() == metachunk->word_size() - metachunk->used_word_size(), "assert"); + assert(metachunk->top() == metachunk->initial_top(), "assert"); + assert(metachunk->is_empty(), "assert"); + + // Allocate + size_t alloc_size = 64; // Words + assert(is_size_aligned(alloc_size, Metachunk::object_alignment()), "assert"); + + MetaWord* mem = metachunk->allocate(alloc_size); + + // Check post alloc + assert(mem == metachunk->initial_top(), "assert"); + assert(mem + alloc_size == metachunk->top(), "assert"); + assert(metachunk->used_word_size() == metachunk->overhead() + alloc_size, "assert"); + assert(metachunk->free_word_size() == metachunk->word_size() - metachunk->used_word_size(), "assert"); + assert(!metachunk->is_empty(), "assert"); + + // Clear chunk + metachunk->reset_empty(); + + // Check post clear + assert(metachunk->used_word_size() == metachunk->overhead(), "assert"); + assert(metachunk->free_word_size() == metachunk->word_size() - metachunk->used_word_size(), "assert"); + assert(metachunk->top() == metachunk->initial_top(), "assert"); + assert(metachunk->is_empty(), "assert"); + + free(memory); + } +}; + +void TestMetachunk_test() { + TestMetachunk::test(); +} + +#endif diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/memory/metachunk.hpp --- a/src/share/vm/memory/metachunk.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/memory/metachunk.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -24,89 +24,44 @@ #ifndef SHARE_VM_MEMORY_METACHUNK_HPP #define SHARE_VM_MEMORY_METACHUNK_HPP -// Metachunk - Quantum of allocation from a Virtualspace -// Metachunks are reused (when freed are put on a global freelist) and -// have no permanent association to a SpaceManager. - -// +--------------+ <- end -// | | --+ ---+ -// | | | free | -// | | | | -// | | | | capacity -// | | | | -// | | <- top --+ | -// | | ---+ | -// | | | used | -// | | | | -// | | | | -// +--------------+ <- bottom ---+ ---+ +#include "memory/allocation.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" class VirtualSpaceNode; -class Metachunk VALUE_OBJ_CLASS_SPEC { - // link to support lists of chunks - Metachunk* _next; - Metachunk* _prev; - VirtualSpaceNode* _container; - - MetaWord* _bottom; - MetaWord* _end; - MetaWord* _top; +// Super class of Metablock and Metachunk to allow them to +// be put on the FreeList and in the BinaryTreeDictionary. +template +class Metabase VALUE_OBJ_CLASS_SPEC { size_t _word_size; - // Used in a guarantee() so included in the Product builds - // even through it is only for debugging. - bool _is_free; + T* _next; + T* _prev; - // Metachunks are allocated out of a MetadataVirtualSpace and - // and use some of its space to describe itself (plus alignment - // considerations). Metadata is allocated in the rest of the chunk. - // This size is the overhead of maintaining the Metachunk within - // the space. - static size_t _overhead; + protected: + Metabase(size_t word_size) : _word_size(word_size), _next(NULL), _prev(NULL) {} public: - Metachunk(size_t word_size , VirtualSpaceNode* container); - - // Used to add a Metachunk to a list of Metachunks - void set_next(Metachunk* v) { _next = v; assert(v != this, "Boom");} - void set_prev(Metachunk* v) { _prev = v; assert(v != this, "Boom");} - void set_container(VirtualSpaceNode* v) { _container = v; } - - MetaWord* allocate(size_t word_size); + T* next() const { return _next; } + T* prev() const { return _prev; } + void set_next(T* v) { _next = v; assert(v != this, "Boom");} + void set_prev(T* v) { _prev = v; assert(v != this, "Boom");} + void clear_next() { set_next(NULL); } + void clear_prev() { set_prev(NULL); } - // Accessors - Metachunk* next() const { return _next; } - Metachunk* prev() const { return _prev; } - VirtualSpaceNode* container() const { return _container; } - MetaWord* bottom() const { return _bottom; } - MetaWord* end() const { return _end; } - MetaWord* top() const { return _top; } - size_t word_size() const { return _word_size; } size_t size() const volatile { return _word_size; } void set_size(size_t v) { _word_size = v; } - bool is_free() { return _is_free; } - void set_is_free(bool v) { _is_free = v; } - static size_t overhead() { return _overhead; } - void clear_next() { set_next(NULL); } - void link_prev(Metachunk* ptr) { set_prev(ptr); } - uintptr_t* end() { return ((uintptr_t*) this) + size(); } - bool cantCoalesce() const { return false; } - void link_next(Metachunk* ptr) { set_next(ptr); } - void link_after(Metachunk* ptr){ + + void link_next(T* ptr) { set_next(ptr); } + void link_prev(T* ptr) { set_prev(ptr); } + void link_after(T* ptr) { link_next(ptr); - if (ptr != NULL) ptr->link_prev(this); + if (ptr != NULL) ptr->link_prev((T*)this); } - // Reset top to bottom so chunk can be reused. - void reset_empty() { _top = (_bottom + _overhead); _next = NULL; _prev = NULL; } - bool is_empty() { return _top == (_bottom + _overhead); } + uintptr_t* end() const { return ((uintptr_t*) this) + size(); } - // used (has been allocated) - // free (available for future allocations) - // capacity (total size of chunk) - size_t used_word_size() const; - size_t free_word_size() const; - size_t capacity_word_size()const; + bool cantCoalesce() const { return false; } // Debug support #ifdef ASSERT @@ -114,14 +69,99 @@ void* next_addr() const { return (void*)&_next; } void* size_addr() const { return (void*)&_word_size; } #endif - bool verify_chunk_in_free_list(Metachunk* tc) const { return true; } + bool verify_chunk_in_free_list(T* tc) const { return true; } bool verify_par_locked() { return true; } void assert_is_mangled() const {/* Don't check "\*/} + bool is_free() { return true; } +}; + +// Metachunk - Quantum of allocation from a Virtualspace +// Metachunks are reused (when freed are put on a global freelist) and +// have no permanent association to a SpaceManager. + +// +--------------+ <- end --+ --+ +// | | | | +// | | | free | +// | | | | +// | | | | size | capacity +// | | | | +// | | <- top -- + | +// | | | | +// | | | used | +// | | | | +// | | | | +// +--------------+ <- bottom --+ --+ + +class Metachunk : public Metabase { + friend class TestMetachunk; + // The VirtualSpaceNode containing this chunk. + VirtualSpaceNode* _container; + + // Current allocation top. + MetaWord* _top; + + DEBUG_ONLY(bool _is_tagged_free;) + + MetaWord* initial_top() const { return (MetaWord*)this + overhead(); } + MetaWord* top() const { return _top; } + + public: + // Metachunks are allocated out of a MetadataVirtualSpace and + // and use some of its space to describe itself (plus alignment + // considerations). Metadata is allocated in the rest of the chunk. + // This size is the overhead of maintaining the Metachunk within + // the space. + + // Alignment of each allocation in the chunks. + static size_t object_alignment(); + + // Size of the Metachunk header, including alignment. + static size_t overhead(); + + Metachunk(size_t word_size , VirtualSpaceNode* container); + + MetaWord* allocate(size_t word_size); + + VirtualSpaceNode* container() const { return _container; } + + MetaWord* bottom() const { return (MetaWord*) this; } + + // Reset top to bottom so chunk can be reused. + void reset_empty() { _top = initial_top(); clear_next(); clear_prev(); } + bool is_empty() { return _top == initial_top(); } + + // used (has been allocated) + // free (available for future allocations) + size_t word_size() const { return size(); } + size_t used_word_size() const; + size_t free_word_size() const; + +#ifdef ASSERT + bool is_tagged_free() { return _is_tagged_free; } + void set_is_tagged_free(bool v) { _is_tagged_free = v; } +#endif + NOT_PRODUCT(void mangle();) void print_on(outputStream* st) const; void verify(); }; + +// Metablock is the unit of allocation from a Chunk. +// +// A Metablock may be reused by its SpaceManager but are never moved between +// SpaceManagers. There is no explicit link to the Metachunk +// from which it was allocated. Metablock may be deallocated and +// put on a freelist but the space is never freed, rather +// the Metachunk it is a part of will be deallocated when it's +// associated class loader is collected. + +class Metablock : public Metabase { + friend class VMStructs; + public: + Metablock(size_t word_size) : Metabase(word_size) {} +}; + #endif // SHARE_VM_MEMORY_METACHUNK_HPP diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/memory/metadataFactory.hpp --- a/src/share/vm/memory/metadataFactory.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/memory/metadataFactory.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,6 +65,7 @@ static void free_array(ClassLoaderData* loader_data, Array* data) { if (data != NULL) { assert(loader_data != NULL, "shouldn't pass null"); + assert(!data->is_shared(), "cannot deallocate array in shared spaces"); int size = data->size(); if (DumpSharedSpaces) { loader_data->ro_metaspace()->deallocate((MetaWord*)data, size, false); @@ -83,6 +84,7 @@ // Call metadata's deallocate function which will call deallocate fields assert(!DumpSharedSpaces, "cannot deallocate metadata when dumping CDS archive"); assert(!md->on_stack(), "can't deallocate things on stack"); + assert(!md->is_shared(), "cannot deallocate if in shared spaces"); md->deallocate_contents(loader_data); loader_data->metaspace_non_null()->deallocate((MetaWord*)md, size, md->is_klass()); } diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/memory/metaspace.cpp --- a/src/share/vm/memory/metaspace.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/memory/metaspace.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -30,7 +30,6 @@ #include "memory/filemap.hpp" #include "memory/freeList.hpp" #include "memory/gcLocker.hpp" -#include "memory/metablock.hpp" #include "memory/metachunk.hpp" #include "memory/metaspace.hpp" #include "memory/metaspaceShared.hpp" @@ -49,13 +48,10 @@ typedef BinaryTreeDictionary BlockTreeDictionary; typedef BinaryTreeDictionary ChunkTreeDictionary; -// Define this macro to enable slow integrity checking of -// the free chunk lists + +// Set this constant to enable slow integrity checking of the free chunk lists const bool metaspace_slow_verify = false; -// Parameters for stress mode testing -const uint metadata_deallocate_a_lot_block = 10; -const uint metadata_deallocate_a_lock_chunk = 3; size_t const allocation_from_dictionary_limit = 4 * K; MetaWord* last_allocated = 0; @@ -79,8 +75,7 @@ ClassSmallChunk = 256, SmallChunk = 512, ClassMediumChunk = 4 * K, - MediumChunk = 8 * K, - HumongousChunkGranularity = 8 + MediumChunk = 8 * K }; static ChunkIndex next_chunk_index(ChunkIndex i) { @@ -92,25 +87,11 @@ uint MetaspaceGC::_shrink_factor = 0; bool MetaspaceGC::_should_concurrent_collect = false; -// Blocks of space for metadata are allocated out of Metachunks. -// -// Metachunk are allocated out of MetadataVirtualspaces and once -// allocated there is no explicit link between a Metachunk and -// the MetadataVirtualspaces from which it was allocated. -// -// Each SpaceManager maintains a -// list of the chunks it is using and the current chunk. The current -// chunk is the chunk from which allocations are done. Space freed in -// a chunk is placed on the free list of blocks (BlockFreelist) and -// reused from there. - typedef class FreeList ChunkList; // Manages the global free lists of chunks. -// Has three lists of free chunks, and a total size and -// count that includes all three - class ChunkManager : public CHeapObj { + friend class TestVirtualSpaceNodeTest; // Free list of chunks of different sizes. // SpecializedChunk @@ -119,7 +100,6 @@ // HumongousChunk ChunkList _free_chunks[NumberOfFreeLists]; - // HumongousChunk ChunkTreeDictionary _humongous_dictionary; @@ -166,7 +146,6 @@ // add or delete (return) a chunk to the global freelist. Metachunk* chunk_freelist_allocate(size_t word_size); - void chunk_freelist_deallocate(Metachunk* chunk); // Map a size to a list index assuming that there are lists // for special, small, medium, and humongous chunks. @@ -200,9 +179,7 @@ // Returns the list for the given chunk word size. ChunkList* find_free_chunks_list(size_t word_size); - // Add and remove from a list by size. Selects - // list based on size of chunk. - void free_chunks_put(Metachunk* chuck); + // Remove from a list by size. Selects list based on size of chunk. Metachunk* free_chunks_get(size_t chunk_word_size); // Debug support @@ -230,7 +207,6 @@ // to the allocation of a quantum of metadata). class BlockFreelist VALUE_OBJ_CLASS_SPEC { BlockTreeDictionary* _dictionary; - static Metablock* initialize_free_chunk(MetaWord* p, size_t word_size); // Only allocate and split from freelist if the size of the allocation // is at least 1/4th the size of the available block. @@ -258,6 +234,7 @@ void print_on(outputStream* st) const; }; +// A VirtualSpaceList node. class VirtualSpaceNode : public CHeapObj { friend class VirtualSpaceList; @@ -280,6 +257,8 @@ // VirtualSpace Metachunk* first_chunk() { return (Metachunk*) bottom(); } + // Committed but unused space in the virtual space + size_t free_words_in_vs() const; public: VirtualSpaceNode(size_t byte_size); @@ -324,7 +303,6 @@ // used and capacity in this single entry in the list size_t used_words_in_vs() const; size_t capacity_words_in_vs() const; - size_t free_words_in_vs() const; bool initialize(); @@ -342,6 +320,13 @@ // in the node from any freelist. void purge(ChunkManager* chunk_manager); + // If an allocation doesn't fit in the current node a new node is created. + // Allocate chunks out of the remaining committed space in this node + // to avoid wasting that memory. + // This always adds up because all the chunk sizes are multiples of + // the smallest chunk size. + void retire(ChunkManager* chunk_manager); + #ifdef ASSERT // Debug support void mangle(); @@ -414,13 +399,13 @@ Metachunk* chunk = first_chunk(); Metachunk* invalid_chunk = (Metachunk*) top(); while (chunk < invalid_chunk ) { - assert(chunk->is_free(), "Should be marked free"); - MetaWord* next = ((MetaWord*)chunk) + chunk->word_size(); - chunk_manager->remove_chunk(chunk); - assert(chunk->next() == NULL && - chunk->prev() == NULL, - "Was not removed from its list"); - chunk = (Metachunk*) next; + assert(chunk->is_tagged_free(), "Should be tagged free"); + MetaWord* next = ((MetaWord*)chunk) + chunk->word_size(); + chunk_manager->remove_chunk(chunk); + assert(chunk->next() == NULL && + chunk->prev() == NULL, + "Was not removed from its list"); + chunk = (Metachunk*) next; } } @@ -434,7 +419,7 @@ // Don't count the chunks on the free lists. Those are // still part of the VirtualSpaceNode but not currently // counted. - if (!chunk->is_free()) { + if (!chunk->is_tagged_free()) { count++; } chunk = (Metachunk*) next; @@ -484,6 +469,10 @@ // and is typically followed by the allocation of a chunk. bool create_new_virtual_space(size_t vs_word_size); + // Chunk up the unused committed space in the current + // virtual space and add the chunks to the free list. + void retire_current_virtual_space(); + public: VirtualSpaceList(size_t word_size); VirtualSpaceList(ReservedSpace rs); @@ -550,44 +539,16 @@ class Metadebug : AllStatic { // Debugging support for Metaspaces - static int _deallocate_block_a_lot_count; - static int _deallocate_chunk_a_lot_count; static int _allocation_fail_alot_count; public: - static int deallocate_block_a_lot_count() { - return _deallocate_block_a_lot_count; - } - static void set_deallocate_block_a_lot_count(int v) { - _deallocate_block_a_lot_count = v; - } - static void inc_deallocate_block_a_lot_count() { - _deallocate_block_a_lot_count++; - } - static int deallocate_chunk_a_lot_count() { - return _deallocate_chunk_a_lot_count; - } - static void reset_deallocate_chunk_a_lot_count() { - _deallocate_chunk_a_lot_count = 1; - } - static void inc_deallocate_chunk_a_lot_count() { - _deallocate_chunk_a_lot_count++; - } static void init_allocation_fail_alot_count(); #ifdef ASSERT static bool test_metadata_failure(); #endif - - static void deallocate_chunk_a_lot(SpaceManager* sm, - size_t chunk_word_size); - static void deallocate_block_a_lot(SpaceManager* sm, - size_t chunk_word_size); - }; -int Metadebug::_deallocate_block_a_lot_count = 0; -int Metadebug::_deallocate_chunk_a_lot_count = 0; int Metadebug::_allocation_fail_alot_count = 0; // SpaceManager - used by Metaspace to handle allocations @@ -675,10 +636,12 @@ bool is_class() { return _mdtype == Metaspace::ClassType; } // Accessors - size_t specialized_chunk_size() { return SpecializedChunk; } - size_t small_chunk_size() { return (size_t) is_class() ? ClassSmallChunk : SmallChunk; } - size_t medium_chunk_size() { return (size_t) is_class() ? ClassMediumChunk : MediumChunk; } - size_t medium_chunk_bunch() { return medium_chunk_size() * MediumChunkMultiple; } + size_t specialized_chunk_size() { return (size_t) is_class() ? ClassSpecializedChunk : SpecializedChunk; } + size_t small_chunk_size() { return (size_t) is_class() ? ClassSmallChunk : SmallChunk; } + size_t medium_chunk_size() { return (size_t) is_class() ? ClassMediumChunk : MediumChunk; } + size_t medium_chunk_bunch() { return medium_chunk_size() * MediumChunkMultiple; } + + size_t smallest_chunk_size() { return specialized_chunk_size(); } size_t allocated_blocks_words() const { return _allocated_blocks_words; } size_t allocated_blocks_bytes() const { return _allocated_blocks_words * BytesPerWord; } @@ -753,14 +716,11 @@ #endif size_t get_raw_word_size(size_t word_size) { - // If only the dictionary is going to be used (i.e., no - // indexed free list), then there is a minimum size requirement. - // MinChunkSize is a placeholder for the real minimum size JJJ size_t byte_size = word_size * BytesPerWord; - size_t raw_bytes_size = MAX2(byte_size, - Metablock::min_block_byte_size()); - raw_bytes_size = ARENA_ALIGN(raw_bytes_size); + size_t raw_bytes_size = MAX2(byte_size, sizeof(Metablock)); + raw_bytes_size = align_size_up(raw_bytes_size, Metachunk::object_alignment()); + size_t raw_word_size = raw_bytes_size / BytesPerWord; assert(raw_word_size * BytesPerWord == raw_bytes_size, "Size problem"); @@ -813,17 +773,8 @@ } } -Metablock* BlockFreelist::initialize_free_chunk(MetaWord* p, size_t word_size) { - Metablock* block = (Metablock*) p; - block->set_word_size(word_size); - block->set_prev(NULL); - block->set_next(NULL); - - return block; -} - void BlockFreelist::return_block(MetaWord* p, size_t word_size) { - Metablock* free_chunk = initialize_free_chunk(p, word_size); + Metablock* free_chunk = ::new (p) Metablock(word_size); if (dictionary() == NULL) { _dictionary = new BlockTreeDictionary(); } @@ -1069,7 +1020,7 @@ } // Chunk is being removed from the chunks free list. - dec_free_chunks_total(chunk->capacity_word_size()); + dec_free_chunks_total(chunk->word_size()); } // Walk the list of VirtualSpaceNodes and delete @@ -1119,6 +1070,35 @@ #endif } +void VirtualSpaceList::retire_current_virtual_space() { + assert_lock_strong(SpaceManager::expand_lock()); + + VirtualSpaceNode* vsn = current_virtual_space(); + + ChunkManager* cm = is_class() ? Metaspace::chunk_manager_class() : + Metaspace::chunk_manager_metadata(); + + vsn->retire(cm); +} + +void VirtualSpaceNode::retire(ChunkManager* chunk_manager) { + for (int i = (int)MediumIndex; i >= (int)ZeroIndex; --i) { + ChunkIndex index = (ChunkIndex)i; + size_t chunk_size = chunk_manager->free_chunks(index)->size(); + + while (free_words_in_vs() >= chunk_size) { + DEBUG_ONLY(verify_container_count();) + Metachunk* chunk = get_chunk_vs(chunk_size); + assert(chunk != NULL, "allocation should have been successful"); + + chunk_manager->return_chunks(index, chunk); + chunk_manager->inc_free_chunks_total(chunk_size); + DEBUG_ONLY(verify_container_count();) + } + } + assert(free_words_in_vs() == 0, "should be empty now"); +} + VirtualSpaceList::VirtualSpaceList(size_t word_size) : _is_class(false), _virtual_space_list(NULL), @@ -1244,6 +1224,7 @@ if (vs_expanded) { return true; } + retire_current_virtual_space(); // Get another virtual space. size_t grow_vs_words = MAX2((size_t)VirtualSpaceSize, preferred_words); @@ -1563,54 +1544,6 @@ // Metadebug methods -void Metadebug::deallocate_chunk_a_lot(SpaceManager* sm, - size_t chunk_word_size){ -#ifdef ASSERT - VirtualSpaceList* vsl = sm->vs_list(); - if (MetaDataDeallocateALot && - Metadebug::deallocate_chunk_a_lot_count() % MetaDataDeallocateALotInterval == 0 ) { - Metadebug::reset_deallocate_chunk_a_lot_count(); - for (uint i = 0; i < metadata_deallocate_a_lock_chunk; i++) { - Metachunk* dummy_chunk = vsl->current_virtual_space()->take_from_committed(chunk_word_size); - if (dummy_chunk == NULL) { - break; - } - sm->chunk_manager()->chunk_freelist_deallocate(dummy_chunk); - - if (TraceMetadataChunkAllocation && Verbose) { - gclog_or_tty->print("Metadebug::deallocate_chunk_a_lot: %d) ", - sm->sum_count_in_chunks_in_use()); - dummy_chunk->print_on(gclog_or_tty); - gclog_or_tty->print_cr(" Free chunks total %d count %d", - sm->chunk_manager()->free_chunks_total_words(), - sm->chunk_manager()->free_chunks_count()); - } - } - } else { - Metadebug::inc_deallocate_chunk_a_lot_count(); - } -#endif -} - -void Metadebug::deallocate_block_a_lot(SpaceManager* sm, - size_t raw_word_size){ -#ifdef ASSERT - if (MetaDataDeallocateALot && - Metadebug::deallocate_block_a_lot_count() % MetaDataDeallocateALotInterval == 0 ) { - Metadebug::set_deallocate_block_a_lot_count(0); - for (uint i = 0; i < metadata_deallocate_a_lot_block; i++) { - MetaWord* dummy_block = sm->allocate_work(raw_word_size); - if (dummy_block == 0) { - break; - } - sm->deallocate(dummy_block, raw_word_size); - } - } else { - Metadebug::inc_deallocate_block_a_lot_count(); - } -#endif -} - void Metadebug::init_allocation_fail_alot_count() { if (MetadataAllocationFailALot) { _allocation_fail_alot_count = @@ -1754,31 +1687,6 @@ return free_chunks(index); } -void ChunkManager::free_chunks_put(Metachunk* chunk) { - assert_lock_strong(SpaceManager::expand_lock()); - ChunkList* free_list = find_free_chunks_list(chunk->word_size()); - chunk->set_next(free_list->head()); - free_list->set_head(chunk); - // chunk is being returned to the chunk free list - inc_free_chunks_total(chunk->capacity_word_size()); - slow_locked_verify(); -} - -void ChunkManager::chunk_freelist_deallocate(Metachunk* chunk) { - // The deallocation of a chunk originates in the freelist - // manangement code for a Metaspace and does not hold the - // lock. - assert(chunk != NULL, "Deallocating NULL"); - assert_lock_strong(SpaceManager::expand_lock()); - slow_locked_verify(); - if (TraceMetadataChunkAllocation) { - gclog_or_tty->print_cr("ChunkManager::chunk_freelist_deallocate: chunk " - PTR_FORMAT " size " SIZE_FORMAT, - chunk, chunk->word_size()); - } - free_chunks_put(chunk); -} - Metachunk* ChunkManager::free_chunks_get(size_t word_size) { assert_lock_strong(SpaceManager::expand_lock()); @@ -1822,7 +1730,7 @@ } // Chunk is being removed from the chunks free list. - dec_free_chunks_total(chunk->capacity_word_size()); + dec_free_chunks_total(chunk->word_size()); // Remove it from the links to this freelist chunk->set_next(NULL); @@ -1830,7 +1738,7 @@ #ifdef ASSERT // Chunk is no longer on any freelist. Setting to false make container_count_slow() // work. - chunk->set_is_free(false); + chunk->set_is_tagged_free(false); #endif chunk->container()->inc_container_count(); @@ -1962,7 +1870,7 @@ for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) { Metachunk* chunk = chunks_in_use(i); while (chunk != NULL) { - sum += chunk->capacity_word_size(); + sum += chunk->word_size(); chunk = chunk->next(); } } @@ -2038,12 +1946,12 @@ chunk_word_size = medium_chunk_size(); } - // Might still need a humongous chunk. Enforce an - // eight word granularity to facilitate reuse (some - // wastage but better chance of reuse). + // Might still need a humongous chunk. Enforce + // humongous allocations sizes to be aligned up to + // the smallest chunk size. size_t if_humongous_sized_chunk = align_size_up(word_size + Metachunk::overhead(), - HumongousChunkGranularity); + smallest_chunk_size()); chunk_word_size = MAX2((size_t) chunk_word_size, if_humongous_sized_chunk); @@ -2098,10 +2006,6 @@ size_t grow_chunks_by_words = calc_chunk_size(word_size); Metachunk* next = get_new_chunk(word_size, grow_chunks_by_words); - if (next != NULL) { - Metadebug::deallocate_chunk_a_lot(this, grow_chunks_by_words); - } - MetaWord* mem = NULL; // If a chunk was available, add it to the in-use chunk list @@ -2210,7 +2114,7 @@ // Capture the next link before it is changed // by the call to return_chunk_at_head(); Metachunk* next = cur->next(); - cur->set_is_free(true); + DEBUG_ONLY(cur->set_is_tagged_free(true);) list->return_chunk_at_head(cur); cur = next; } @@ -2282,7 +2186,7 @@ while (humongous_chunks != NULL) { #ifdef ASSERT - humongous_chunks->set_is_free(true); + humongous_chunks->set_is_tagged_free(true); #endif if (TraceMetadataChunkAllocation && Verbose) { gclog_or_tty->print(PTR_FORMAT " (" SIZE_FORMAT ") ", @@ -2291,10 +2195,10 @@ } assert(humongous_chunks->word_size() == (size_t) align_size_up(humongous_chunks->word_size(), - HumongousChunkGranularity), + smallest_chunk_size()), err_msg("Humongous chunk size is wrong: word size " SIZE_FORMAT " granularity %d", - humongous_chunks->word_size(), HumongousChunkGranularity)); + humongous_chunks->word_size(), smallest_chunk_size())); Metachunk* next_humongous_chunks = humongous_chunks->next(); humongous_chunks->container()->dec_container_count(); chunk_manager()->humongous_dictionary()->return_chunk(humongous_chunks); @@ -2446,7 +2350,6 @@ if (p == NULL) { p = allocate_work(raw_word_size); } - Metadebug::deallocate_block_a_lot(this, raw_word_size); return p; } @@ -2545,7 +2448,7 @@ curr->print_on(out); curr_total += curr->word_size(); used += curr->used_word_size(); - capacity += curr->capacity_word_size(); + capacity += curr->word_size(); waste += curr->free_word_size() + curr->overhead();; } } @@ -3396,7 +3299,7 @@ } -Metablock* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size, +MetaWord* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size, bool read_only, MetaspaceObj::Type type, TRAPS) { if (HAS_PENDING_EXCEPTION) { assert(false, "Should not allocate with exception pending"); @@ -3415,10 +3318,14 @@ MetaWord* result = space->allocate(word_size, NonClassType); if (result == NULL) { report_out_of_shared_space(read_only ? SharedReadOnly : SharedReadWrite); - } else { - space->record_allocation(result, type, space->vsm()->get_raw_word_size(word_size)); } - return Metablock::initialize(result, word_size); + + space->record_allocation(result, type, space->vsm()->get_raw_word_size(word_size)); + + // Zero initialize. + Copy::fill_to_aligned_words((HeapWord*)result, word_size, 0); + + return result; } MetadataType mdtype = (type == MetaspaceObj::ClassType) ? ClassType : NonClassType; @@ -3438,12 +3345,13 @@ } if (result == NULL) { - report_metadata_oome(loader_data, word_size, mdtype, THREAD); - // Will not reach here. - return NULL; + report_metadata_oome(loader_data, word_size, mdtype, CHECK_NULL); } - return Metablock::initialize(result, word_size); + // Zero initialize. + Copy::fill_to_aligned_words((HeapWord*)result, word_size, 0); + + return result; } void Metaspace::report_metadata_oome(ClassLoaderData* loader_data, size_t word_size, MetadataType mdtype, TRAPS) { @@ -3628,4 +3536,94 @@ TestMetaspaceAuxTest::test(); } +class TestVirtualSpaceNodeTest { + static void chunk_up(size_t words_left, size_t& num_medium_chunks, + size_t& num_small_chunks, + size_t& num_specialized_chunks) { + num_medium_chunks = words_left / MediumChunk; + words_left = words_left % MediumChunk; + + num_small_chunks = words_left / SmallChunk; + words_left = words_left % SmallChunk; + // how many specialized chunks can we get? + num_specialized_chunks = words_left / SpecializedChunk; + assert(words_left % SpecializedChunk == 0, "should be nothing left"); + } + + public: + static void test() { + MutexLockerEx ml(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag); + const size_t vsn_test_size_words = MediumChunk * 4; + const size_t vsn_test_size_bytes = vsn_test_size_words * BytesPerWord; + + // The chunk sizes must be multiples of eachother, or this will fail + STATIC_ASSERT(MediumChunk % SmallChunk == 0); + STATIC_ASSERT(SmallChunk % SpecializedChunk == 0); + + { // No committed memory in VSN + ChunkManager cm(SpecializedChunk, SmallChunk, MediumChunk); + VirtualSpaceNode vsn(vsn_test_size_bytes); + vsn.initialize(); + vsn.retire(&cm); + assert(cm.sum_free_chunks_count() == 0, "did not commit any memory in the VSN"); + } + + { // All of VSN is committed, half is used by chunks + ChunkManager cm(SpecializedChunk, SmallChunk, MediumChunk); + VirtualSpaceNode vsn(vsn_test_size_bytes); + vsn.initialize(); + vsn.expand_by(vsn_test_size_words, vsn_test_size_words); + vsn.get_chunk_vs(MediumChunk); + vsn.get_chunk_vs(MediumChunk); + vsn.retire(&cm); + assert(cm.sum_free_chunks_count() == 2, "should have been memory left for 2 medium chunks"); + assert(cm.sum_free_chunks() == 2*MediumChunk, "sizes should add up"); + } + + { // 4 pages of VSN is committed, some is used by chunks + ChunkManager cm(SpecializedChunk, SmallChunk, MediumChunk); + VirtualSpaceNode vsn(vsn_test_size_bytes); + const size_t page_chunks = 4 * (size_t)os::vm_page_size() / BytesPerWord; + assert(page_chunks < MediumChunk, "Test expects medium chunks to be at least 4*page_size"); + vsn.initialize(); + vsn.expand_by(page_chunks, page_chunks); + vsn.get_chunk_vs(SmallChunk); + vsn.get_chunk_vs(SpecializedChunk); + vsn.retire(&cm); + + // committed - used = words left to retire + const size_t words_left = page_chunks - SmallChunk - SpecializedChunk; + + size_t num_medium_chunks, num_small_chunks, num_spec_chunks; + chunk_up(words_left, num_medium_chunks, num_small_chunks, num_spec_chunks); + + assert(num_medium_chunks == 0, "should not get any medium chunks"); + assert(cm.sum_free_chunks_count() == (num_small_chunks + num_spec_chunks), "should be space for 3 chunks"); + assert(cm.sum_free_chunks() == words_left, "sizes should add up"); + } + + { // Half of VSN is committed, a humongous chunk is used + ChunkManager cm(SpecializedChunk, SmallChunk, MediumChunk); + VirtualSpaceNode vsn(vsn_test_size_bytes); + vsn.initialize(); + vsn.expand_by(MediumChunk * 2, MediumChunk * 2); + vsn.get_chunk_vs(MediumChunk + SpecializedChunk); // Humongous chunks will be aligned up to MediumChunk + SpecializedChunk + vsn.retire(&cm); + + const size_t words_left = MediumChunk * 2 - (MediumChunk + SpecializedChunk); + size_t num_medium_chunks, num_small_chunks, num_spec_chunks; + chunk_up(words_left, num_medium_chunks, num_small_chunks, num_spec_chunks); + + assert(num_medium_chunks == 0, "should not get any medium chunks"); + assert(cm.sum_free_chunks_count() == (num_small_chunks + num_spec_chunks), "should be space for 3 chunks"); + assert(cm.sum_free_chunks() == words_left, "sizes should add up"); + } + + } +}; + +void TestVirtualSpaceNode_test() { + TestVirtualSpaceNodeTest::test(); +} + #endif diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/memory/metaspace.hpp --- a/src/share/vm/memory/metaspace.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/memory/metaspace.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -139,7 +139,6 @@ // Allocate space for metadata of type mdtype. This is space // within a Metachunk and is used by // allocate(ClassLoaderData*, size_t, bool, MetadataType, TRAPS) - // which returns a Metablock. MetaWord* allocate(size_t word_size, MetadataType mdtype); // Virtual Space lists for both classes and other metadata @@ -217,8 +216,8 @@ size_t used_bytes_slow(MetadataType mdtype) const; size_t capacity_bytes_slow(MetadataType mdtype) const; - static Metablock* allocate(ClassLoaderData* loader_data, size_t word_size, - bool read_only, MetaspaceObj::Type type, TRAPS); + static MetaWord* allocate(ClassLoaderData* loader_data, size_t word_size, + bool read_only, MetaspaceObj::Type type, TRAPS); void deallocate(MetaWord* ptr, size_t byte_size, bool is_class); MetaWord* expand_and_allocate(size_t size, diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/oops/constantPool.cpp --- a/src/share/vm/oops/constantPool.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/oops/constantPool.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -40,7 +40,6 @@ #include "runtime/init.hpp" #include "runtime/javaCalls.hpp" #include "runtime/signature.hpp" -#include "runtime/synchronizer.hpp" #include "runtime/vframe.hpp" ConstantPool* ConstantPool::allocate(ClassLoaderData* loader_data, int length, TRAPS) { @@ -70,6 +69,7 @@ // only set to non-zero if constant pool is merged by RedefineClasses set_version(0); + set_lock(new Monitor(Monitor::nonleaf + 2, "A constant pool lock")); // initialize tag array int length = tags->length(); @@ -95,6 +95,9 @@ void ConstantPool::release_C_heap_structures() { // walk constant pool and decrement symbol reference counts unreference_symbols(); + + delete _lock; + set_lock(NULL); } objArrayOop ConstantPool::resolved_references() const { @@ -151,6 +154,9 @@ ClassLoaderData* loader_data = pool_holder()->class_loader_data(); set_resolved_references(loader_data->add_handle(refs_handle)); } + + // Also need to recreate the mutex. Make sure this matches the constructor + set_lock(new Monitor(Monitor::nonleaf + 2, "A constant pool lock")); } } @@ -161,23 +167,7 @@ set_resolved_reference_length( resolved_references() != NULL ? resolved_references()->length() : 0); set_resolved_references(NULL); -} - -oop ConstantPool::lock() { - if (_pool_holder) { - // We re-use the _pool_holder's init_lock to reduce footprint. - // Notes on deadlocks: - // [1] This lock is a Java oop, so it can be recursively locked by - // the same thread without self-deadlocks. - // [2] Deadlock will happen if there is circular dependency between - // the of two Java classes. However, in this case, - // the deadlock would have happened long before we reach - // ConstantPool::lock(), so reusing init_lock does not - // increase the possibility of deadlock. - return _pool_holder->init_lock(); - } else { - return NULL; - } + set_lock(NULL); } int ConstantPool::cp_to_object_index(int cp_index) { @@ -211,9 +201,7 @@ Symbol* name = NULL; Handle loader; - { - oop cplock = this_oop->lock(); - ObjectLocker ol(cplock , THREAD, cplock != NULL); + { MonitorLockerEx ml(this_oop->lock()); if (this_oop->tag_at(which).is_unresolved_klass()) { if (this_oop->tag_at(which).is_unresolved_klass_in_error()) { @@ -260,8 +248,7 @@ bool throw_orig_error = false; { - oop cplock = this_oop->lock(); - ObjectLocker ol(cplock, THREAD, cplock != NULL); + MonitorLockerEx ml(this_oop->lock()); // some other thread has beaten us and has resolved the class. if (this_oop->tag_at(which).is_klass()) { @@ -329,8 +316,7 @@ } return k(); } else { - oop cplock = this_oop->lock(); - ObjectLocker ol(cplock, THREAD, cplock != NULL); + MonitorLockerEx ml(this_oop->lock()); // Only updated constant pool - if it is resolved. do_resolve = this_oop->tag_at(which).is_unresolved_klass(); if (do_resolve) { @@ -600,8 +586,7 @@ int tag, TRAPS) { ResourceMark rm; Symbol* error = PENDING_EXCEPTION->klass()->name(); - oop cplock = this_oop->lock(); - ObjectLocker ol(cplock, THREAD, cplock != NULL); // lock cpool to change tag. + MonitorLockerEx ml(this_oop->lock()); // lock cpool to change tag. int error_tag = (tag == JVM_CONSTANT_MethodHandle) ? JVM_CONSTANT_MethodHandleInError : JVM_CONSTANT_MethodTypeInError; @@ -762,8 +747,7 @@ if (cache_index >= 0) { // Cache the oop here also. Handle result_handle(THREAD, result_oop); - oop cplock = this_oop->lock(); - ObjectLocker ol(cplock, THREAD, cplock != NULL); // don't know if we really need this + MonitorLockerEx ml(this_oop->lock()); // don't know if we really need this oop result = this_oop->resolved_references()->obj_at(cache_index); // Benign race condition: resolved_references may already be filled in while we were trying to lock. // The important thing here is that all threads pick up the same result. @@ -869,18 +853,9 @@ bool ConstantPool::compare_entry_to(int index1, constantPoolHandle cp2, int index2, TRAPS) { - jbyte t1 = tag_at(index1).value(); - jbyte t2 = cp2->tag_at(index2).value(); - - - // JVM_CONSTANT_UnresolvedClassInError is equal to JVM_CONSTANT_UnresolvedClass - // when comparing - if (t1 == JVM_CONSTANT_UnresolvedClassInError) { - t1 = JVM_CONSTANT_UnresolvedClass; - } - if (t2 == JVM_CONSTANT_UnresolvedClassInError) { - t2 = JVM_CONSTANT_UnresolvedClass; - } + // The error tags are equivalent to non-error tags when comparing + jbyte t1 = tag_at(index1).non_error_value(); + jbyte t2 = cp2->tag_at(index2).non_error_value(); if (t1 != t2) { // Not the same entry type so there is nothing else to check. Note @@ -1001,8 +976,8 @@ case JVM_CONSTANT_MethodType: { - int k1 = method_type_index_at(index1); - int k2 = cp2->method_type_index_at(index2); + int k1 = method_type_index_at_error_ok(index1); + int k2 = cp2->method_type_index_at_error_ok(index2); bool match = compare_entry_to(k1, cp2, k2, CHECK_false); if (match) { return true; @@ -1011,11 +986,11 @@ case JVM_CONSTANT_MethodHandle: { - int k1 = method_handle_ref_kind_at(index1); - int k2 = cp2->method_handle_ref_kind_at(index2); + int k1 = method_handle_ref_kind_at_error_ok(index1); + int k2 = cp2->method_handle_ref_kind_at_error_ok(index2); if (k1 == k2) { - int i1 = method_handle_index_at(index1); - int i2 = cp2->method_handle_index_at(index2); + int i1 = method_handle_index_at_error_ok(index1); + int i2 = cp2->method_handle_index_at_error_ok(index2); bool match = compare_entry_to(i1, cp2, i2, CHECK_false); if (match) { return true; @@ -1329,14 +1304,6 @@ } } break; - case JVM_CONSTANT_UnresolvedClassInError: - { - Symbol* k = from_cp->unresolved_klass_at(from_i); - to_cp->unresolved_klass_at_put(to_i, k); - to_cp->tag_at_put(to_i, JVM_CONSTANT_UnresolvedClassInError); - } break; - - case JVM_CONSTANT_String: { Symbol* s = from_cp->unresolved_string_at(from_i); @@ -1352,15 +1319,17 @@ } break; case JVM_CONSTANT_MethodType: + case JVM_CONSTANT_MethodTypeInError: { - jint k = from_cp->method_type_index_at(from_i); + jint k = from_cp->method_type_index_at_error_ok(from_i); to_cp->method_type_index_at_put(to_i, k); } break; case JVM_CONSTANT_MethodHandle: + case JVM_CONSTANT_MethodHandleInError: { - int k1 = from_cp->method_handle_ref_kind_at(from_i); - int k2 = from_cp->method_handle_index_at(from_i); + int k1 = from_cp->method_handle_ref_kind_at_error_ok(from_i); + int k2 = from_cp->method_handle_index_at_error_ok(from_i); to_cp->method_handle_index_at_put(to_i, k1, k2); } break; diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/oops/constantPool.hpp --- a/src/share/vm/oops/constantPool.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/oops/constantPool.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -111,6 +111,7 @@ int _version; } _saved; + Monitor* _lock; void set_tags(Array* tags) { _tags = tags; } void tag_at_put(int which, jbyte t) { tags()->at_put(which, t); } @@ -843,17 +844,8 @@ void set_resolved_reference_length(int length) { _saved._resolved_reference_length = length; } int resolved_reference_length() const { return _saved._resolved_reference_length; } - - // lock() may return null -- constant pool updates may happen before this lock is - // initialized, because the _pool_holder has not been fully initialized and - // has not been registered into the system dictionary. In this case, no other - // thread can be modifying this constantpool, so no synchronization is - // necessary. - // - // Use cplock() like this: - // oop cplock = cp->lock(); - // ObjectLocker ol(cplock , THREAD, cplock != NULL); - oop lock(); + void set_lock(Monitor* lock) { _lock = lock; } + Monitor* lock() { return _lock; } // Decrease ref counts of symbols that are in the constant pool // when the holder class is unloaded diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/oops/cpCache.cpp --- a/src/share/vm/oops/cpCache.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/oops/cpCache.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -284,8 +284,7 @@ // the lock, so that when the losing writer returns, he can use the linked // cache entry. - oop cplock = cpool->lock(); - ObjectLocker ol(cplock, Thread::current(), cplock != NULL); + MonitorLockerEx ml(cpool->lock()); if (!is_f1_null()) { return; } diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/oops/instanceKlass.cpp --- a/src/share/vm/oops/instanceKlass.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/oops/instanceKlass.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -320,7 +320,8 @@ void InstanceKlass::deallocate_methods(ClassLoaderData* loader_data, Array* methods) { - if (methods != NULL && methods != Universe::the_empty_method_array()) { + if (methods != NULL && methods != Universe::the_empty_method_array() && + !methods->is_shared()) { for (int i = 0; i < methods->length(); i++) { Method* method = methods->at(i); if (method == NULL) continue; // maybe null if error processing @@ -344,13 +345,14 @@ // check that the interfaces don't come from super class Array* sti = (super_klass == NULL) ? NULL : InstanceKlass::cast(super_klass)->transitive_interfaces(); - if (ti != sti) { + if (ti != sti && ti != NULL && !ti->is_shared()) { MetadataFactory::free_array(loader_data, ti); } } // local interfaces can be empty - if (local_interfaces != Universe::the_empty_klass_array()) { + if (local_interfaces != Universe::the_empty_klass_array() && + local_interfaces != NULL && !local_interfaces->is_shared()) { MetadataFactory::free_array(loader_data, local_interfaces); } } @@ -380,21 +382,25 @@ deallocate_methods(loader_data, methods()); set_methods(NULL); - if (method_ordering() != Universe::the_empty_int_array()) { + if (method_ordering() != NULL && + method_ordering() != Universe::the_empty_int_array() && + !method_ordering()->is_shared()) { MetadataFactory::free_array(loader_data, method_ordering()); } set_method_ordering(NULL); // default methods can be empty if (default_methods() != NULL && - default_methods() != Universe::the_empty_method_array()) { + default_methods() != Universe::the_empty_method_array() && + !default_methods()->is_shared()) { MetadataFactory::free_array(loader_data, default_methods()); } // Do NOT deallocate the default methods, they are owned by superinterfaces. set_default_methods(NULL); // default methods vtable indices can be empty - if (default_vtable_indices() != NULL) { + if (default_vtable_indices() != NULL && + !default_vtable_indices()->is_shared()) { MetadataFactory::free_array(loader_data, default_vtable_indices()); } set_default_vtable_indices(NULL); @@ -403,8 +409,10 @@ // This array is in Klass, but remove it with the InstanceKlass since // this place would be the only caller and it can share memory with transitive // interfaces. - if (secondary_supers() != Universe::the_empty_klass_array() && - secondary_supers() != transitive_interfaces()) { + if (secondary_supers() != NULL && + secondary_supers() != Universe::the_empty_klass_array() && + secondary_supers() != transitive_interfaces() && + !secondary_supers()->is_shared()) { MetadataFactory::free_array(loader_data, secondary_supers()); } set_secondary_supers(NULL); @@ -413,24 +421,32 @@ set_transitive_interfaces(NULL); set_local_interfaces(NULL); - MetadataFactory::free_array(loader_data, fields()); + if (fields() != NULL && !fields()->is_shared()) { + MetadataFactory::free_array(loader_data, fields()); + } set_fields(NULL, 0); // If a method from a redefined class is using this constant pool, don't // delete it, yet. The new class's previous version will point to this. if (constants() != NULL) { assert (!constants()->on_stack(), "shouldn't be called if anything is onstack"); - MetadataFactory::free_metadata(loader_data, constants()); + if (!constants()->is_shared()) { + MetadataFactory::free_metadata(loader_data, constants()); + } set_constants(NULL); } - if (inner_classes() != Universe::the_empty_short_array()) { + if (inner_classes() != NULL && + inner_classes() != Universe::the_empty_short_array() && + !inner_classes()->is_shared()) { MetadataFactory::free_array(loader_data, inner_classes()); } set_inner_classes(NULL); - // We should deallocate the Annotations instance - MetadataFactory::free_metadata(loader_data, annotations()); + // We should deallocate the Annotations instance if it's not in shared spaces. + if (annotations() != NULL && !annotations()->is_shared()) { + MetadataFactory::free_metadata(loader_data, annotations()); + } set_annotations(NULL); } @@ -482,13 +498,27 @@ oop InstanceKlass::init_lock() const { // return the init lock from the mirror - return java_lang_Class::init_lock(java_mirror()); + oop lock = java_lang_Class::init_lock(java_mirror()); + assert((oop)lock != NULL || !is_not_initialized(), // initialized or in_error state + "only fully initialized state can have a null lock"); + return lock; +} + +// Set the initialization lock to null so the object can be GC'ed. Any racing +// threads to get this lock will see a null lock and will not lock. +// That's okay because they all check for initialized state after getting +// the lock and return. +void InstanceKlass::fence_and_clear_init_lock() { + // make sure previous stores are all done, notably the init_state. + OrderAccess::storestore(); + java_lang_Class::set_init_lock(java_mirror(), NULL); + assert(!is_not_initialized(), "class must be initialized now"); } void InstanceKlass::eager_initialize_impl(instanceKlassHandle this_oop) { EXCEPTION_MARK; oop init_lock = this_oop->init_lock(); - ObjectLocker ol(init_lock, THREAD); + ObjectLocker ol(init_lock, THREAD, init_lock != NULL); // abort if someone beat us to the initialization if (!this_oop->is_not_initialized()) return; // note: not equivalent to is_initialized() @@ -507,6 +537,7 @@ } else { // linking successfull, mark class as initialized this_oop->set_init_state (fully_initialized); + this_oop->fence_and_clear_init_lock(); // trace if (TraceClassInitialization) { ResourceMark rm(THREAD); @@ -633,7 +664,7 @@ // verification & rewriting { oop init_lock = this_oop->init_lock(); - ObjectLocker ol(init_lock, THREAD); + ObjectLocker ol(init_lock, THREAD, init_lock != NULL); // rewritten will have been set if loader constraint error found // on an earlier link attempt // don't verify or rewrite if already rewritten @@ -756,7 +787,7 @@ // Step 1 { oop init_lock = this_oop->init_lock(); - ObjectLocker ol(init_lock, THREAD); + ObjectLocker ol(init_lock, THREAD, init_lock != NULL); Thread *self = THREAD; // it's passed the current thread @@ -904,8 +935,9 @@ void InstanceKlass::set_initialization_state_and_notify_impl(instanceKlassHandle this_oop, ClassState state, TRAPS) { oop init_lock = this_oop->init_lock(); - ObjectLocker ol(init_lock, THREAD); + ObjectLocker ol(init_lock, THREAD, init_lock != NULL); this_oop->set_init_state(state); + this_oop->fence_and_clear_init_lock(); ol.notify_all(CHECK); } diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/oops/instanceKlass.hpp --- a/src/share/vm/oops/instanceKlass.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/oops/instanceKlass.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -1023,6 +1023,7 @@ // It has to be an object not a Mutex because it's held through java calls. oop init_lock() const; private: + void fence_and_clear_init_lock(); // Static methods that are used to implement member methods where an exposed this pointer // is needed due to possible GCs diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/oops/method.hpp --- a/src/share/vm/oops/method.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/oops/method.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -805,6 +805,7 @@ private: void print_made_not_compilable(int comp_level, bool is_osr, bool report, const char* reason); + public: MethodCounters* get_method_counters(TRAPS) { if (_method_counters == NULL) { build_method_counters(this, CHECK_AND_CLEAR_NULL); @@ -812,7 +813,6 @@ return _method_counters; } - public: bool is_not_c1_compilable() const { return access_flags().is_not_c1_compilable(); } void set_not_c1_compilable() { _access_flags.set_not_c1_compilable(); } void clear_not_c1_compilable() { _access_flags.clear_not_c1_compilable(); } diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/oops/methodData.cpp --- a/src/share/vm/oops/methodData.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/oops/methodData.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -41,7 +41,7 @@ // Some types of data layouts need a length field. bool DataLayout::needs_array_len(u1 tag) { - return (tag == multi_branch_data_tag) || (tag == arg_info_data_tag); + return (tag == multi_branch_data_tag) || (tag == arg_info_data_tag) || (tag == parameters_type_data_tag); } // Perform generic initialization of the data. More specific @@ -56,6 +56,11 @@ if (needs_array_len(tag)) { set_cell_at(ArrayData::array_len_off_set, cell_count - 1); // -1 for header. } + if (tag == call_type_data_tag) { + CallTypeData::initialize(this, cell_count); + } else if (tag == virtual_call_type_data_tag) { + VirtualCallTypeData::initialize(this, cell_count); + } } void DataLayout::clean_weak_klass_links(BoolObjectClosure* cl) { @@ -76,7 +81,7 @@ } #ifndef PRODUCT -void ProfileData::print_shared(outputStream* st, const char* name) { +void ProfileData::print_shared(outputStream* st, const char* name) const { st->print("bci: %d", bci()); st->fill_to(tab_width_one); st->print("%s", name); @@ -91,8 +96,8 @@ st->print("flags(%d) ", flags); } -void ProfileData::tab(outputStream* st) { - st->fill_to(tab_width_two); +void ProfileData::tab(outputStream* st, bool first) const { + st->fill_to(first ? tab_width_one : tab_width_two); } #endif // !PRODUCT @@ -104,7 +109,7 @@ #ifndef PRODUCT -void BitData::print_data_on(outputStream* st) { +void BitData::print_data_on(outputStream* st) const { print_shared(st, "BitData"); } #endif // !PRODUCT @@ -115,7 +120,7 @@ // A CounterData corresponds to a simple counter. #ifndef PRODUCT -void CounterData::print_data_on(outputStream* st) { +void CounterData::print_data_on(outputStream* st) const { print_shared(st, "CounterData"); st->print_cr("count(%u)", count()); } @@ -145,12 +150,217 @@ } #ifndef PRODUCT -void JumpData::print_data_on(outputStream* st) { +void JumpData::print_data_on(outputStream* st) const { print_shared(st, "JumpData"); st->print_cr("taken(%u) displacement(%d)", taken(), displacement()); } #endif // !PRODUCT +int TypeStackSlotEntries::compute_cell_count(Symbol* signature, bool include_receiver, int max) { + // Parameter profiling include the receiver + int args_count = include_receiver ? 1 : 0; + ResourceMark rm; + SignatureStream ss(signature); + args_count += ss.reference_parameter_count(); + args_count = MIN2(args_count, max); + return args_count * per_arg_cell_count; +} + +int TypeEntriesAtCall::compute_cell_count(BytecodeStream* stream) { + assert(Bytecodes::is_invoke(stream->code()), "should be invoke"); + assert(TypeStackSlotEntries::per_arg_count() > ReturnTypeEntry::static_cell_count(), "code to test for arguments/results broken"); + Bytecode_invoke inv(stream->method(), stream->bci()); + int args_cell = 0; + if (arguments_profiling_enabled()) { + args_cell = TypeStackSlotEntries::compute_cell_count(inv.signature(), false, TypeProfileArgsLimit); + } + int ret_cell = 0; + if (return_profiling_enabled() && (inv.result_type() == T_OBJECT || inv.result_type() == T_ARRAY)) { + ret_cell = ReturnTypeEntry::static_cell_count(); + } + int header_cell = 0; + if (args_cell + ret_cell > 0) { + header_cell = header_cell_count(); + } + + return header_cell + args_cell + ret_cell; +} + +class ArgumentOffsetComputer : public SignatureInfo { +private: + int _max; + GrowableArray _offsets; + + void set(int size, BasicType type) { _size += size; } + void do_object(int begin, int end) { + if (_offsets.length() < _max) { + _offsets.push(_size); + } + SignatureInfo::do_object(begin, end); + } + void do_array (int begin, int end) { + if (_offsets.length() < _max) { + _offsets.push(_size); + } + SignatureInfo::do_array(begin, end); + } + +public: + ArgumentOffsetComputer(Symbol* signature, int max) + : SignatureInfo(signature), _max(max), _offsets(Thread::current(), max) { + } + + int total() { lazy_iterate_parameters(); return _size; } + + int off_at(int i) const { return _offsets.at(i); } +}; + +void TypeStackSlotEntries::post_initialize(Symbol* signature, bool has_receiver, bool include_receiver) { + ResourceMark rm; + int start = 0; + // Parameter profiling include the receiver + if (include_receiver && has_receiver) { + set_stack_slot(0, 0); + set_type(0, type_none()); + start += 1; + } + ArgumentOffsetComputer aos(signature, _number_of_entries-start); + aos.total(); + for (int i = start; i < _number_of_entries; i++) { + set_stack_slot(i, aos.off_at(i-start) + (has_receiver ? 1 : 0)); + set_type(i, type_none()); + } +} + +void CallTypeData::post_initialize(BytecodeStream* stream, MethodData* mdo) { + assert(Bytecodes::is_invoke(stream->code()), "should be invoke"); + Bytecode_invoke inv(stream->method(), stream->bci()); + + SignatureStream ss(inv.signature()); + if (has_arguments()) { +#ifdef ASSERT + ResourceMark rm; + int count = MIN2(ss.reference_parameter_count(), (int)TypeProfileArgsLimit); + assert(count > 0, "room for args type but none found?"); + check_number_of_arguments(count); +#endif + _args.post_initialize(inv.signature(), inv.has_receiver(), false); + } + + if (has_return()) { + assert(inv.result_type() == T_OBJECT || inv.result_type() == T_ARRAY, "room for a ret type but doesn't return obj?"); + _ret.post_initialize(); + } +} + +void VirtualCallTypeData::post_initialize(BytecodeStream* stream, MethodData* mdo) { + assert(Bytecodes::is_invoke(stream->code()), "should be invoke"); + Bytecode_invoke inv(stream->method(), stream->bci()); + + if (has_arguments()) { +#ifdef ASSERT + ResourceMark rm; + SignatureStream ss(inv.signature()); + int count = MIN2(ss.reference_parameter_count(), (int)TypeProfileArgsLimit); + assert(count > 0, "room for args type but none found?"); + check_number_of_arguments(count); +#endif + _args.post_initialize(inv.signature(), inv.has_receiver(), false); + } + + if (has_return()) { + assert(inv.result_type() == T_OBJECT || inv.result_type() == T_ARRAY, "room for a ret type but doesn't return obj?"); + _ret.post_initialize(); + } +} + +bool TypeEntries::is_loader_alive(BoolObjectClosure* is_alive_cl, intptr_t p) { + return !is_type_none(p) && + !((Klass*)klass_part(p))->is_loader_alive(is_alive_cl); +} + +void TypeStackSlotEntries::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) { + for (int i = 0; i < _number_of_entries; i++) { + intptr_t p = type(i); + if (is_loader_alive(is_alive_cl, p)) { + set_type(i, type_none()); + } + } +} + +void ReturnTypeEntry::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) { + intptr_t p = type(); + if (is_loader_alive(is_alive_cl, p)) { + set_type(type_none()); + } +} + +bool TypeEntriesAtCall::return_profiling_enabled() { + return MethodData::profile_return(); +} + +bool TypeEntriesAtCall::arguments_profiling_enabled() { + return MethodData::profile_arguments(); +} + +#ifndef PRODUCT +void TypeEntries::print_klass(outputStream* st, intptr_t k) { + if (is_type_none(k)) { + st->print("none"); + } else if (is_type_unknown(k)) { + st->print("unknown"); + } else { + valid_klass(k)->print_value_on(st); + } + if (was_null_seen(k)) { + st->print(" (null seen)"); + } +} + +void TypeStackSlotEntries::print_data_on(outputStream* st) const { + for (int i = 0; i < _number_of_entries; i++) { + _pd->tab(st); + st->print("%d: stack(%u) ", i, stack_slot(i)); + print_klass(st, type(i)); + st->cr(); + } +} + +void ReturnTypeEntry::print_data_on(outputStream* st) const { + _pd->tab(st); + print_klass(st, type()); + st->cr(); +} + +void CallTypeData::print_data_on(outputStream* st) const { + CounterData::print_data_on(st); + if (has_arguments()) { + tab(st, true); + st->print("argument types"); + _args.print_data_on(st); + } + if (has_return()) { + tab(st, true); + st->print("return type"); + _ret.print_data_on(st); + } +} + +void VirtualCallTypeData::print_data_on(outputStream* st) const { + VirtualCallData::print_data_on(st); + if (has_arguments()) { + tab(st, true); + st->print("argument types"); + _args.print_data_on(st); + } + if (has_return()) { + tab(st, true); + st->print("return type"); + _ret.print_data_on(st); + } +} +#endif + // ================================================================== // ReceiverTypeData // @@ -169,7 +379,7 @@ } #ifndef PRODUCT -void ReceiverTypeData::print_receiver_data_on(outputStream* st) { +void ReceiverTypeData::print_receiver_data_on(outputStream* st) const { uint row; int entries = 0; for (row = 0; row < row_limit(); row++) { @@ -190,11 +400,11 @@ } } } -void ReceiverTypeData::print_data_on(outputStream* st) { +void ReceiverTypeData::print_data_on(outputStream* st) const { print_shared(st, "ReceiverTypeData"); print_receiver_data_on(st); } -void VirtualCallData::print_data_on(outputStream* st) { +void VirtualCallData::print_data_on(outputStream* st) const { print_shared(st, "VirtualCallData"); print_receiver_data_on(st); } @@ -246,7 +456,7 @@ #ifndef PRODUCT -void RetData::print_data_on(outputStream* st) { +void RetData::print_data_on(outputStream* st) const { print_shared(st, "RetData"); uint row; int entries = 0; @@ -281,7 +491,7 @@ } #ifndef PRODUCT -void BranchData::print_data_on(outputStream* st) { +void BranchData::print_data_on(outputStream* st) const { print_shared(st, "BranchData"); st->print_cr("taken(%u) displacement(%d)", taken(), displacement()); @@ -355,7 +565,7 @@ } #ifndef PRODUCT -void MultiBranchData::print_data_on(outputStream* st) { +void MultiBranchData::print_data_on(outputStream* st) const { print_shared(st, "MultiBranchData"); st->print_cr("default_count(%u) displacement(%d)", default_count(), default_displacement()); @@ -369,7 +579,7 @@ #endif #ifndef PRODUCT -void ArgInfoData::print_data_on(outputStream* st) { +void ArgInfoData::print_data_on(outputStream* st) const { print_shared(st, "ArgInfoData"); int nargs = number_of_args(); for (int i = 0; i < nargs; i++) { @@ -379,6 +589,34 @@ } #endif + +int ParametersTypeData::compute_cell_count(Method* m) { + if (!MethodData::profile_parameters_for_method(m)) { + return 0; + } + int max = TypeProfileParmsLimit == -1 ? INT_MAX : TypeProfileParmsLimit; + int obj_args = TypeStackSlotEntries::compute_cell_count(m->signature(), !m->is_static(), max); + if (obj_args > 0) { + return obj_args + 1; // 1 cell for array len + } + return 0; +} + +void ParametersTypeData::post_initialize(BytecodeStream* stream, MethodData* mdo) { + _parameters.post_initialize(mdo->method()->signature(), !mdo->method()->is_static(), true); +} + +bool ParametersTypeData::profiling_enabled() { + return MethodData::profile_parameters(); +} + +#ifndef PRODUCT +void ParametersTypeData::print_data_on(outputStream* st) const { + st->print("parameter types"); + _parameters.print_data_on(st); +} +#endif + // ================================================================== // MethodData* // @@ -407,7 +645,11 @@ } case Bytecodes::_invokespecial: case Bytecodes::_invokestatic: - return CounterData::static_cell_count(); + if (MethodData::profile_arguments() || MethodData::profile_return()) { + return variable_cell_count; + } else { + return CounterData::static_cell_count(); + } case Bytecodes::_goto: case Bytecodes::_goto_w: case Bytecodes::_jsr: @@ -415,9 +657,17 @@ return JumpData::static_cell_count(); case Bytecodes::_invokevirtual: case Bytecodes::_invokeinterface: - return VirtualCallData::static_cell_count(); + if (MethodData::profile_arguments() || MethodData::profile_return()) { + return variable_cell_count; + } else { + return VirtualCallData::static_cell_count(); + } case Bytecodes::_invokedynamic: - return CounterData::static_cell_count(); + if (MethodData::profile_arguments() || MethodData::profile_return()) { + return variable_cell_count; + } else { + return CounterData::static_cell_count(); + } case Bytecodes::_ret: return RetData::static_cell_count(); case Bytecodes::_ifeq: @@ -453,7 +703,36 @@ return 0; } if (cell_count == variable_cell_count) { - cell_count = MultiBranchData::compute_cell_count(stream); + switch (stream->code()) { + case Bytecodes::_lookupswitch: + case Bytecodes::_tableswitch: + cell_count = MultiBranchData::compute_cell_count(stream); + break; + case Bytecodes::_invokespecial: + case Bytecodes::_invokestatic: + case Bytecodes::_invokedynamic: + assert(MethodData::profile_arguments() || MethodData::profile_return(), "should be collecting args profile"); + if (profile_arguments_for_invoke(stream->method(), stream->bci()) || + profile_return_for_invoke(stream->method(), stream->bci())) { + cell_count = CallTypeData::compute_cell_count(stream); + } else { + cell_count = CounterData::static_cell_count(); + } + break; + case Bytecodes::_invokevirtual: + case Bytecodes::_invokeinterface: { + assert(MethodData::profile_arguments() || MethodData::profile_return(), "should be collecting args profile"); + if (profile_arguments_for_invoke(stream->method(), stream->bci()) || + profile_return_for_invoke(stream->method(), stream->bci())) { + cell_count = VirtualCallTypeData::compute_cell_count(stream); + } else { + cell_count = VirtualCallData::static_cell_count(); + } + break; + } + default: + fatal("unexpected bytecode for var length profile data"); + } } // Note: cell_count might be zero, meaning that there is just // a DataLayout header, with no extra cells. @@ -499,6 +778,13 @@ // Add a cell to record information about modified arguments. int arg_size = method->size_of_parameters(); object_size += DataLayout::compute_size_in_bytes(arg_size+1); + + // Reserve room for an area of the MDO dedicated to profiling of + // parameters + int args_cell = ParametersTypeData::compute_cell_count(method()); + if (args_cell > 0) { + object_size += DataLayout::compute_size_in_bytes(args_cell); + } return object_size; } @@ -534,10 +820,21 @@ } break; case Bytecodes::_invokespecial: - case Bytecodes::_invokestatic: - cell_count = CounterData::static_cell_count(); - tag = DataLayout::counter_data_tag; + case Bytecodes::_invokestatic: { + int counter_data_cell_count = CounterData::static_cell_count(); + if (profile_arguments_for_invoke(stream->method(), stream->bci()) || + profile_return_for_invoke(stream->method(), stream->bci())) { + cell_count = CallTypeData::compute_cell_count(stream); + } else { + cell_count = counter_data_cell_count; + } + if (cell_count > counter_data_cell_count) { + tag = DataLayout::call_type_data_tag; + } else { + tag = DataLayout::counter_data_tag; + } break; + } case Bytecodes::_goto: case Bytecodes::_goto_w: case Bytecodes::_jsr: @@ -546,15 +843,37 @@ tag = DataLayout::jump_data_tag; break; case Bytecodes::_invokevirtual: - case Bytecodes::_invokeinterface: - cell_count = VirtualCallData::static_cell_count(); - tag = DataLayout::virtual_call_data_tag; + case Bytecodes::_invokeinterface: { + int virtual_call_data_cell_count = VirtualCallData::static_cell_count(); + if (profile_arguments_for_invoke(stream->method(), stream->bci()) || + profile_return_for_invoke(stream->method(), stream->bci())) { + cell_count = VirtualCallTypeData::compute_cell_count(stream); + } else { + cell_count = virtual_call_data_cell_count; + } + if (cell_count > virtual_call_data_cell_count) { + tag = DataLayout::virtual_call_type_data_tag; + } else { + tag = DataLayout::virtual_call_data_tag; + } break; - case Bytecodes::_invokedynamic: + } + case Bytecodes::_invokedynamic: { // %%% should make a type profile for any invokedynamic that takes a ref argument - cell_count = CounterData::static_cell_count(); - tag = DataLayout::counter_data_tag; + int counter_data_cell_count = CounterData::static_cell_count(); + if (profile_arguments_for_invoke(stream->method(), stream->bci()) || + profile_return_for_invoke(stream->method(), stream->bci())) { + cell_count = CallTypeData::compute_cell_count(stream); + } else { + cell_count = counter_data_cell_count; + } + if (cell_count > counter_data_cell_count) { + tag = DataLayout::call_type_data_tag; + } else { + tag = DataLayout::counter_data_tag; + } break; + } case Bytecodes::_ret: cell_count = RetData::static_cell_count(); tag = DataLayout::ret_data_tag; @@ -585,6 +904,11 @@ break; } assert(tag == DataLayout::multi_branch_data_tag || + ((MethodData::profile_arguments() || MethodData::profile_return()) && + (tag == DataLayout::call_type_data_tag || + tag == DataLayout::counter_data_tag || + tag == DataLayout::virtual_call_type_data_tag || + tag == DataLayout::virtual_call_data_tag)) || cell_count == bytecode_cell_count(c), "cell counts must agree"); if (cell_count >= 0) { assert(tag != DataLayout::no_tag, "bad tag"); @@ -631,6 +955,12 @@ return new MultiBranchData(this); case DataLayout::arg_info_data_tag: return new ArgInfoData(this); + case DataLayout::call_type_data_tag: + return new CallTypeData(this); + case DataLayout::virtual_call_type_data_tag: + return new VirtualCallTypeData(this); + case DataLayout::parameters_type_data_tag: + return new ParametersTypeData(this); }; } @@ -652,6 +982,9 @@ stream->next(); data->post_initialize(stream, this); } + if (_parameters_type_data_di != -1) { + parameters_type_data()->post_initialize(NULL, this); + } } // Initialize the MethodData* corresponding to a given method. @@ -691,7 +1024,23 @@ int arg_size = method->size_of_parameters(); dp->initialize(DataLayout::arg_info_data_tag, 0, arg_size+1); - object_size += extra_size + DataLayout::compute_size_in_bytes(arg_size+1); + int arg_data_size = DataLayout::compute_size_in_bytes(arg_size+1); + object_size += extra_size + arg_data_size; + + int args_cell = ParametersTypeData::compute_cell_count(method()); + // If we are profiling parameters, we reserver an area near the end + // of the MDO after the slots for bytecodes (because there's no bci + // for method entry so they don't fit with the framework for the + // profiling of bytecodes). We store the offset within the MDO of + // this area (or -1 if no parameter is profiled) + if (args_cell > 0) { + object_size += DataLayout::compute_size_in_bytes(args_cell); + _parameters_type_data_di = data_size + extra_size + arg_data_size; + DataLayout *dp = data_layout_at(data_size + extra_size + arg_data_size); + dp->initialize(DataLayout::parameters_type_data_tag, 0, args_cell); + } else { + _parameters_type_data_di = -1; + } // Set an initial hint. Don't use set_hint_di() because // first_di() may be out of bounds if data_size is 0. @@ -850,6 +1199,9 @@ void MethodData::print_data_on(outputStream* st) const { ResourceMark rm; ProfileData* data = first_data(); + if (_parameters_type_data_di != -1) { + parameters_type_data()->print_data_on(st); + } for ( ; is_valid(data); data = next_data(data)) { st->print("%d", dp_to_di(data->dp())); st->fill_to(6); @@ -898,3 +1250,99 @@ NEEDS_CLEANUP; // not yet implemented. } + +bool MethodData::profile_jsr292(methodHandle m, int bci) { + if (m->is_compiled_lambda_form()) { + return true; + } + + Bytecode_invoke inv(m , bci); + return inv.is_invokedynamic() || inv.is_invokehandle(); +} + +int MethodData::profile_arguments_flag() { + return TypeProfileLevel % 10; +} + +bool MethodData::profile_arguments() { + return profile_arguments_flag() > no_type_profile && profile_arguments_flag() <= type_profile_all; +} + +bool MethodData::profile_arguments_jsr292_only() { + return profile_arguments_flag() == type_profile_jsr292; +} + +bool MethodData::profile_all_arguments() { + return profile_arguments_flag() == type_profile_all; +} + +bool MethodData::profile_arguments_for_invoke(methodHandle m, int bci) { + if (!profile_arguments()) { + return false; + } + + if (profile_all_arguments()) { + return true; + } + + assert(profile_arguments_jsr292_only(), "inconsistent"); + return profile_jsr292(m, bci); +} + +int MethodData::profile_return_flag() { + return (TypeProfileLevel % 100) / 10; +} + +bool MethodData::profile_return() { + return profile_return_flag() > no_type_profile && profile_return_flag() <= type_profile_all; +} + +bool MethodData::profile_return_jsr292_only() { + return profile_return_flag() == type_profile_jsr292; +} + +bool MethodData::profile_all_return() { + return profile_return_flag() == type_profile_all; +} + +bool MethodData::profile_return_for_invoke(methodHandle m, int bci) { + if (!profile_return()) { + return false; + } + + if (profile_all_return()) { + return true; + } + + assert(profile_return_jsr292_only(), "inconsistent"); + return profile_jsr292(m, bci); +} + +int MethodData::profile_parameters_flag() { + return TypeProfileLevel / 100; +} + +bool MethodData::profile_parameters() { + return profile_parameters_flag() > no_type_profile && profile_parameters_flag() <= type_profile_all; +} + +bool MethodData::profile_parameters_jsr292_only() { + return profile_parameters_flag() == type_profile_jsr292; +} + +bool MethodData::profile_all_parameters() { + return profile_parameters_flag() == type_profile_all; +} + +bool MethodData::profile_parameters_for_method(methodHandle m) { + if (!profile_parameters()) { + return false; + } + + if (profile_all_parameters()) { + return true; + } + + assert(profile_parameters_jsr292_only(), "inconsistent"); + return m->is_compiled_lambda_form(); +} diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/oops/methodData.hpp --- a/src/share/vm/oops/methodData.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/oops/methodData.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -117,7 +117,10 @@ ret_data_tag, branch_data_tag, multi_branch_data_tag, - arg_info_data_tag + arg_info_data_tag, + call_type_data_tag, + virtual_call_type_data_tag, + parameters_type_data_tag }; enum { @@ -165,7 +168,7 @@ // occurred, and the MDO shows N occurrences of X, we make the // simplifying assumption that all N occurrences can be blamed // on that BCI. - int trap_state() { + int trap_state() const { return ((_header._struct._flags >> trap_shift) & trap_mask); } @@ -175,11 +178,11 @@ _header._struct._flags = (new_state << trap_shift) | old_flags; } - u1 flags() { + u1 flags() const { return _header._struct._flags; } - u2 bci() { + u2 bci() const { return _header._struct._bci; } @@ -198,7 +201,7 @@ void release_set_cell_at(int index, intptr_t value) { OrderAccess::release_store_ptr(&_cells[index], value); } - intptr_t cell_at(int index) { + intptr_t cell_at(int index) const { return _cells[index]; } @@ -206,7 +209,7 @@ assert(flag_number < flag_limit, "oob"); _header._struct._flags |= (0x1 << flag_number); } - bool flag_at(int flag_number) { + bool flag_at(int flag_number) const { assert(flag_number < flag_limit, "oob"); return (_header._struct._flags & (0x1 << flag_number)) != 0; } @@ -254,19 +257,24 @@ class CounterData; class ReceiverTypeData; class VirtualCallData; +class VirtualCallTypeData; class RetData; +class CallTypeData; class JumpData; class BranchData; class ArrayData; class MultiBranchData; class ArgInfoData; - +class ParametersTypeData; // ProfileData // // A ProfileData object is created to refer to a section of profiling // data in a structured way. class ProfileData : public ResourceObj { + friend class TypeEntries; + friend class ReturnTypeEntry; + friend class TypeStackSlotEntries; private: #ifndef PRODUCT enum { @@ -280,6 +288,7 @@ protected: DataLayout* data() { return _data; } + const DataLayout* data() const { return _data; } enum { cell_size = DataLayout::cell_size @@ -287,7 +296,7 @@ public: // How many cells are in this? - virtual int cell_count() { + virtual int cell_count() const { ShouldNotReachHere(); return -1; } @@ -307,7 +316,7 @@ assert(0 <= index && index < cell_count(), "oob"); data()->release_set_cell_at(index, value); } - intptr_t intptr_at(int index) { + intptr_t intptr_at(int index) const { assert(0 <= index && index < cell_count(), "oob"); return data()->cell_at(index); } @@ -317,7 +326,7 @@ void release_set_uint_at(int index, uint value) { release_set_intptr_at(index, (intptr_t) value); } - uint uint_at(int index) { + uint uint_at(int index) const { return (uint)intptr_at(index); } void set_int_at(int index, int value) { @@ -326,23 +335,23 @@ void release_set_int_at(int index, int value) { release_set_intptr_at(index, (intptr_t) value); } - int int_at(int index) { + int int_at(int index) const { return (int)intptr_at(index); } - int int_at_unchecked(int index) { + int int_at_unchecked(int index) const { return (int)data()->cell_at(index); } void set_oop_at(int index, oop value) { set_intptr_at(index, cast_from_oop(value)); } - oop oop_at(int index) { + oop oop_at(int index) const { return cast_to_oop(intptr_at(index)); } void set_flag_at(int flag_number) { data()->set_flag_at(flag_number); } - bool flag_at(int flag_number) { + bool flag_at(int flag_number) const { return data()->flag_at(flag_number); } @@ -362,7 +371,7 @@ // Constructor for invalid ProfileData. ProfileData(); - u2 bci() { + u2 bci() const { return data()->bci(); } @@ -370,7 +379,7 @@ return (address)_data; } - int trap_state() { + int trap_state() const { return data()->trap_state(); } void set_trap_state(int new_state) { @@ -378,58 +387,73 @@ } // Type checking - virtual bool is_BitData() { return false; } - virtual bool is_CounterData() { return false; } - virtual bool is_JumpData() { return false; } - virtual bool is_ReceiverTypeData(){ return false; } - virtual bool is_VirtualCallData() { return false; } - virtual bool is_RetData() { return false; } - virtual bool is_BranchData() { return false; } - virtual bool is_ArrayData() { return false; } - virtual bool is_MultiBranchData() { return false; } - virtual bool is_ArgInfoData() { return false; } + virtual bool is_BitData() const { return false; } + virtual bool is_CounterData() const { return false; } + virtual bool is_JumpData() const { return false; } + virtual bool is_ReceiverTypeData()const { return false; } + virtual bool is_VirtualCallData() const { return false; } + virtual bool is_RetData() const { return false; } + virtual bool is_BranchData() const { return false; } + virtual bool is_ArrayData() const { return false; } + virtual bool is_MultiBranchData() const { return false; } + virtual bool is_ArgInfoData() const { return false; } + virtual bool is_CallTypeData() const { return false; } + virtual bool is_VirtualCallTypeData()const { return false; } + virtual bool is_ParametersTypeData() const { return false; } - BitData* as_BitData() { + BitData* as_BitData() const { assert(is_BitData(), "wrong type"); return is_BitData() ? (BitData*) this : NULL; } - CounterData* as_CounterData() { + CounterData* as_CounterData() const { assert(is_CounterData(), "wrong type"); return is_CounterData() ? (CounterData*) this : NULL; } - JumpData* as_JumpData() { + JumpData* as_JumpData() const { assert(is_JumpData(), "wrong type"); return is_JumpData() ? (JumpData*) this : NULL; } - ReceiverTypeData* as_ReceiverTypeData() { + ReceiverTypeData* as_ReceiverTypeData() const { assert(is_ReceiverTypeData(), "wrong type"); return is_ReceiverTypeData() ? (ReceiverTypeData*)this : NULL; } - VirtualCallData* as_VirtualCallData() { + VirtualCallData* as_VirtualCallData() const { assert(is_VirtualCallData(), "wrong type"); return is_VirtualCallData() ? (VirtualCallData*)this : NULL; } - RetData* as_RetData() { + RetData* as_RetData() const { assert(is_RetData(), "wrong type"); return is_RetData() ? (RetData*) this : NULL; } - BranchData* as_BranchData() { + BranchData* as_BranchData() const { assert(is_BranchData(), "wrong type"); return is_BranchData() ? (BranchData*) this : NULL; } - ArrayData* as_ArrayData() { + ArrayData* as_ArrayData() const { assert(is_ArrayData(), "wrong type"); return is_ArrayData() ? (ArrayData*) this : NULL; } - MultiBranchData* as_MultiBranchData() { + MultiBranchData* as_MultiBranchData() const { assert(is_MultiBranchData(), "wrong type"); return is_MultiBranchData() ? (MultiBranchData*)this : NULL; } - ArgInfoData* as_ArgInfoData() { + ArgInfoData* as_ArgInfoData() const { assert(is_ArgInfoData(), "wrong type"); return is_ArgInfoData() ? (ArgInfoData*)this : NULL; } + CallTypeData* as_CallTypeData() const { + assert(is_CallTypeData(), "wrong type"); + return is_CallTypeData() ? (CallTypeData*)this : NULL; + } + VirtualCallTypeData* as_VirtualCallTypeData() const { + assert(is_VirtualCallTypeData(), "wrong type"); + return is_VirtualCallTypeData() ? (VirtualCallTypeData*)this : NULL; + } + ParametersTypeData* as_ParametersTypeData() const { + assert(is_ParametersTypeData(), "wrong type"); + return is_ParametersTypeData() ? (ParametersTypeData*)this : NULL; + } // Subclass specific initialization @@ -443,15 +467,15 @@ // an oop in a ProfileData to the ci equivalent. Generally speaking, // most ProfileData don't require any translation, so we provide the null // translation here, and the required translators are in the ci subclasses. - virtual void translate_from(ProfileData* data) {} + virtual void translate_from(const ProfileData* data) {} - virtual void print_data_on(outputStream* st) { + virtual void print_data_on(outputStream* st) const { ShouldNotReachHere(); } #ifndef PRODUCT - void print_shared(outputStream* st, const char* name); - void tab(outputStream* st); + void print_shared(outputStream* st, const char* name) const; + void tab(outputStream* st, bool first = false) const; #endif }; @@ -470,13 +494,13 @@ BitData(DataLayout* layout) : ProfileData(layout) { } - virtual bool is_BitData() { return true; } + virtual bool is_BitData() const { return true; } static int static_cell_count() { return bit_cell_count; } - virtual int cell_count() { + virtual int cell_count() const { return static_cell_count(); } @@ -498,7 +522,7 @@ } #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; #endif }; @@ -514,18 +538,18 @@ public: CounterData(DataLayout* layout) : BitData(layout) {} - virtual bool is_CounterData() { return true; } + virtual bool is_CounterData() const { return true; } static int static_cell_count() { return counter_cell_count; } - virtual int cell_count() { + virtual int cell_count() const { return static_cell_count(); } // Direct accessor - uint count() { + uint count() const { return uint_at(count_off); } @@ -542,7 +566,7 @@ } #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; #endif }; @@ -570,18 +594,18 @@ layout->tag() == DataLayout::branch_data_tag, "wrong type"); } - virtual bool is_JumpData() { return true; } + virtual bool is_JumpData() const { return true; } static int static_cell_count() { return jump_cell_count; } - virtual int cell_count() { + virtual int cell_count() const { return static_cell_count(); } // Direct accessor - uint taken() { + uint taken() const { return uint_at(taken_off_set); } @@ -598,7 +622,7 @@ return cnt; } - int displacement() { + int displacement() const { return int_at(displacement_off_set); } @@ -615,7 +639,417 @@ void post_initialize(BytecodeStream* stream, MethodData* mdo); #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; +#endif +}; + +// Entries in a ProfileData object to record types: it can either be +// none (no profile), unknown (conflicting profile data) or a klass if +// a single one is seen. Whether a null reference was seen is also +// recorded. No counter is associated with the type and a single type +// is tracked (unlike VirtualCallData). +class TypeEntries { + +public: + + // A single cell is used to record information for a type: + // - the cell is initialized to 0 + // - when a type is discovered it is stored in the cell + // - bit zero of the cell is used to record whether a null reference + // was encountered or not + // - bit 1 is set to record a conflict in the type information + + enum { + null_seen = 1, + type_mask = ~null_seen, + type_unknown = 2, + status_bits = null_seen | type_unknown, + type_klass_mask = ~status_bits + }; + + // what to initialize a cell to + static intptr_t type_none() { + return 0; + } + + // null seen = bit 0 set? + static bool was_null_seen(intptr_t v) { + return (v & null_seen) != 0; + } + + // conflicting type information = bit 1 set? + static bool is_type_unknown(intptr_t v) { + return (v & type_unknown) != 0; + } + + // not type information yet = all bits cleared, ignoring bit 0? + static bool is_type_none(intptr_t v) { + return (v & type_mask) == 0; + } + + // recorded type: cell without bit 0 and 1 + static intptr_t klass_part(intptr_t v) { + intptr_t r = v & type_klass_mask; + assert (r != 0, "invalid"); + return r; + } + + // type recorded + static Klass* valid_klass(intptr_t k) { + if (!is_type_none(k) && + !is_type_unknown(k)) { + return (Klass*)klass_part(k); + } else { + return NULL; + } + } + + static intptr_t with_status(intptr_t k, intptr_t in) { + return k | (in & status_bits); + } + + static intptr_t with_status(Klass* k, intptr_t in) { + return with_status((intptr_t)k, in); + } + +#ifndef PRODUCT + static void print_klass(outputStream* st, intptr_t k); +#endif + + // GC support + static bool is_loader_alive(BoolObjectClosure* is_alive_cl, intptr_t p); + +protected: + // ProfileData object these entries are part of + ProfileData* _pd; + // offset within the ProfileData object where the entries start + const int _base_off; + + TypeEntries(int base_off) + : _base_off(base_off), _pd(NULL) {} + + void set_intptr_at(int index, intptr_t value) { + _pd->set_intptr_at(index, value); + } + + intptr_t intptr_at(int index) const { + return _pd->intptr_at(index); + } + +public: + void set_profile_data(ProfileData* pd) { + _pd = pd; + } +}; + +// Type entries used for arguments passed at a call and parameters on +// method entry. 2 cells per entry: one for the type encoded as in +// TypeEntries and one initialized with the stack slot where the +// profiled object is to be found so that the interpreter can locate +// it quickly. +class TypeStackSlotEntries : public TypeEntries { + +private: + enum { + stack_slot_entry, + type_entry, + per_arg_cell_count + }; + + // offset of cell for stack slot for entry i within ProfileData object + int stack_slot_offset(int i) const { + return _base_off + stack_slot_local_offset(i); + } + +protected: + const int _number_of_entries; + + // offset of cell for type for entry i within ProfileData object + int type_offset(int i) const { + return _base_off + type_local_offset(i); + } + +public: + + TypeStackSlotEntries(int base_off, int nb_entries) + : TypeEntries(base_off), _number_of_entries(nb_entries) {} + + static int compute_cell_count(Symbol* signature, bool include_receiver, int max); + + void post_initialize(Symbol* signature, bool has_receiver, bool include_receiver); + + // offset of cell for stack slot for entry i within this block of cells for a TypeStackSlotEntries + static int stack_slot_local_offset(int i) { + return i * per_arg_cell_count + stack_slot_entry; + } + + // offset of cell for type for entry i within this block of cells for a TypeStackSlotEntries + static int type_local_offset(int i) { + return i * per_arg_cell_count + type_entry; + } + + // stack slot for entry i + uint stack_slot(int i) const { + assert(i >= 0 && i < _number_of_entries, "oob"); + return _pd->uint_at(stack_slot_offset(i)); + } + + // set stack slot for entry i + void set_stack_slot(int i, uint num) { + assert(i >= 0 && i < _number_of_entries, "oob"); + _pd->set_uint_at(stack_slot_offset(i), num); + } + + // type for entry i + intptr_t type(int i) const { + assert(i >= 0 && i < _number_of_entries, "oob"); + return _pd->intptr_at(type_offset(i)); + } + + // set type for entry i + void set_type(int i, intptr_t k) { + assert(i >= 0 && i < _number_of_entries, "oob"); + _pd->set_intptr_at(type_offset(i), k); + } + + static ByteSize per_arg_size() { + return in_ByteSize(per_arg_cell_count * DataLayout::cell_size); + } + + static int per_arg_count() { + return per_arg_cell_count ; + } + + // GC support + void clean_weak_klass_links(BoolObjectClosure* is_alive_closure); + +#ifndef PRODUCT + void print_data_on(outputStream* st) const; +#endif +}; + +// Type entry used for return from a call. A single cell to record the +// type. +class ReturnTypeEntry : public TypeEntries { + +private: + enum { + cell_count = 1 + }; + +public: + ReturnTypeEntry(int base_off) + : TypeEntries(base_off) {} + + void post_initialize() { + set_type(type_none()); + } + + intptr_t type() const { + return _pd->intptr_at(_base_off); + } + + void set_type(intptr_t k) { + _pd->set_intptr_at(_base_off, k); + } + + static int static_cell_count() { + return cell_count; + } + + static ByteSize size() { + return in_ByteSize(cell_count * DataLayout::cell_size); + } + + ByteSize type_offset() { + return DataLayout::cell_offset(_base_off); + } + + // GC support + void clean_weak_klass_links(BoolObjectClosure* is_alive_closure); + +#ifndef PRODUCT + void print_data_on(outputStream* st) const; +#endif +}; + +// Entries to collect type information at a call: contains arguments +// (TypeStackSlotEntries), a return type (ReturnTypeEntry) and a +// number of cells. Because the number of cells for the return type is +// smaller than the number of cells for the type of an arguments, the +// number of cells is used to tell how many arguments are profiled and +// whether a return value is profiled. See has_arguments() and +// has_return(). +class TypeEntriesAtCall { +private: + static int stack_slot_local_offset(int i) { + return header_cell_count() + TypeStackSlotEntries::stack_slot_local_offset(i); + } + + static int argument_type_local_offset(int i) { + return header_cell_count() + TypeStackSlotEntries::type_local_offset(i);; + } + +public: + + static int header_cell_count() { + return 1; + } + + static int cell_count_local_offset() { + return 0; + } + + static int compute_cell_count(BytecodeStream* stream); + + static void initialize(DataLayout* dl, int base, int cell_count) { + int off = base + cell_count_local_offset(); + dl->set_cell_at(off, cell_count - base - header_cell_count()); + } + + static bool arguments_profiling_enabled(); + static bool return_profiling_enabled(); + + // Code generation support + static ByteSize cell_count_offset() { + return in_ByteSize(cell_count_local_offset() * DataLayout::cell_size); + } + + static ByteSize args_data_offset() { + return in_ByteSize(header_cell_count() * DataLayout::cell_size); + } + + static ByteSize stack_slot_offset(int i) { + return in_ByteSize(stack_slot_local_offset(i) * DataLayout::cell_size); + } + + static ByteSize argument_type_offset(int i) { + return in_ByteSize(argument_type_local_offset(i) * DataLayout::cell_size); + } +}; + +// CallTypeData +// +// A CallTypeData is used to access profiling information about a non +// virtual call for which we collect type information about arguments +// and return value. +class CallTypeData : public CounterData { +private: + // entries for arguments if any + TypeStackSlotEntries _args; + // entry for return type if any + ReturnTypeEntry _ret; + + int cell_count_global_offset() const { + return CounterData::static_cell_count() + TypeEntriesAtCall::cell_count_local_offset(); + } + + // number of cells not counting the header + int cell_count_no_header() const { + return uint_at(cell_count_global_offset()); + } + + void check_number_of_arguments(int total) { + assert(number_of_arguments() == total, "should be set in DataLayout::initialize"); + } + +public: + CallTypeData(DataLayout* layout) : + CounterData(layout), + _args(CounterData::static_cell_count()+TypeEntriesAtCall::header_cell_count(), number_of_arguments()), + _ret(cell_count() - ReturnTypeEntry::static_cell_count()) + { + assert(layout->tag() == DataLayout::call_type_data_tag, "wrong type"); + // Some compilers (VC++) don't want this passed in member initialization list + _args.set_profile_data(this); + _ret.set_profile_data(this); + } + + const TypeStackSlotEntries* args() const { + assert(has_arguments(), "no profiling of arguments"); + return &_args; + } + + const ReturnTypeEntry* ret() const { + assert(has_return(), "no profiling of return value"); + return &_ret; + } + + virtual bool is_CallTypeData() const { return true; } + + static int static_cell_count() { + return -1; + } + + static int compute_cell_count(BytecodeStream* stream) { + return CounterData::static_cell_count() + TypeEntriesAtCall::compute_cell_count(stream); + } + + static void initialize(DataLayout* dl, int cell_count) { + TypeEntriesAtCall::initialize(dl, CounterData::static_cell_count(), cell_count); + } + + virtual void post_initialize(BytecodeStream* stream, MethodData* mdo); + + virtual int cell_count() const { + return CounterData::static_cell_count() + + TypeEntriesAtCall::header_cell_count() + + int_at_unchecked(cell_count_global_offset()); + } + + int number_of_arguments() const { + return cell_count_no_header() / TypeStackSlotEntries::per_arg_count(); + } + + void set_argument_type(int i, Klass* k) { + assert(has_arguments(), "no arguments!"); + intptr_t current = _args.type(i); + _args.set_type(i, TypeEntries::with_status(k, current)); + } + + void set_return_type(Klass* k) { + assert(has_return(), "no return!"); + intptr_t current = _ret.type(); + _ret.set_type(TypeEntries::with_status(k, current)); + } + + // An entry for a return value takes less space than an entry for an + // argument so if the number of cells exceeds the number of cells + // needed for an argument, this object contains type information for + // at least one argument. + bool has_arguments() const { + bool res = cell_count_no_header() >= TypeStackSlotEntries::per_arg_count(); + assert (!res || TypeEntriesAtCall::arguments_profiling_enabled(), "no profiling of arguments"); + return res; + } + + // An entry for a return value takes less space than an entry for an + // argument, so if the remainder of the number of cells divided by + // the number of cells for an argument is not null, a return value + // is profiled in this object. + bool has_return() const { + bool res = (cell_count_no_header() % TypeStackSlotEntries::per_arg_count()) != 0; + assert (!res || TypeEntriesAtCall::return_profiling_enabled(), "no profiling of return values"); + return res; + } + + // Code generation support + static ByteSize args_data_offset() { + return cell_offset(CounterData::static_cell_count()) + TypeEntriesAtCall::args_data_offset(); + } + + // GC support + virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) { + if (has_arguments()) { + _args.clean_weak_klass_links(is_alive_closure); + } + if (has_return()) { + _ret.clean_weak_klass_links(is_alive_closure); + } + } + +#ifndef PRODUCT + virtual void print_data_on(outputStream* st) const; #endif }; @@ -636,16 +1070,17 @@ public: ReceiverTypeData(DataLayout* layout) : CounterData(layout) { assert(layout->tag() == DataLayout::receiver_type_data_tag || - layout->tag() == DataLayout::virtual_call_data_tag, "wrong type"); + layout->tag() == DataLayout::virtual_call_data_tag || + layout->tag() == DataLayout::virtual_call_type_data_tag, "wrong type"); } - virtual bool is_ReceiverTypeData() { return true; } + virtual bool is_ReceiverTypeData() const { return true; } static int static_cell_count() { return counter_cell_count + (uint) TypeProfileWidth * receiver_type_row_cell_count; } - virtual int cell_count() { + virtual int cell_count() const { return static_cell_count(); } @@ -660,7 +1095,7 @@ return count0_offset + row * receiver_type_row_cell_count; } - Klass* receiver(uint row) { + Klass* receiver(uint row) const { assert(row < row_limit(), "oob"); Klass* recv = (Klass*)intptr_at(receiver_cell_index(row)); @@ -673,7 +1108,7 @@ set_intptr_at(receiver_cell_index(row), (uintptr_t)k); } - uint receiver_count(uint row) { + uint receiver_count(uint row) const { assert(row < row_limit(), "oob"); return uint_at(receiver_count_cell_index(row)); } @@ -721,8 +1156,8 @@ virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure); #ifndef PRODUCT - void print_receiver_data_on(outputStream* st); - void print_data_on(outputStream* st); + void print_receiver_data_on(outputStream* st) const; + void print_data_on(outputStream* st) const; #endif }; @@ -733,10 +1168,11 @@ class VirtualCallData : public ReceiverTypeData { public: VirtualCallData(DataLayout* layout) : ReceiverTypeData(layout) { - assert(layout->tag() == DataLayout::virtual_call_data_tag, "wrong type"); + assert(layout->tag() == DataLayout::virtual_call_data_tag || + layout->tag() == DataLayout::virtual_call_type_data_tag, "wrong type"); } - virtual bool is_VirtualCallData() { return true; } + virtual bool is_VirtualCallData() const { return true; } static int static_cell_count() { // At this point we could add more profile state, e.g., for arguments. @@ -744,7 +1180,7 @@ return ReceiverTypeData::static_cell_count(); } - virtual int cell_count() { + virtual int cell_count() const { return static_cell_count(); } @@ -754,7 +1190,133 @@ } #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; +#endif +}; + +// VirtualCallTypeData +// +// A VirtualCallTypeData is used to access profiling information about +// a virtual call for which we collect type information about +// arguments and return value. +class VirtualCallTypeData : public VirtualCallData { +private: + // entries for arguments if any + TypeStackSlotEntries _args; + // entry for return type if any + ReturnTypeEntry _ret; + + int cell_count_global_offset() const { + return VirtualCallData::static_cell_count() + TypeEntriesAtCall::cell_count_local_offset(); + } + + // number of cells not counting the header + int cell_count_no_header() const { + return uint_at(cell_count_global_offset()); + } + + void check_number_of_arguments(int total) { + assert(number_of_arguments() == total, "should be set in DataLayout::initialize"); + } + +public: + VirtualCallTypeData(DataLayout* layout) : + VirtualCallData(layout), + _args(VirtualCallData::static_cell_count()+TypeEntriesAtCall::header_cell_count(), number_of_arguments()), + _ret(cell_count() - ReturnTypeEntry::static_cell_count()) + { + assert(layout->tag() == DataLayout::virtual_call_type_data_tag, "wrong type"); + // Some compilers (VC++) don't want this passed in member initialization list + _args.set_profile_data(this); + _ret.set_profile_data(this); + } + + const TypeStackSlotEntries* args() const { + assert(has_arguments(), "no profiling of arguments"); + return &_args; + } + + const ReturnTypeEntry* ret() const { + assert(has_return(), "no profiling of return value"); + return &_ret; + } + + virtual bool is_VirtualCallTypeData() const { return true; } + + static int static_cell_count() { + return -1; + } + + static int compute_cell_count(BytecodeStream* stream) { + return VirtualCallData::static_cell_count() + TypeEntriesAtCall::compute_cell_count(stream); + } + + static void initialize(DataLayout* dl, int cell_count) { + TypeEntriesAtCall::initialize(dl, VirtualCallData::static_cell_count(), cell_count); + } + + virtual void post_initialize(BytecodeStream* stream, MethodData* mdo); + + virtual int cell_count() const { + return VirtualCallData::static_cell_count() + + TypeEntriesAtCall::header_cell_count() + + int_at_unchecked(cell_count_global_offset()); + } + + int number_of_arguments() const { + return cell_count_no_header() / TypeStackSlotEntries::per_arg_count(); + } + + void set_argument_type(int i, Klass* k) { + assert(has_arguments(), "no arguments!"); + intptr_t current = _args.type(i); + _args.set_type(i, TypeEntries::with_status(k, current)); + } + + void set_return_type(Klass* k) { + assert(has_return(), "no return!"); + intptr_t current = _ret.type(); + _ret.set_type(TypeEntries::with_status(k, current)); + } + + // An entry for a return value takes less space than an entry for an + // argument, so if the remainder of the number of cells divided by + // the number of cells for an argument is not null, a return value + // is profiled in this object. + bool has_return() const { + bool res = (cell_count_no_header() % TypeStackSlotEntries::per_arg_count()) != 0; + assert (!res || TypeEntriesAtCall::return_profiling_enabled(), "no profiling of return values"); + return res; + } + + // An entry for a return value takes less space than an entry for an + // argument so if the number of cells exceeds the number of cells + // needed for an argument, this object contains type information for + // at least one argument. + bool has_arguments() const { + bool res = cell_count_no_header() >= TypeStackSlotEntries::per_arg_count(); + assert (!res || TypeEntriesAtCall::arguments_profiling_enabled(), "no profiling of arguments"); + return res; + } + + // Code generation support + static ByteSize args_data_offset() { + return cell_offset(VirtualCallData::static_cell_count()) + TypeEntriesAtCall::args_data_offset(); + } + + // GC support + virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) { + ReceiverTypeData::clean_weak_klass_links(is_alive_closure); + if (has_arguments()) { + _args.clean_weak_klass_links(is_alive_closure); + } + if (has_return()) { + _ret.clean_weak_klass_links(is_alive_closure); + } + } + +#ifndef PRODUCT + virtual void print_data_on(outputStream* st) const; #endif }; @@ -797,7 +1359,7 @@ assert(layout->tag() == DataLayout::ret_data_tag, "wrong type"); } - virtual bool is_RetData() { return true; } + virtual bool is_RetData() const { return true; } enum { no_bci = -1 // value of bci when bci1/2 are not in use. @@ -807,7 +1369,7 @@ return counter_cell_count + (uint) BciProfileWidth * ret_row_cell_count; } - virtual int cell_count() { + virtual int cell_count() const { return static_cell_count(); } @@ -825,13 +1387,13 @@ } // Direct accessors - int bci(uint row) { + int bci(uint row) const { return int_at(bci_cell_index(row)); } - uint bci_count(uint row) { + uint bci_count(uint row) const { return uint_at(bci_count_cell_index(row)); } - int bci_displacement(uint row) { + int bci_displacement(uint row) const { return int_at(bci_displacement_cell_index(row)); } @@ -853,7 +1415,7 @@ void post_initialize(BytecodeStream* stream, MethodData* mdo); #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; #endif }; @@ -878,18 +1440,18 @@ assert(layout->tag() == DataLayout::branch_data_tag, "wrong type"); } - virtual bool is_BranchData() { return true; } + virtual bool is_BranchData() const { return true; } static int static_cell_count() { return branch_cell_count; } - virtual int cell_count() { + virtual int cell_count() const { return static_cell_count(); } // Direct accessor - uint not_taken() { + uint not_taken() const { return uint_at(not_taken_off_set); } @@ -917,7 +1479,7 @@ void post_initialize(BytecodeStream* stream, MethodData* mdo); #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; #endif }; @@ -935,15 +1497,15 @@ array_start_off_set }; - uint array_uint_at(int index) { + uint array_uint_at(int index) const { int aindex = index + array_start_off_set; return uint_at(aindex); } - int array_int_at(int index) { + int array_int_at(int index) const { int aindex = index + array_start_off_set; return int_at(aindex); } - oop array_oop_at(int index) { + oop array_oop_at(int index) const { int aindex = index + array_start_off_set; return oop_at(aindex); } @@ -960,17 +1522,17 @@ public: ArrayData(DataLayout* layout) : ProfileData(layout) {} - virtual bool is_ArrayData() { return true; } + virtual bool is_ArrayData() const { return true; } static int static_cell_count() { return -1; } - int array_len() { + int array_len() const { return int_at_unchecked(array_len_off_set); } - virtual int cell_count() { + virtual int cell_count() const { return array_len() + 1; } @@ -1017,29 +1579,29 @@ assert(layout->tag() == DataLayout::multi_branch_data_tag, "wrong type"); } - virtual bool is_MultiBranchData() { return true; } + virtual bool is_MultiBranchData() const { return true; } static int compute_cell_count(BytecodeStream* stream); - int number_of_cases() { + int number_of_cases() const { int alen = array_len() - 2; // get rid of default case here. assert(alen % per_case_cell_count == 0, "must be even"); return (alen / per_case_cell_count); } - uint default_count() { + uint default_count() const { return array_uint_at(default_count_off_set); } - int default_displacement() { + int default_displacement() const { return array_int_at(default_disaplacement_off_set); } - uint count_at(int index) { + uint count_at(int index) const { return array_uint_at(case_array_start + index * per_case_cell_count + relative_count_off_set); } - int displacement_at(int index) { + int displacement_at(int index) const { return array_int_at(case_array_start + index * per_case_cell_count + relative_displacement_off_set); @@ -1074,7 +1636,7 @@ void post_initialize(BytecodeStream* stream, MethodData* mdo); #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; #endif }; @@ -1085,14 +1647,14 @@ assert(layout->tag() == DataLayout::arg_info_data_tag, "wrong type"); } - virtual bool is_ArgInfoData() { return true; } + virtual bool is_ArgInfoData() const { return true; } - int number_of_args() { + int number_of_args() const { return array_len(); } - uint arg_modified(int arg) { + uint arg_modified(int arg) const { return array_uint_at(arg); } @@ -1101,10 +1663,79 @@ } #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; #endif }; +// ParametersTypeData +// +// A ParametersTypeData is used to access profiling information about +// types of parameters to a method +class ParametersTypeData : public ArrayData { + +private: + TypeStackSlotEntries _parameters; + + static int stack_slot_local_offset(int i) { + assert_profiling_enabled(); + return array_start_off_set + TypeStackSlotEntries::stack_slot_local_offset(i); + } + + static int type_local_offset(int i) { + assert_profiling_enabled(); + return array_start_off_set + TypeStackSlotEntries::type_local_offset(i); + } + + static bool profiling_enabled(); + static void assert_profiling_enabled() { + assert(profiling_enabled(), "method parameters profiling should be on"); + } + +public: + ParametersTypeData(DataLayout* layout) : ArrayData(layout), _parameters(1, number_of_parameters()) { + assert(layout->tag() == DataLayout::parameters_type_data_tag, "wrong type"); + // Some compilers (VC++) don't want this passed in member initialization list + _parameters.set_profile_data(this); + } + + static int compute_cell_count(Method* m); + + virtual bool is_ParametersTypeData() const { return true; } + + virtual void post_initialize(BytecodeStream* stream, MethodData* mdo); + + int number_of_parameters() const { + return array_len() / TypeStackSlotEntries::per_arg_count(); + } + + const TypeStackSlotEntries* parameters() const { return &_parameters; } + + uint stack_slot(int i) const { + return _parameters.stack_slot(i); + } + + void set_type(int i, Klass* k) { + intptr_t current = _parameters.type(i); + _parameters.set_type(i, TypeEntries::with_status((intptr_t)k, current)); + } + + virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) { + _parameters.clean_weak_klass_links(is_alive_closure); + } + +#ifndef PRODUCT + virtual void print_data_on(outputStream* st) const; +#endif + + static ByteSize stack_slot_offset(int i) { + return cell_offset(stack_slot_local_offset(i)); + } + + static ByteSize type_offset(int i) { + return cell_offset(type_local_offset(i)); + } +}; + // MethodData* // // A MethodData* holds information which has been collected about @@ -1216,6 +1847,10 @@ // Size of _data array in bytes. (Excludes header and extra_data fields.) int _data_size; + // data index for the area dedicated to parameters. -1 if no + // parameter profiling. + int _parameters_type_data_di; + // Beginning of the data entries intptr_t _data[1]; @@ -1271,6 +1906,24 @@ // return the argument info cell ArgInfoData *arg_info(); + enum { + no_type_profile = 0, + type_profile_jsr292 = 1, + type_profile_all = 2 + }; + + static bool profile_jsr292(methodHandle m, int bci); + static int profile_arguments_flag(); + static bool profile_arguments_jsr292_only(); + static bool profile_all_arguments(); + static bool profile_arguments_for_invoke(methodHandle m, int bci); + static int profile_return_flag(); + static bool profile_all_return(); + static bool profile_return_for_invoke(methodHandle m, int bci); + static int profile_parameters_flag(); + static bool profile_parameters_jsr292_only(); + static bool profile_all_parameters(); + public: static int header_size() { return sizeof(MethodData)/wordSize; @@ -1476,6 +2129,16 @@ } } + // Return pointer to area dedicated to parameters in MDO + ParametersTypeData* parameters_type_data() const { + return _parameters_type_data_di != -1 ? data_layout_at(_parameters_type_data_di)->data_in()->as_ParametersTypeData() : NULL; + } + + int parameters_type_data_di() const { + assert(_parameters_type_data_di != -1, "no args type data"); + return _parameters_type_data_di; + } + // Support for code generation static ByteSize data_offset() { return byte_offset_of(MethodData, _data[0]); @@ -1488,6 +2151,10 @@ return byte_offset_of(MethodData, _backedge_counter); } + static ByteSize parameters_type_data_di_offset() { + return byte_offset_of(MethodData, _parameters_type_data_di); + } + // Deallocation support - no pointer fields to deallocate void deallocate_contents(ClassLoaderData* loader_data) {} @@ -1510,6 +2177,12 @@ // verification void verify_on(outputStream* st); void verify_data_on(outputStream* st); + + static bool profile_parameters_for_method(methodHandle m); + static bool profile_arguments(); + static bool profile_return(); + static bool profile_parameters(); + static bool profile_return_jsr292_only(); }; #endif // SHARE_VM_OOPS_METHODDATAOOP_HPP diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/bytecodeInfo.cpp --- a/src/share/vm/opto/bytecodeInfo.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/bytecodeInfo.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -197,6 +197,7 @@ // negative filter: should callee NOT be inlined? bool InlineTree::should_not_inline(ciMethod *callee_method, ciMethod* caller_method, + JVMState* jvms, WarmCallInfo* wci_result) { const char* fail_msg = NULL; @@ -226,7 +227,7 @@ // don't inline exception code unless the top method belongs to an // exception class if (callee_method->holder()->is_subclass_of(C->env()->Throwable_klass())) { - ciMethod* top_method = caller_jvms() ? caller_jvms()->of_depth(1)->method() : method(); + ciMethod* top_method = jvms->caller() != NULL ? jvms->caller()->of_depth(1)->method() : method(); if (!top_method->holder()->is_subclass_of(C->env()->Throwable_klass())) { wci_result->set_profit(wci_result->profit() * 0.1); } @@ -328,7 +329,7 @@ // return true if ok // Relocated from "InliningClosure::try_to_inline" bool InlineTree::try_to_inline(ciMethod* callee_method, ciMethod* caller_method, - int caller_bci, ciCallProfile& profile, + int caller_bci, JVMState* jvms, ciCallProfile& profile, WarmCallInfo* wci_result, bool& should_delay) { // Old algorithm had funny accumulating BC-size counters @@ -346,7 +347,7 @@ wci_result)) { return false; } - if (should_not_inline(callee_method, caller_method, wci_result)) { + if (should_not_inline(callee_method, caller_method, jvms, wci_result)) { return false; } @@ -397,24 +398,35 @@ } // detect direct and indirect recursive inlining - if (!callee_method->is_compiled_lambda_form()) { + { // count the current method and the callee - int inline_level = (method() == callee_method) ? 1 : 0; - if (inline_level > MaxRecursiveInlineLevel) { - set_msg("recursively inlining too deep"); - return false; + const bool is_compiled_lambda_form = callee_method->is_compiled_lambda_form(); + int inline_level = 0; + if (!is_compiled_lambda_form) { + if (method() == callee_method) { + inline_level++; + } } // count callers of current method and callee - JVMState* jvms = caller_jvms(); - while (jvms != NULL && jvms->has_method()) { - if (jvms->method() == callee_method) { - inline_level++; - if (inline_level > MaxRecursiveInlineLevel) { - set_msg("recursively inlining too deep"); - return false; + Node* callee_argument0 = is_compiled_lambda_form ? jvms->map()->argument(jvms, 0)->uncast() : NULL; + for (JVMState* j = jvms->caller(); j != NULL && j->has_method(); j = j->caller()) { + if (j->method() == callee_method) { + if (is_compiled_lambda_form) { + // Since compiled lambda forms are heavily reused we allow recursive inlining. If it is truly + // a recursion (using the same "receiver") we limit inlining otherwise we can easily blow the + // compiler stack. + Node* caller_argument0 = j->map()->argument(j, 0)->uncast(); + if (caller_argument0 == callee_argument0) { + inline_level++; + } + } else { + inline_level++; } } - jvms = jvms->caller(); + } + if (inline_level > MaxRecursiveInlineLevel) { + set_msg("recursive inlining is too deep"); + return false; } } @@ -536,7 +548,7 @@ // Check if inlining policy says no. WarmCallInfo wci = *(initial_wci); bool success = try_to_inline(callee_method, caller_method, caller_bci, - profile, &wci, should_delay); + jvms, profile, &wci, should_delay); #ifndef PRODUCT if (UseOldInlining && InlineWarmCalls diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/c2_globals.hpp --- a/src/share/vm/opto/c2_globals.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/c2_globals.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -638,7 +638,13 @@ "Find best control for expensive operations") \ \ product(bool, UseMathExactIntrinsics, true, \ - "Enables intrinsification of various java.lang.Math funcitons") + "Enables intrinsification of various java.lang.Math functions") \ + \ + experimental(bool, ReplaceInParentMaps, false, \ + "Propagate type improvements in callers of inlinee if possible") \ + \ + experimental(bool, UseTypeSpeculation, false, \ + "Speculatively propagate types from profiles") C2_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG) diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/c2compiler.cpp --- a/src/share/vm/opto/c2compiler.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/c2compiler.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -44,9 +44,6 @@ # include "adfiles/ad_ppc.hpp" #endif - -volatile int C2Compiler::_runtimes = uninitialized; - // register information defined by ADLC extern const char register_save_policy[]; extern const int register_save_type[]; @@ -57,7 +54,7 @@ const char* C2Compiler::retry_no_escape_analysis() { return "retry without escape analysis"; } -void C2Compiler::initialize_runtime() { +bool C2Compiler::init_c2_runtime() { // Check assumptions used while running ADLC Compile::adlc_verification(); @@ -90,41 +87,31 @@ CompilerThread* thread = CompilerThread::current(); - HandleMark handle_mark(thread); - - OptoRuntime::generate(thread->env()); - + HandleMark handle_mark(thread); + return OptoRuntime::generate(thread->env()); } void C2Compiler::initialize() { - - // This method can only be called once per C2Compiler object // The first compiler thread that gets here will initialize the - // small amount of global state (and runtime stubs) that c2 needs. + // small amount of global state (and runtime stubs) that C2 needs. // There is a race possible once at startup and then we're fine // Note that this is being called from a compiler thread not the // main startup thread. - - if (_runtimes != initialized) { - initialize_runtimes( initialize_runtime, &_runtimes); + if (should_perform_init()) { + bool successful = C2Compiler::init_c2_runtime(); + int new_state = (successful) ? initialized : failed; + set_state(new_state); } - - // Mark this compiler object as ready to roll - mark_initialized(); } -void C2Compiler::compile_method(ciEnv* env, - ciMethod* target, - int entry_bci) { - if (!is_initialized()) { - initialize(); - } +void C2Compiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci) { + assert(is_initialized(), "Compiler thread must be initialized"); + bool subsume_loads = SubsumeLoads; - bool do_escape_analysis = DoEscapeAnalysis && - !env->jvmti_can_access_local_variables(); + bool do_escape_analysis = DoEscapeAnalysis && !env->jvmti_can_access_local_variables(); bool eliminate_boxing = EliminateAutoBox; while (!env->failing()) { // Attempt to compile while subsuming loads into machine instructions. diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/c2compiler.hpp --- a/src/share/vm/opto/c2compiler.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/c2compiler.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -28,24 +28,17 @@ #include "compiler/abstractCompiler.hpp" class C2Compiler : public AbstractCompiler { -private: - - static void initialize_runtime(); + private: + static bool init_c2_runtime(); public: // Name const char *name() { return "C2"; } - static volatile int _runtimes; - #ifdef TIERED virtual bool is_c2() { return true; }; #endif // TIERED - // Customization - bool needs_adapters () { return true; } - bool needs_stubs () { return true; } - void initialize(); // Compilation entry point for methods diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/callGenerator.cpp --- a/src/share/vm/opto/callGenerator.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/callGenerator.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -63,12 +63,12 @@ } virtual bool is_parse() const { return true; } - virtual JVMState* generate(JVMState* jvms); + virtual JVMState* generate(JVMState* jvms, Parse* parent_parser); int is_osr() { return _is_osr; } }; -JVMState* ParseGenerator::generate(JVMState* jvms) { +JVMState* ParseGenerator::generate(JVMState* jvms, Parse* parent_parser) { Compile* C = Compile::current(); if (is_osr()) { @@ -80,7 +80,7 @@ return NULL; // bailing out of the compile; do not try to parse } - Parse parser(jvms, method(), _expected_uses); + Parse parser(jvms, method(), _expected_uses, parent_parser); // Grab signature for matching/allocation #ifdef ASSERT if (parser.tf() != (parser.depth() == 1 ? C->tf() : tf())) { @@ -119,12 +119,12 @@ _separate_io_proj(separate_io_proj) { } - virtual JVMState* generate(JVMState* jvms); + virtual JVMState* generate(JVMState* jvms, Parse* parent_parser); CallStaticJavaNode* call_node() const { return _call_node; } }; -JVMState* DirectCallGenerator::generate(JVMState* jvms) { +JVMState* DirectCallGenerator::generate(JVMState* jvms, Parse* parent_parser) { GraphKit kit(jvms); bool is_static = method()->is_static(); address target = is_static ? SharedRuntime::get_resolve_static_call_stub() @@ -171,10 +171,10 @@ vtable_index >= 0, "either invalid or usable"); } virtual bool is_virtual() const { return true; } - virtual JVMState* generate(JVMState* jvms); + virtual JVMState* generate(JVMState* jvms, Parse* parent_parser); }; -JVMState* VirtualCallGenerator::generate(JVMState* jvms) { +JVMState* VirtualCallGenerator::generate(JVMState* jvms, Parse* parent_parser) { GraphKit kit(jvms); Node* receiver = kit.argument(0); @@ -276,7 +276,7 @@ // Convert the CallStaticJava into an inline virtual void do_late_inline(); - virtual JVMState* generate(JVMState* jvms) { + virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) { Compile *C = Compile::current(); C->print_inlining_skip(this); @@ -290,7 +290,7 @@ // that the late inlining logic can distinguish between fall // through and exceptional uses of the memory and io projections // as is done for allocations and macro expansion. - return DirectCallGenerator::generate(jvms); + return DirectCallGenerator::generate(jvms, parent_parser); } virtual void print_inlining_late(const char* msg) { @@ -389,7 +389,7 @@ } // Now perform the inling using the synthesized JVMState - JVMState* new_jvms = _inline_cg->generate(jvms); + JVMState* new_jvms = _inline_cg->generate(jvms, NULL); if (new_jvms == NULL) return; // no change if (C->failing()) return; @@ -429,8 +429,8 @@ virtual bool is_mh_late_inline() const { return true; } - virtual JVMState* generate(JVMState* jvms) { - JVMState* new_jvms = LateInlineCallGenerator::generate(jvms); + virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) { + JVMState* new_jvms = LateInlineCallGenerator::generate(jvms, parent_parser); if (_input_not_const) { // inlining won't be possible so no need to enqueue right now. call_node()->set_generator(this); @@ -477,15 +477,17 @@ LateInlineStringCallGenerator(ciMethod* method, CallGenerator* inline_cg) : LateInlineCallGenerator(method, inline_cg) {} - virtual JVMState* generate(JVMState* jvms) { + virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) { Compile *C = Compile::current(); C->print_inlining_skip(this); C->add_string_late_inline(this); - JVMState* new_jvms = DirectCallGenerator::generate(jvms); + JVMState* new_jvms = DirectCallGenerator::generate(jvms, parent_parser); return new_jvms; } + + virtual bool is_string_late_inline() const { return true; } }; CallGenerator* CallGenerator::for_string_late_inline(ciMethod* method, CallGenerator* inline_cg) { @@ -498,13 +500,13 @@ LateInlineBoxingCallGenerator(ciMethod* method, CallGenerator* inline_cg) : LateInlineCallGenerator(method, inline_cg) {} - virtual JVMState* generate(JVMState* jvms) { + virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) { Compile *C = Compile::current(); C->print_inlining_skip(this); C->add_boxing_late_inline(this); - JVMState* new_jvms = DirectCallGenerator::generate(jvms); + JVMState* new_jvms = DirectCallGenerator::generate(jvms, parent_parser); return new_jvms; } }; @@ -540,7 +542,7 @@ virtual bool is_virtual() const { return _is_virtual; } virtual bool is_deferred() const { return true; } - virtual JVMState* generate(JVMState* jvms); + virtual JVMState* generate(JVMState* jvms, Parse* parent_parser); }; @@ -550,12 +552,12 @@ return new WarmCallGenerator(ci, if_cold, if_hot); } -JVMState* WarmCallGenerator::generate(JVMState* jvms) { +JVMState* WarmCallGenerator::generate(JVMState* jvms, Parse* parent_parser) { Compile* C = Compile::current(); if (C->log() != NULL) { C->log()->elem("warm_call bci='%d'", jvms->bci()); } - jvms = _if_cold->generate(jvms); + jvms = _if_cold->generate(jvms, parent_parser); if (jvms != NULL) { Node* m = jvms->map()->control(); if (m->is_CatchProj()) m = m->in(0); else m = C->top(); @@ -616,7 +618,7 @@ virtual bool is_inline() const { return _if_hit->is_inline(); } virtual bool is_deferred() const { return _if_hit->is_deferred(); } - virtual JVMState* generate(JVMState* jvms); + virtual JVMState* generate(JVMState* jvms, Parse* parent_parser); }; @@ -628,7 +630,7 @@ } -JVMState* PredictedCallGenerator::generate(JVMState* jvms) { +JVMState* PredictedCallGenerator::generate(JVMState* jvms, Parse* parent_parser) { GraphKit kit(jvms); PhaseGVN& gvn = kit.gvn(); // We need an explicit receiver null_check before checking its type. @@ -656,7 +658,7 @@ { PreserveJVMState pjvms(&kit); kit.set_control(slow_ctl); if (!kit.stopped()) { - slow_jvms = _if_missed->generate(kit.sync_jvms()); + slow_jvms = _if_missed->generate(kit.sync_jvms(), parent_parser); if (kit.failing()) return NULL; // might happen because of NodeCountInliningCutoff assert(slow_jvms != NULL, "must be"); @@ -677,12 +679,12 @@ kit.replace_in_map(receiver, exact_receiver); // Make the hot call: - JVMState* new_jvms = _if_hit->generate(kit.sync_jvms()); + JVMState* new_jvms = _if_hit->generate(kit.sync_jvms(), parent_parser); if (new_jvms == NULL) { // Inline failed, so make a direct call. assert(_if_hit->is_inline(), "must have been a failed inline"); CallGenerator* cg = CallGenerator::for_direct_call(_if_hit->method()); - new_jvms = cg->generate(kit.sync_jvms()); + new_jvms = cg->generate(kit.sync_jvms(), parent_parser); } kit.add_exception_states_from(new_jvms); kit.set_jvms(new_jvms); @@ -773,7 +775,7 @@ ciMethod* target = oop_ptr->const_oop()->as_method_handle()->get_vmtarget(); guarantee(!target->is_method_handle_intrinsic(), "should not happen"); // XXX remove const int vtable_index = Method::invalid_vtable_index; - CallGenerator* cg = C->call_generator(target, vtable_index, false, jvms, true, PROB_ALWAYS, true, true); + CallGenerator* cg = C->call_generator(target, vtable_index, false, jvms, true, PROB_ALWAYS, NULL, true, true); assert(!cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here"); if (cg != NULL && cg->is_inline()) return cg; @@ -829,6 +831,7 @@ int vtable_index = Method::invalid_vtable_index; bool call_does_dispatch = false; + ciKlass* speculative_receiver_type = NULL; if (is_virtual_or_interface) { ciInstanceKlass* klass = target->holder(); Node* receiver_node = kit.argument(0); @@ -837,9 +840,12 @@ target = C->optimize_virtual_call(caller, jvms->bci(), klass, target, receiver_type, is_virtual, call_does_dispatch, vtable_index); // out-parameters + // We lack profiling at this call but type speculation may + // provide us with a type + speculative_receiver_type = receiver_type->speculative_type(); } - CallGenerator* cg = C->call_generator(target, vtable_index, call_does_dispatch, jvms, true, PROB_ALWAYS, true, true); + CallGenerator* cg = C->call_generator(target, vtable_index, call_does_dispatch, jvms, true, PROB_ALWAYS, speculative_receiver_type, true, true); assert(!cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here"); if (cg != NULL && cg->is_inline()) return cg; @@ -874,7 +880,7 @@ virtual bool is_inlined() const { return true; } virtual bool is_intrinsic() const { return true; } - virtual JVMState* generate(JVMState* jvms); + virtual JVMState* generate(JVMState* jvms, Parse* parent_parser); }; @@ -884,7 +890,7 @@ } -JVMState* PredictedIntrinsicGenerator::generate(JVMState* jvms) { +JVMState* PredictedIntrinsicGenerator::generate(JVMState* jvms, Parse* parent_parser) { GraphKit kit(jvms); PhaseGVN& gvn = kit.gvn(); @@ -904,7 +910,7 @@ PreserveJVMState pjvms(&kit); kit.set_control(slow_ctl); if (!kit.stopped()) { - slow_jvms = _cg->generate(kit.sync_jvms()); + slow_jvms = _cg->generate(kit.sync_jvms(), parent_parser); if (kit.failing()) return NULL; // might happen because of NodeCountInliningCutoff assert(slow_jvms != NULL, "must be"); @@ -922,12 +928,12 @@ } // Generate intrinsic code: - JVMState* new_jvms = _intrinsic->generate(kit.sync_jvms()); + JVMState* new_jvms = _intrinsic->generate(kit.sync_jvms(), parent_parser); if (new_jvms == NULL) { // Intrinsic failed, so use slow code or make a direct call. if (slow_map == NULL) { CallGenerator* cg = CallGenerator::for_direct_call(method()); - new_jvms = cg->generate(kit.sync_jvms()); + new_jvms = cg->generate(kit.sync_jvms(), parent_parser); } else { kit.set_jvms(slow_jvms); return kit.transfer_exceptions_into_jvms(); @@ -997,7 +1003,7 @@ virtual bool is_virtual() const { ShouldNotReachHere(); return false; } virtual bool is_trap() const { return true; } - virtual JVMState* generate(JVMState* jvms); + virtual JVMState* generate(JVMState* jvms, Parse* parent_parser); }; @@ -1009,7 +1015,7 @@ } -JVMState* UncommonTrapCallGenerator::generate(JVMState* jvms) { +JVMState* UncommonTrapCallGenerator::generate(JVMState* jvms, Parse* parent_parser) { GraphKit kit(jvms); // Take the trap with arguments pushed on the stack. (Cf. null_check_receiver). int nargs = method()->arg_size(); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/callGenerator.hpp --- a/src/share/vm/opto/callGenerator.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/callGenerator.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -31,6 +31,8 @@ #include "opto/type.hpp" #include "runtime/deoptimization.hpp" +class Parse; + //---------------------------CallGenerator------------------------------------- // The subclasses of this class handle generation of ideal nodes for // call sites and method entry points. @@ -72,6 +74,7 @@ virtual bool is_late_inline() const { return false; } // same but for method handle calls virtual bool is_mh_late_inline() const { return false; } + virtual bool is_string_late_inline() const{ return false; } // for method handle calls: have we tried inlinining the call already? virtual bool already_attempted() const { ShouldNotReachHere(); return false; } @@ -108,7 +111,7 @@ // // If the result is NULL, it means that this CallGenerator was unable // to handle the given call, and another CallGenerator should be consulted. - virtual JVMState* generate(JVMState* jvms) = 0; + virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) = 0; // How to generate a call site that is inlined: static CallGenerator* for_inline(ciMethod* m, float expected_uses = -1); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/chaitin.hpp --- a/src/share/vm/opto/chaitin.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/chaitin.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -52,6 +52,7 @@ class LRG : public ResourceObj { friend class VMStructs; public: + static const uint AllStack_size = 0xFFFFF; // This mask size is used to tell that the mask of this LRG supports stack positions enum { SPILL_REG=29999 }; // Register number of a spilled LRG double _cost; // 2 for loads/1 for stores times block freq @@ -80,14 +81,21 @@ private: uint _eff_degree; // Effective degree: Sum of neighbors _num_regs public: - int degree() const { assert( _degree_valid, "" ); return _eff_degree; } + int degree() const { assert( _degree_valid , "" ); return _eff_degree; } // Degree starts not valid and any change to the IFG neighbor // set makes it not valid. - void set_degree( uint degree ) { _eff_degree = degree; debug_only(_degree_valid = 1;) } + void set_degree( uint degree ) { + _eff_degree = degree; + debug_only(_degree_valid = 1;) + assert(!_mask.is_AllStack() || (_mask.is_AllStack() && lo_degree()), "_eff_degree can't be bigger than AllStack_size - _num_regs if the mask supports stack registers"); + } // Made a change that hammered degree void invalid_degree() { debug_only(_degree_valid=0;) } // Incrementally modify degree. If it was correct, it should remain correct - void inc_degree( uint mod ) { _eff_degree += mod; } + void inc_degree( uint mod ) { + _eff_degree += mod; + assert(!_mask.is_AllStack() || (_mask.is_AllStack() && lo_degree()), "_eff_degree can't be bigger than AllStack_size - _num_regs if the mask supports stack registers"); + } // Compute the degree between 2 live ranges int compute_degree( LRG &l ) const; @@ -95,9 +103,9 @@ RegMask _mask; // Allowed registers for this LRG uint _mask_size; // cache of _mask.Size(); public: - int compute_mask_size() const { return _mask.is_AllStack() ? 65535 : _mask.Size(); } + int compute_mask_size() const { return _mask.is_AllStack() ? AllStack_size : _mask.Size(); } void set_mask_size( int size ) { - assert((size == 65535) || (size == (int)_mask.Size()), ""); + assert((size == (int)AllStack_size) || (size == (int)_mask.Size()), ""); _mask_size = size; #ifdef ASSERT _msize_valid=1; diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/classes.hpp --- a/src/share/vm/opto/classes.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/classes.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -30,6 +30,7 @@ macro(AbsI) macro(AddD) macro(AddExactI) +macro(AddExactL) macro(AddF) macro(AddI) macro(AddL) @@ -170,6 +171,8 @@ macro(Mach) macro(MachProj) macro(MathExact) +macro(MathExactI) +macro(MathExactL) macro(MaxI) macro(MemBarAcquire) macro(MemBarAcquireLock) @@ -189,12 +192,16 @@ macro(MoveL2D) macro(MoveD2L) macro(MulD) +macro(MulExactI) +macro(MulExactL) macro(MulF) macro(MulHiL) macro(MulI) macro(MulL) macro(Multi) macro(NegD) +macro(NegExactI) +macro(NegExactL) macro(NegF) macro(NeverBranch) macro(Opaque1) @@ -244,6 +251,8 @@ macro(StrEquals) macro(StrIndexOf) macro(SubD) +macro(SubExactI) +macro(SubExactL) macro(SubF) macro(SubI) macro(SubL) diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/compile.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -47,6 +47,7 @@ #include "opto/machnode.hpp" #include "opto/macro.hpp" #include "opto/matcher.hpp" +#include "opto/mathexactnode.hpp" #include "opto/memnode.hpp" #include "opto/mulnode.hpp" #include "opto/node.hpp" @@ -654,7 +655,8 @@ _inlining_progress(false), _inlining_incrementally(false), _print_inlining_list(NULL), - _print_inlining_idx(0) { + _print_inlining_idx(0), + _preserve_jvm_state(0) { C = this; CompileWrapper cw(this); @@ -762,7 +764,7 @@ return; } JVMState* jvms = build_start_state(start(), tf()); - if ((jvms = cg->generate(jvms)) == NULL) { + if ((jvms = cg->generate(jvms, NULL)) == NULL) { record_method_not_compilable("method parse failed"); return; } @@ -939,7 +941,8 @@ _inlining_progress(false), _inlining_incrementally(false), _print_inlining_list(NULL), - _print_inlining_idx(0) { + _print_inlining_idx(0), + _preserve_jvm_state(0) { C = this; #ifndef PRODUCT @@ -1357,7 +1360,7 @@ // During the 2nd round of IterGVN, NotNull castings are removed. // Make sure the Bottom and NotNull variants alias the same. // Also, make sure exact and non-exact variants alias the same. - if( ptr == TypePtr::NotNull || ta->klass_is_exact() ) { + if (ptr == TypePtr::NotNull || ta->klass_is_exact() || ta->speculative() != NULL) { tj = ta = TypeAryPtr::make(TypePtr::BotPTR,ta->ary(),ta->klass(),false,offset); } } @@ -1382,6 +1385,9 @@ // Also, make sure exact and non-exact variants alias the same. tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,offset); } + if (to->speculative() != NULL) { + tj = to = TypeInstPtr::make(to->ptr(),to->klass(),to->klass_is_exact(),to->const_oop(),to->offset(), to->instance_id()); + } // Canonicalize the holder of this field if (offset >= 0 && offset < instanceOopDesc::base_offset_in_bytes()) { // First handle header references such as a LoadKlassNode, even if the @@ -2010,6 +2016,12 @@ if (failing()) return; } + // Remove the speculative part of types and clean up the graph from + // the extra CastPP nodes whose only purpose is to carry them. Do + // that early so that optimizations are not disrupted by the extra + // CastPP nodes. + remove_speculative_types(igvn); + // No more new expensive nodes will be added to the list from here // so keep only the actual candidates for optimizations. cleanup_expensive_nodes(igvn); @@ -2986,6 +2998,37 @@ n->set_req(MemBarNode::Precedent, top()); } break; + // Must set a control edge on all nodes that produce a FlagsProj + // so they can't escape the block that consumes the flags. + // Must also set the non throwing branch as the control + // for all nodes that depends on the result. Unless the node + // already have a control that isn't the control of the + // flag producer + case Op_FlagsProj: + { + MathExactNode* math = (MathExactNode*) n->in(0); + Node* ctrl = math->control_node(); + Node* non_throwing = math->non_throwing_branch(); + math->set_req(0, ctrl); + + Node* result = math->result_node(); + if (result != NULL) { + for (DUIterator_Fast jmax, j = result->fast_outs(jmax); j < jmax; j++) { + Node* out = result->fast_out(j); + // Phi nodes shouldn't be moved. They would only match below if they + // had the same control as the MathExactNode. The only time that + // would happen is if the Phi is also an input to the MathExact + if (!out->is_Phi()) { + if (out->in(0) == NULL) { + out->set_req(0, non_throwing); + } else if (out->in(0) == ctrl) { + out->set_req(0, non_throwing); + } + } + } + } + } + break; default: assert( !n->is_Call(), "" ); assert( !n->is_Mem(), "" ); @@ -3765,6 +3808,45 @@ } } +/** + * Remove the speculative part of types and clean up the graph + */ +void Compile::remove_speculative_types(PhaseIterGVN &igvn) { + if (UseTypeSpeculation) { + Unique_Node_List worklist; + worklist.push(root()); + int modified = 0; + // Go over all type nodes that carry a speculative type, drop the + // speculative part of the type and enqueue the node for an igvn + // which may optimize it out. + for (uint next = 0; next < worklist.size(); ++next) { + Node *n = worklist.at(next); + if (n->is_Type() && n->as_Type()->type()->isa_oopptr() != NULL && + n->as_Type()->type()->is_oopptr()->speculative() != NULL) { + TypeNode* tn = n->as_Type(); + const TypeOopPtr* t = tn->type()->is_oopptr(); + bool in_hash = igvn.hash_delete(n); + assert(in_hash, "node should be in igvn hash table"); + tn->set_type(t->remove_speculative()); + igvn.hash_insert(n); + igvn._worklist.push(n); // give it a chance to go away + modified++; + } + uint max = n->len(); + for( uint i = 0; i < max; ++i ) { + Node *m = n->in(i); + if (not_a_node(m)) continue; + worklist.push(m); + } + } + // Drop the speculative part of all types in the igvn's type table + igvn.remove_speculative_types(); + if (modified > 0) { + igvn.optimize(); + } + } +} + // Auxiliary method to support randomized stressing/fuzzing. // // This method can be called the arbitrary number of times, with current count diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/compile.hpp --- a/src/share/vm/opto/compile.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/compile.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -424,6 +424,11 @@ static int cmp_expensive_nodes(Node** n1, Node** n2); // Expensive nodes list already sorted? bool expensive_nodes_sorted() const; + // Remove the speculative part of types and clean up the graph + void remove_speculative_types(PhaseIterGVN &igvn); + + // Are we within a PreserveJVMState block? + int _preserve_jvm_state; public: @@ -820,7 +825,9 @@ // Decide how to build a call. // The profile factor is a discount to apply to this site's interp. profile. - CallGenerator* call_generator(ciMethod* call_method, int vtable_index, bool call_does_dispatch, JVMState* jvms, bool allow_inline, float profile_factor, bool allow_intrinsics = true, bool delayed_forbidden = false); + CallGenerator* call_generator(ciMethod* call_method, int vtable_index, bool call_does_dispatch, + JVMState* jvms, bool allow_inline, float profile_factor, ciKlass* speculative_receiver_type = NULL, + bool allow_intrinsics = true, bool delayed_forbidden = false); bool should_delay_inlining(ciMethod* call_method, JVMState* jvms) { return should_delay_string_inlining(call_method, jvms) || should_delay_boxing_inlining(call_method, jvms); @@ -1156,6 +1163,21 @@ // Auxiliary method for randomized fuzzing/stressing static bool randomized_select(int count); + + // enter a PreserveJVMState block + void inc_preserve_jvm_state() { + _preserve_jvm_state++; + } + + // exit a PreserveJVMState block + void dec_preserve_jvm_state() { + _preserve_jvm_state--; + assert(_preserve_jvm_state >= 0, "_preserve_jvm_state shouldn't be negative"); + } + + bool has_preserve_jvm_state() const { + return _preserve_jvm_state > 0; + } }; #endif // SHARE_VM_OPTO_COMPILE_HPP diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/doCall.cpp --- a/src/share/vm/opto/doCall.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/doCall.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -63,7 +63,8 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool call_does_dispatch, JVMState* jvms, bool allow_inline, - float prof_factor, bool allow_intrinsics, bool delayed_forbidden) { + float prof_factor, ciKlass* speculative_receiver_type, + bool allow_intrinsics, bool delayed_forbidden) { ciMethod* caller = jvms->method(); int bci = jvms->bci(); Bytecodes::Code bytecode = caller->java_code_at_bci(bci); @@ -117,7 +118,7 @@ if (cg->is_predicted()) { // Code without intrinsic but, hopefully, inlined. CallGenerator* inline_cg = this->call_generator(callee, - vtable_index, call_does_dispatch, jvms, allow_inline, prof_factor, false); + vtable_index, call_does_dispatch, jvms, allow_inline, prof_factor, speculative_receiver_type, false); if (inline_cg != NULL) { cg = CallGenerator::for_predicted_intrinsic(cg, inline_cg); } @@ -212,8 +213,24 @@ // The major receiver's count >= TypeProfileMajorReceiverPercent of site_count. bool have_major_receiver = (100.*profile.receiver_prob(0) >= (float)TypeProfileMajorReceiverPercent); ciMethod* receiver_method = NULL; - if (have_major_receiver || profile.morphism() == 1 || - (profile.morphism() == 2 && UseBimorphicInlining)) { + + int morphism = profile.morphism(); + if (speculative_receiver_type != NULL) { + // We have a speculative type, we should be able to resolve + // the call. We do that before looking at the profiling at + // this invoke because it may lead to bimorphic inlining which + // a speculative type should help us avoid. + receiver_method = callee->resolve_invoke(jvms->method()->holder(), + speculative_receiver_type); + if (receiver_method == NULL) { + speculative_receiver_type = NULL; + } else { + morphism = 1; + } + } + if (receiver_method == NULL && + (have_major_receiver || morphism == 1 || + (morphism == 2 && UseBimorphicInlining))) { // receiver_method = profile.method(); // Profiles do not suggest methods now. Look it up in the major receiver. receiver_method = callee->resolve_invoke(jvms->method()->holder(), @@ -227,7 +244,7 @@ // Look up second receiver. CallGenerator* next_hit_cg = NULL; ciMethod* next_receiver_method = NULL; - if (profile.morphism() == 2 && UseBimorphicInlining) { + if (morphism == 2 && UseBimorphicInlining) { next_receiver_method = callee->resolve_invoke(jvms->method()->holder(), profile.receiver(1)); if (next_receiver_method != NULL) { @@ -242,11 +259,10 @@ } } CallGenerator* miss_cg; - Deoptimization::DeoptReason reason = (profile.morphism() == 2) ? + Deoptimization::DeoptReason reason = morphism == 2 ? Deoptimization::Reason_bimorphic : Deoptimization::Reason_class_check; - if (( profile.morphism() == 1 || - (profile.morphism() == 2 && next_hit_cg != NULL) ) && + if ((morphism == 1 || (morphism == 2 && next_hit_cg != NULL)) && !too_many_traps(jvms->method(), jvms->bci(), reason) ) { // Generate uncommon trap for class check failure path @@ -260,6 +276,7 @@ } if (miss_cg != NULL) { if (next_hit_cg != NULL) { + assert(speculative_receiver_type == NULL, "shouldn't end up here if we used speculation"); trace_type_profile(C, jvms->method(), jvms->depth() - 1, jvms->bci(), next_receiver_method, profile.receiver(1), site_count, profile.receiver_count(1)); // We don't need to record dependency on a receiver here and below. // Whenever we inline, the dependency is added by Parse::Parse(). @@ -267,7 +284,9 @@ } if (miss_cg != NULL) { trace_type_profile(C, jvms->method(), jvms->depth() - 1, jvms->bci(), receiver_method, profile.receiver(0), site_count, receiver_count); - CallGenerator* cg = CallGenerator::for_predicted_call(profile.receiver(0), miss_cg, hit_cg, profile.receiver_prob(0)); + ciKlass* k = speculative_receiver_type != NULL ? speculative_receiver_type : profile.receiver(0); + float hit_prob = speculative_receiver_type != NULL ? 1.0 : profile.receiver_prob(0); + CallGenerator* cg = CallGenerator::for_predicted_call(k, miss_cg, hit_cg, hit_prob); if (cg != NULL) return cg; } } @@ -446,13 +465,16 @@ int vtable_index = Method::invalid_vtable_index; bool call_does_dispatch = false; + // Speculative type of the receiver if any + ciKlass* speculative_receiver_type = NULL; if (is_virtual_or_interface) { - Node* receiver_node = stack(sp() - nargs); + Node* receiver_node = stack(sp() - nargs); const TypeOopPtr* receiver_type = _gvn.type(receiver_node)->isa_oopptr(); // call_does_dispatch and vtable_index are out-parameters. They might be changed. callee = C->optimize_virtual_call(method(), bci(), klass, orig_callee, receiver_type, is_virtual, call_does_dispatch, vtable_index); // out-parameters + speculative_receiver_type = receiver_type != NULL ? receiver_type->speculative_type() : NULL; } // Note: It's OK to try to inline a virtual call. @@ -468,7 +490,7 @@ // Decide call tactic. // This call checks with CHA, the interpreter profile, intrinsics table, etc. // It decides whether inlining is desirable or not. - CallGenerator* cg = C->call_generator(callee, vtable_index, call_does_dispatch, jvms, try_inline, prof_factor()); + CallGenerator* cg = C->call_generator(callee, vtable_index, call_does_dispatch, jvms, try_inline, prof_factor(), speculative_receiver_type); // NOTE: Don't use orig_callee and callee after this point! Use cg->method() instead. orig_callee = callee = NULL; @@ -477,6 +499,10 @@ // Round double arguments before call round_double_arguments(cg->method()); + // Feed profiling data for arguments to the type system so it can + // propagate it as speculative types + record_profiled_arguments_for_speculation(cg->method(), bc()); + #ifndef PRODUCT // bump global counters for calls count_compiled_calls(/*at_method_entry*/ false, cg->is_inline()); @@ -491,11 +517,18 @@ // save across call, for a subsequent cast_not_null. Node* receiver = has_receiver ? argument(0) : NULL; + // The extra CheckCastPP for speculative types mess with PhaseStringOpts + if (receiver != NULL && !call_does_dispatch && !cg->is_string_late_inline()) { + // Feed profiling data for a single receiver to the type system so + // it can propagate it as a speculative type + receiver = record_profiled_receiver_for_speculation(receiver); + } + // Bump method data counters (We profile *before* the call is made // because exceptions don't return to the call site.) profile_call(receiver); - JVMState* new_jvms = cg->generate(jvms); + JVMState* new_jvms = cg->generate(jvms, this); if (new_jvms == NULL) { // When inlining attempt fails (e.g., too many arguments), // it may contaminate the current compile state, making it @@ -508,8 +541,8 @@ // the call site, perhaps because it did not match a pattern the // intrinsic was expecting to optimize. Should always be possible to // get a normal java call that may inline in that case - cg = C->call_generator(cg->method(), vtable_index, call_does_dispatch, jvms, try_inline, prof_factor(), /* allow_intrinsics= */ false); - if ((new_jvms = cg->generate(jvms)) == NULL) { + cg = C->call_generator(cg->method(), vtable_index, call_does_dispatch, jvms, try_inline, prof_factor(), speculative_receiver_type, /* allow_intrinsics= */ false); + if ((new_jvms = cg->generate(jvms, this)) == NULL) { guarantee(failing(), "call failed to generate: calls should work"); return; } @@ -607,6 +640,16 @@ null_assert(peek()); set_bci(iter().cur_bci()); // put it back } + BasicType ct = ctype->basic_type(); + if (ct == T_OBJECT || ct == T_ARRAY) { + ciKlass* better_type = method()->return_profiled_type(bci()); + if (UseTypeSpeculation && better_type != NULL) { + // If profiling reports a single type for the return value, + // feed it to the type system so it can propagate it as a + // speculative type + record_profile_for_speculation(stack(sp()-1), better_type); + } + } } // Restart record of parsing work after possible inlining of call diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/escape.cpp --- a/src/share/vm/opto/escape.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/escape.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -780,6 +780,7 @@ } } else { // Allocate instance if (cik->is_subclass_of(_compile->env()->Thread_klass()) || + cik->is_subclass_of(_compile->env()->Reference_klass()) || !cik->is_instance_klass() || // StressReflectiveCode cik->as_instance_klass()->has_finalizer()) { es = PointsToNode::GlobalEscape; diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/graphKit.cpp --- a/src/share/vm/opto/graphKit.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/graphKit.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -639,6 +639,7 @@ _map = kit->map(); // preserve the map _sp = kit->sp(); kit->set_map(clone_map ? kit->clone_map() : NULL); + Compile::current()->inc_preserve_jvm_state(); #ifdef ASSERT _bci = kit->bci(); Parse* parser = kit->is_Parse(); @@ -656,6 +657,7 @@ #endif kit->set_map(_map); kit->set_sp(_sp); + Compile::current()->dec_preserve_jvm_state(); } @@ -1373,17 +1375,70 @@ //--------------------------replace_in_map------------------------------------- void GraphKit::replace_in_map(Node* old, Node* neww) { - this->map()->replace_edge(old, neww); + if (old == neww) { + return; + } + + map()->replace_edge(old, neww); // Note: This operation potentially replaces any edge // on the map. This includes locals, stack, and monitors // of the current (innermost) JVM state. - // We can consider replacing in caller maps. - // The idea would be that an inlined function's null checks - // can be shared with the entire inlining tree. - // The expense of doing this is that the PreserveJVMState class - // would have to preserve caller states too, with a deep copy. + if (!ReplaceInParentMaps) { + return; + } + + // PreserveJVMState doesn't do a deep copy so we can't modify + // parents + if (Compile::current()->has_preserve_jvm_state()) { + return; + } + + Parse* parser = is_Parse(); + bool progress = true; + Node* ctrl = map()->in(0); + // Follow the chain of parsers and see whether the update can be + // done in the map of callers. We can do the replace for a caller if + // the current control post dominates the control of a caller. + while (parser != NULL && parser->caller() != NULL && progress) { + progress = false; + Node* parent_map = parser->caller()->map(); + assert(parser->exits().map()->jvms()->depth() == parser->caller()->depth(), "map mismatch"); + + Node* parent_ctrl = parent_map->in(0); + + while (parent_ctrl->is_Region()) { + Node* n = parent_ctrl->as_Region()->is_copy(); + if (n == NULL) { + break; + } + parent_ctrl = n; + } + + for (;;) { + if (ctrl == parent_ctrl) { + // update the map of the exits which is the one that will be + // used when compilation resume after inlining + parser->exits().map()->replace_edge(old, neww); + progress = true; + break; + } + if (ctrl->is_Proj() && ctrl->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none)) { + ctrl = ctrl->in(0)->in(0); + } else if (ctrl->is_Region()) { + Node* n = ctrl->as_Region()->is_copy(); + if (n == NULL) { + break; + } + ctrl = n; + } else { + break; + } + } + + parser = parser->parent_parser(); + } } @@ -2043,6 +2098,104 @@ } } +/** + * Record profiling data exact_kls for Node n with the type system so + * that it can propagate it (speculation) + * + * @param n node that the type applies to + * @param exact_kls type from profiling + * + * @return node with improved type + */ +Node* GraphKit::record_profile_for_speculation(Node* n, ciKlass* exact_kls) { + const TypeOopPtr* current_type = _gvn.type(n)->isa_oopptr(); + assert(UseTypeSpeculation, "type speculation must be on"); + if (exact_kls != NULL && + // nothing to improve if type is already exact + (current_type == NULL || + (!current_type->klass_is_exact() && + (current_type->speculative() == NULL || + !current_type->speculative()->klass_is_exact())))) { + const TypeKlassPtr* tklass = TypeKlassPtr::make(exact_kls); + const TypeOopPtr* xtype = tklass->as_instance_type(); + assert(xtype->klass_is_exact(), "Should be exact"); + + // Build a type with a speculative type (what we think we know + // about the type but will need a guard when we use it) + const TypeOopPtr* spec_type = TypeOopPtr::make(TypePtr::BotPTR, Type::OffsetBot, TypeOopPtr::InstanceBot, xtype); + // We're changing the type, we need a new cast node to carry the + // new type. The new type depends on the control: what profiling + // tells us is only valid from here as far as we can tell. + Node* cast = new(C) CastPPNode(n, spec_type); + cast->init_req(0, control()); + cast = _gvn.transform(cast); + replace_in_map(n, cast); + n = cast; + } + return n; +} + +/** + * Record profiling data from receiver profiling at an invoke with the + * type system so that it can propagate it (speculation) + * + * @param n receiver node + * + * @return node with improved type + */ +Node* GraphKit::record_profiled_receiver_for_speculation(Node* n) { + if (!UseTypeSpeculation) { + return n; + } + ciKlass* exact_kls = profile_has_unique_klass(); + return record_profile_for_speculation(n, exact_kls); +} + +/** + * Record profiling data from argument profiling at an invoke with the + * type system so that it can propagate it (speculation) + * + * @param dest_method target method for the call + * @param bc what invoke bytecode is this? + */ +void GraphKit::record_profiled_arguments_for_speculation(ciMethod* dest_method, Bytecodes::Code bc) { + if (!UseTypeSpeculation) { + return; + } + const TypeFunc* tf = TypeFunc::make(dest_method); + int nargs = tf->_domain->_cnt - TypeFunc::Parms; + int skip = Bytecodes::has_receiver(bc) ? 1 : 0; + for (int j = skip, i = 0; j < nargs && i < TypeProfileArgsLimit; j++) { + const Type *targ = tf->_domain->field_at(j + TypeFunc::Parms); + if (targ->basic_type() == T_OBJECT || targ->basic_type() == T_ARRAY) { + ciKlass* better_type = method()->argument_profiled_type(bci(), i); + if (better_type != NULL) { + record_profile_for_speculation(argument(j), better_type); + } + i++; + } + } +} + +/** + * Record profiling data from parameter profiling at an invoke with + * the type system so that it can propagate it (speculation) + */ +void GraphKit::record_profiled_parameters_for_speculation() { + if (!UseTypeSpeculation) { + return; + } + for (int i = 0, j = 0; i < method()->arg_size() ; i++) { + if (_gvn.type(local(i))->isa_oopptr()) { + ciKlass* better_type = method()->parameter_profiled_type(j); + if (better_type != NULL) { + record_profile_for_speculation(local(i), better_type); + } + j++; + } + } +} + void GraphKit::round_double_result(ciMethod* dest_method) { // A non-strict method may return a double value which has an extended // exponent, but this must not be visible in a caller which is 'strict' @@ -2122,7 +2275,7 @@ // Null check oop. Set null-path control into Region in slot 3. // Make a cast-not-nullness use the other not-null control. Return cast. Node* GraphKit::null_check_oop(Node* value, Node* *null_control, - bool never_see_null) { + bool never_see_null, bool safe_for_replace) { // Initial NULL check taken path (*null_control) = top(); Node* cast = null_check_common(value, T_OBJECT, false, null_control); @@ -2140,6 +2293,9 @@ Deoptimization::Action_make_not_entrant); (*null_control) = top(); // NULL path is dead } + if ((*null_control) == top() && safe_for_replace) { + replace_in_map(value, cast); + } // Cast away null-ness on the result return cast; @@ -2577,10 +2733,10 @@ // If the profile has seen exactly one type, narrow to exactly that type. // Subsequent type checks will always fold up. Node* GraphKit::maybe_cast_profiled_receiver(Node* not_null_obj, - ciProfileData* data, - ciKlass* require_klass) { + ciKlass* require_klass, + ciKlass* spec_klass, + bool safe_for_replace) { if (!UseTypeProfile || !TypeProfileCasts) return NULL; - if (data == NULL) return NULL; // Make sure we haven't already deoptimized from this tactic. if (too_many_traps(Deoptimization::Reason_class_check)) @@ -2588,15 +2744,15 @@ // (No, this isn't a call, but it's enough like a virtual call // to use the same ciMethod accessor to get the profile info...) - ciCallProfile profile = method()->call_profile_at_bci(bci()); - if (profile.count() >= 0 && // no cast failures here - profile.has_receiver(0) && - profile.morphism() == 1) { - ciKlass* exact_kls = profile.receiver(0); + // If we have a speculative type use it instead of profiling (which + // may not help us) + ciKlass* exact_kls = spec_klass == NULL ? profile_has_unique_klass() : spec_klass; + if (exact_kls != NULL) {// no cast failures here if (require_klass == NULL || static_subtype_check(require_klass, exact_kls) == SSC_always_true) { - // If we narrow the type to match what the type profile sees, - // we can then remove the rest of the cast. + // If we narrow the type to match what the type profile sees or + // the speculative type, we can then remove the rest of the + // cast. // This is a win, even if the exact_kls is very specific, // because downstream operations, such as method calls, // will often benefit from the sharper type. @@ -2608,7 +2764,9 @@ uncommon_trap(Deoptimization::Reason_class_check, Deoptimization::Action_maybe_recompile); } - replace_in_map(not_null_obj, exact_obj); + if (safe_for_replace) { + replace_in_map(not_null_obj, exact_obj); + } return exact_obj; } // assert(ssc == SSC_always_true)... except maybe the profile lied to us. @@ -2617,11 +2775,59 @@ return NULL; } +/** + * Cast obj to type and emit guard unless we had too many traps here + * already + * + * @param obj node being casted + * @param type type to cast the node to + * @param not_null true if we know node cannot be null + */ +Node* GraphKit::maybe_cast_profiled_obj(Node* obj, + ciKlass* type, + bool not_null) { + // type == NULL if profiling tells us this object is always null + if (type != NULL) { + if (!too_many_traps(Deoptimization::Reason_null_check) && + !too_many_traps(Deoptimization::Reason_class_check)) { + Node* not_null_obj = NULL; + // not_null is true if we know the object is not null and + // there's no need for a null check + if (!not_null) { + Node* null_ctl = top(); + not_null_obj = null_check_oop(obj, &null_ctl, true, true); + assert(null_ctl->is_top(), "no null control here"); + } else { + not_null_obj = obj; + } + + Node* exact_obj = not_null_obj; + ciKlass* exact_kls = type; + Node* slow_ctl = type_check_receiver(exact_obj, exact_kls, 1.0, + &exact_obj); + { + PreserveJVMState pjvms(this); + set_control(slow_ctl); + uncommon_trap(Deoptimization::Reason_class_check, + Deoptimization::Action_maybe_recompile); + } + replace_in_map(not_null_obj, exact_obj); + obj = exact_obj; + } + } else { + if (!too_many_traps(Deoptimization::Reason_null_assert)) { + Node* exact_obj = null_assert(obj); + replace_in_map(obj, exact_obj); + obj = exact_obj; + } + } + return obj; +} //-------------------------------gen_instanceof-------------------------------- // Generate an instance-of idiom. Used by both the instance-of bytecode // and the reflective instance-of call. -Node* GraphKit::gen_instanceof(Node* obj, Node* superklass) { +Node* GraphKit::gen_instanceof(Node* obj, Node* superklass, bool safe_for_replace) { kill_dead_locals(); // Benefit all the uncommon traps assert( !stopped(), "dead parse path should be checked in callers" ); assert(!TypePtr::NULL_PTR->higher_equal(_gvn.type(superklass)->is_klassptr()), @@ -2642,7 +2848,7 @@ // Null check; get casted pointer; set region slot 3 Node* null_ctl = top(); - Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null); + Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace); // If not_null_obj is dead, only null-path is taken if (stopped()) { // Doing instance-of on a NULL? @@ -2659,14 +2865,37 @@ phi ->del_req(_null_path); } - if (ProfileDynamicTypes && data != NULL) { - Node* cast_obj = maybe_cast_profiled_receiver(not_null_obj, data, NULL); - if (stopped()) { // Profile disagrees with this path. - set_control(null_ctl); // Null is the only remaining possibility. - return intcon(0); + // Do we know the type check always succeed? + bool known_statically = false; + if (_gvn.type(superklass)->singleton()) { + ciKlass* superk = _gvn.type(superklass)->is_klassptr()->klass(); + ciKlass* subk = _gvn.type(obj)->is_oopptr()->klass(); + if (subk != NULL && subk->is_loaded()) { + int static_res = static_subtype_check(superk, subk); + known_statically = (static_res == SSC_always_true || static_res == SSC_always_false); } - if (cast_obj != NULL) - not_null_obj = cast_obj; + } + + if (known_statically && UseTypeSpeculation) { + // If we know the type check always succeed then we don't use the + // profiling data at this bytecode. Don't lose it, feed it to the + // type system as a speculative type. + not_null_obj = record_profiled_receiver_for_speculation(not_null_obj); + } else { + const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr(); + // We may not have profiling here or it may not help us. If we + // have a speculative type use it to perform an exact cast. + ciKlass* spec_obj_type = obj_type->speculative_type(); + if (spec_obj_type != NULL || (ProfileDynamicTypes && data != NULL)) { + Node* cast_obj = maybe_cast_profiled_receiver(not_null_obj, NULL, spec_obj_type, safe_for_replace); + if (stopped()) { // Profile disagrees with this path. + set_control(null_ctl); // Null is the only remaining possibility. + return intcon(0); + } + if (cast_obj != NULL) { + not_null_obj = cast_obj; + } + } } // Load the object's klass @@ -2713,7 +2942,10 @@ if (objtp != NULL && objtp->klass() != NULL) { switch (static_subtype_check(tk->klass(), objtp->klass())) { case SSC_always_true: - return obj; + // If we know the type check always succeed then we don't use + // the profiling data at this bytecode. Don't lose it, feed it + // to the type system as a speculative type. + return record_profiled_receiver_for_speculation(obj); case SSC_always_false: // It needs a null check because a null will *pass* the cast check. // A non-null value will always produce an exception. @@ -2723,11 +2955,13 @@ } ciProfileData* data = NULL; + bool safe_for_replace = false; if (failure_control == NULL) { // use MDO in regular case only assert(java_bc() == Bytecodes::_aastore || java_bc() == Bytecodes::_checkcast, "interpreter profiles type checks only for these BCs"); data = method()->method_data()->bci_to_data(bci()); + safe_for_replace = true; } // Make the merge point @@ -2742,7 +2976,7 @@ // Null check; get casted pointer; set region slot 3 Node* null_ctl = top(); - Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null); + Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace); // If not_null_obj is dead, only null-path is taken if (stopped()) { // Doing instance-of on a NULL? @@ -2760,12 +2994,17 @@ } Node* cast_obj = NULL; - if (data != NULL && - // Counter has never been decremented (due to cast failure). - // ...This is a reasonable thing to expect. It is true of - // all casts inserted by javac to implement generic types. - data->as_CounterData()->count() >= 0) { - cast_obj = maybe_cast_profiled_receiver(not_null_obj, data, tk->klass()); + const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr(); + // We may not have profiling here or it may not help us. If we have + // a speculative type use it to perform an exact cast. + ciKlass* spec_obj_type = obj_type->speculative_type(); + if (spec_obj_type != NULL || + (data != NULL && + // Counter has never been decremented (due to cast failure). + // ...This is a reasonable thing to expect. It is true of + // all casts inserted by javac to implement generic types. + data->as_CounterData()->count() >= 0)) { + cast_obj = maybe_cast_profiled_receiver(not_null_obj, tk->klass(), spec_obj_type, safe_for_replace); if (cast_obj != NULL) { if (failure_control != NULL) // failure is now impossible (*failure_control) = top(); @@ -3608,7 +3847,7 @@ Node* marking = __ load(__ ctrl(), marking_adr, TypeInt::INT, active_type, Compile::AliasIdxRaw); // if (!marking) - __ if_then(marking, BoolTest::ne, zero); { + __ if_then(marking, BoolTest::ne, zero, unlikely); { BasicType index_bt = TypeX_X->basic_type(); assert(sizeof(size_t) == type2aelembytes(index_bt), "Loading G1 PtrQueue::_index with wrong size."); Node* index = __ load(__ ctrl(), index_adr, TypeX_X, index_bt, Compile::AliasIdxRaw); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/graphKit.hpp --- a/src/share/vm/opto/graphKit.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/graphKit.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -378,16 +378,41 @@ // Return a cast-not-null node which depends on the not-null control. // If never_see_null, use an uncommon trap (*null_control sees a top). // The cast is not valid along the null path; keep a copy of the original. + // If safe_for_replace, then we can replace the value with the cast + // in the parsing map (the cast is guaranteed to dominate the map) Node* null_check_oop(Node* value, Node* *null_control, - bool never_see_null = false); + bool never_see_null = false, bool safe_for_replace = false); // Check the null_seen bit. bool seems_never_null(Node* obj, ciProfileData* data); + // Check for unique class for receiver at call + ciKlass* profile_has_unique_klass() { + ciCallProfile profile = method()->call_profile_at_bci(bci()); + if (profile.count() >= 0 && // no cast failures here + profile.has_receiver(0) && + profile.morphism() == 1) { + return profile.receiver(0); + } + return NULL; + } + + // record type from profiling with the type system + Node* record_profile_for_speculation(Node* n, ciKlass* exact_kls); + Node* record_profiled_receiver_for_speculation(Node* n); + void record_profiled_arguments_for_speculation(ciMethod* dest_method, Bytecodes::Code bc); + void record_profiled_parameters_for_speculation(); + // Use the type profile to narrow an object type. Node* maybe_cast_profiled_receiver(Node* not_null_obj, - ciProfileData* data, - ciKlass* require_klass); + ciKlass* require_klass, + ciKlass* spec, + bool safe_for_replace); + + // Cast obj to type and emit guard unless we had too many traps here already + Node* maybe_cast_profiled_obj(Node* obj, + ciKlass* type, + bool not_null = false); // Cast obj to not-null on this path Node* cast_not_null(Node* obj, bool do_replace_in_map = true); @@ -773,7 +798,7 @@ // Generate an instance-of idiom. Used by both the instance-of bytecode // and the reflective instance-of call. - Node* gen_instanceof( Node *subobj, Node* superkls ); + Node* gen_instanceof(Node *subobj, Node* superkls, bool safe_for_replace = false); // Generate a check-cast idiom. Used by both the check-cast bytecode // and the array-store bytecode diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/idealGraphPrinter.cpp --- a/src/share/vm/opto/idealGraphPrinter.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/idealGraphPrinter.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -616,7 +616,11 @@ buffer[0] = 0; _chaitin->dump_register(node, buffer); print_prop("reg", buffer); - print_prop("lrg", _chaitin->_lrg_map.live_range_id(node)); + uint lrg_id = 0; + if (node->_idx < _chaitin->_lrg_map.size()) { + lrg_id = _chaitin->_lrg_map.live_range_id(node); + } + print_prop("lrg", lrg_id); } node->_in_dump_cnt--; diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/ifg.cpp --- a/src/share/vm/opto/ifg.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/ifg.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -677,7 +677,7 @@ } else { // Common case: size 1 bound removal if( lrg.mask().Member(r_reg) ) { lrg.Remove(r_reg); - lrg.set_mask_size(lrg.mask().is_AllStack() ? 65535:old_size-1); + lrg.set_mask_size(lrg.mask().is_AllStack() ? LRG::AllStack_size : old_size - 1); } } // If 'l' goes completely dry, it must spill. diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/ifnode.cpp --- a/src/share/vm/opto/ifnode.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/ifnode.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -689,6 +689,7 @@ ctrl->in(0)->in(1)->is_Bool() && ctrl->in(0)->in(1)->in(1)->Opcode() == Op_CmpI && ctrl->in(0)->in(1)->in(1)->in(2)->is_Con() && + ctrl->in(0)->in(1)->in(1)->in(2) != phase->C->top() && ctrl->in(0)->in(1)->in(1)->in(1) == n) { IfNode* dom_iff = ctrl->in(0)->as_If(); Node* otherproj = dom_iff->proj_out(!ctrl->as_Proj()->_con); @@ -1018,7 +1019,7 @@ // be skipped. For example, range check predicate has two checks // for lower and upper bounds. ProjNode* unc_proj = proj_out(1 - prev_dom->as_Proj()->_con)->as_Proj(); - if (PhaseIdealLoop::is_uncommon_trap_proj(unc_proj, Deoptimization::Reason_predicate)) + if (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate)) prev_dom = idom; // Now walk the current IfNode's projections. diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/library_call.cpp --- a/src/share/vm/opto/library_call.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/library_call.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -63,7 +63,7 @@ virtual bool is_virtual() const { return _is_virtual; } virtual bool is_predicted() const { return _is_predicted; } virtual bool does_virtual_dispatch() const { return _does_virtual_dispatch; } - virtual JVMState* generate(JVMState* jvms); + virtual JVMState* generate(JVMState* jvms, Parse* parent_parser); virtual Node* generate_predicate(JVMState* jvms); vmIntrinsics::ID intrinsic_id() const { return _intrinsic_id; } }; @@ -203,8 +203,15 @@ bool inline_math_native(vmIntrinsics::ID id); bool inline_trig(vmIntrinsics::ID id); bool inline_math(vmIntrinsics::ID id); - bool inline_math_mathExact(Node* math); - bool inline_math_addExact(); + void inline_math_mathExact(Node* math); + bool inline_math_addExactI(bool is_increment); + bool inline_math_addExactL(bool is_increment); + bool inline_math_multiplyExactI(); + bool inline_math_multiplyExactL(); + bool inline_math_negateExactI(); + bool inline_math_negateExactL(); + bool inline_math_subtractExactI(bool is_decrement); + bool inline_math_subtractExactL(bool is_decrement); bool inline_exp(); bool inline_pow(); void finish_pow_exp(Node* result, Node* x, Node* y, const TypeFunc* call_type, address funcAddr, const char* funcName); @@ -507,13 +514,33 @@ if (!UseCRC32Intrinsics) return NULL; break; - case vmIntrinsics::_addExact: - if (!Matcher::match_rule_supported(Op_AddExactI)) { - return NULL; - } - if (!UseMathExactIntrinsics) { - return NULL; - } + case vmIntrinsics::_incrementExactI: + case vmIntrinsics::_addExactI: + if (!Matcher::match_rule_supported(Op_AddExactI) || !UseMathExactIntrinsics) return NULL; + break; + case vmIntrinsics::_incrementExactL: + case vmIntrinsics::_addExactL: + if (!Matcher::match_rule_supported(Op_AddExactL) || !UseMathExactIntrinsics) return NULL; + break; + case vmIntrinsics::_decrementExactI: + case vmIntrinsics::_subtractExactI: + if (!Matcher::match_rule_supported(Op_SubExactI) || !UseMathExactIntrinsics) return NULL; + break; + case vmIntrinsics::_decrementExactL: + case vmIntrinsics::_subtractExactL: + if (!Matcher::match_rule_supported(Op_SubExactL) || !UseMathExactIntrinsics) return NULL; + break; + case vmIntrinsics::_negateExactI: + if (!Matcher::match_rule_supported(Op_NegExactI) || !UseMathExactIntrinsics) return NULL; + break; + case vmIntrinsics::_negateExactL: + if (!Matcher::match_rule_supported(Op_NegExactL) || !UseMathExactIntrinsics) return NULL; + break; + case vmIntrinsics::_multiplyExactI: + if (!Matcher::match_rule_supported(Op_MulExactI) || !UseMathExactIntrinsics) return NULL; + break; + case vmIntrinsics::_multiplyExactL: + if (!Matcher::match_rule_supported(Op_MulExactL) || !UseMathExactIntrinsics) return NULL; break; default: @@ -556,7 +583,7 @@ // Nothing to do here. } -JVMState* LibraryIntrinsic::generate(JVMState* jvms) { +JVMState* LibraryIntrinsic::generate(JVMState* jvms, Parse* parent_parser) { LibraryCallKit kit(jvms, this); Compile* C = kit.C; int nodes = C->unique(); @@ -686,7 +713,18 @@ case vmIntrinsics::_min: case vmIntrinsics::_max: return inline_min_max(intrinsic_id()); - case vmIntrinsics::_addExact: return inline_math_addExact(); + case vmIntrinsics::_addExactI: return inline_math_addExactI(false /* add */); + case vmIntrinsics::_addExactL: return inline_math_addExactL(false /* add */); + case vmIntrinsics::_decrementExactI: return inline_math_subtractExactI(true /* decrement */); + case vmIntrinsics::_decrementExactL: return inline_math_subtractExactL(true /* decrement */); + case vmIntrinsics::_incrementExactI: return inline_math_addExactI(true /* increment */); + case vmIntrinsics::_incrementExactL: return inline_math_addExactL(true /* increment */); + case vmIntrinsics::_multiplyExactI: return inline_math_multiplyExactI(); + case vmIntrinsics::_multiplyExactL: return inline_math_multiplyExactL(); + case vmIntrinsics::_negateExactI: return inline_math_negateExactI(); + case vmIntrinsics::_negateExactL: return inline_math_negateExactL(); + case vmIntrinsics::_subtractExactI: return inline_math_subtractExactI(false /* subtract */); + case vmIntrinsics::_subtractExactL: return inline_math_subtractExactL(false /* subtract */); case vmIntrinsics::_arraycopy: return inline_arraycopy(); @@ -1931,7 +1969,14 @@ return true; } -bool LibraryCallKit::inline_math_mathExact(Node* math) { +void LibraryCallKit::inline_math_mathExact(Node* math) { + // If we didn't get the expected opcode it means we have optimized + // the node to something else and don't need the exception edge. + if (!math->is_MathExact()) { + set_result(math); + return; + } + Node* result = _gvn.transform( new(C) ProjNode(math, MathExactNode::result_proj_node)); Node* flags = _gvn.transform( new(C) FlagsProjNode(math, MathExactNode::flags_proj_node)); @@ -1954,19 +1999,106 @@ set_control(fast_path); set_result(result); +} + +bool LibraryCallKit::inline_math_addExactI(bool is_increment) { + Node* arg1 = argument(0); + Node* arg2 = NULL; + + if (is_increment) { + arg2 = intcon(1); + } else { + arg2 = argument(1); + } + + Node* add = _gvn.transform( new(C) AddExactINode(NULL, arg1, arg2) ); + inline_math_mathExact(add); + return true; +} + +bool LibraryCallKit::inline_math_addExactL(bool is_increment) { + Node* arg1 = argument(0); // type long + // argument(1) == TOP + Node* arg2 = NULL; + + if (is_increment) { + arg2 = longcon(1); + } else { + arg2 = argument(2); // type long + // argument(3) == TOP + } + + Node* add = _gvn.transform(new(C) AddExactLNode(NULL, arg1, arg2)); + inline_math_mathExact(add); return true; } -bool LibraryCallKit::inline_math_addExact() { +bool LibraryCallKit::inline_math_subtractExactI(bool is_decrement) { + Node* arg1 = argument(0); + Node* arg2 = NULL; + + if (is_decrement) { + arg2 = intcon(1); + } else { + arg2 = argument(1); + } + + Node* sub = _gvn.transform(new(C) SubExactINode(NULL, arg1, arg2)); + inline_math_mathExact(sub); + return true; +} + +bool LibraryCallKit::inline_math_subtractExactL(bool is_decrement) { + Node* arg1 = argument(0); // type long + // argument(1) == TOP + Node* arg2 = NULL; + + if (is_decrement) { + arg2 = longcon(1); + } else { + Node* arg2 = argument(2); // type long + // argument(3) == TOP + } + + Node* sub = _gvn.transform(new(C) SubExactLNode(NULL, arg1, arg2)); + inline_math_mathExact(sub); + return true; +} + +bool LibraryCallKit::inline_math_negateExactI() { + Node* arg1 = argument(0); + + Node* neg = _gvn.transform(new(C) NegExactINode(NULL, arg1)); + inline_math_mathExact(neg); + return true; +} + +bool LibraryCallKit::inline_math_negateExactL() { + Node* arg1 = argument(0); + // argument(1) == TOP + + Node* neg = _gvn.transform(new(C) NegExactLNode(NULL, arg1)); + inline_math_mathExact(neg); + return true; +} + +bool LibraryCallKit::inline_math_multiplyExactI() { Node* arg1 = argument(0); Node* arg2 = argument(1); - Node* add = _gvn.transform( new(C) AddExactINode(NULL, arg1, arg2) ); - if (add->Opcode() == Op_AddExactI) { - return inline_math_mathExact(add); - } else { - set_result(add); - } + Node* mul = _gvn.transform(new(C) MulExactINode(NULL, arg1, arg2)); + inline_math_mathExact(mul); + return true; +} + +bool LibraryCallKit::inline_math_multiplyExactL() { + Node* arg1 = argument(0); + // argument(1) == TOP + Node* arg2 = argument(2); + // argument(3) == TOP + + Node* mul = _gvn.transform(new(C) MulExactLNode(NULL, arg1, arg2)); + inline_math_mathExact(mul); return true; } @@ -3353,6 +3485,7 @@ // If kls is null, we have a primitive mirror. phi->init_req(_prim_path, prim_return_value); if (stopped()) { set_result(region, phi); return true; } + bool safe_for_replace = (region->in(_prim_path) == top()); Node* p; // handy temp Node* null_ctl; @@ -3363,7 +3496,7 @@ switch (id) { case vmIntrinsics::_isInstance: // nothing is an instance of a primitive type - query_value = gen_instanceof(obj, kls); + query_value = gen_instanceof(obj, kls, safe_for_replace); break; case vmIntrinsics::_getModifiers: @@ -4553,8 +4686,62 @@ const Type* dest_type = dest->Value(&_gvn); const TypeAryPtr* top_src = src_type->isa_aryptr(); const TypeAryPtr* top_dest = dest_type->isa_aryptr(); - if (top_src == NULL || top_src->klass() == NULL || - top_dest == NULL || top_dest->klass() == NULL) { + + // Do we have the type of src? + bool has_src = (top_src != NULL && top_src->klass() != NULL); + // Do we have the type of dest? + bool has_dest = (top_dest != NULL && top_dest->klass() != NULL); + // Is the type for src from speculation? + bool src_spec = false; + // Is the type for dest from speculation? + bool dest_spec = false; + + if (!has_src || !has_dest) { + // We don't have sufficient type information, let's see if + // speculative types can help. We need to have types for both src + // and dest so that it pays off. + + // Do we already have or could we have type information for src + bool could_have_src = has_src; + // Do we already have or could we have type information for dest + bool could_have_dest = has_dest; + + ciKlass* src_k = NULL; + if (!has_src) { + src_k = src_type->speculative_type(); + if (src_k != NULL && src_k->is_array_klass()) { + could_have_src = true; + } + } + + ciKlass* dest_k = NULL; + if (!has_dest) { + dest_k = dest_type->speculative_type(); + if (dest_k != NULL && dest_k->is_array_klass()) { + could_have_dest = true; + } + } + + if (could_have_src && could_have_dest) { + // This is going to pay off so emit the required guards + if (!has_src) { + src = maybe_cast_profiled_obj(src, src_k); + src_type = _gvn.type(src); + top_src = src_type->isa_aryptr(); + has_src = (top_src != NULL && top_src->klass() != NULL); + src_spec = true; + } + if (!has_dest) { + dest = maybe_cast_profiled_obj(dest, dest_k); + dest_type = _gvn.type(dest); + top_dest = dest_type->isa_aryptr(); + has_dest = (top_dest != NULL && top_dest->klass() != NULL); + dest_spec = true; + } + } + } + + if (!has_src || !has_dest) { // Conservatively insert a memory barrier on all memory slices. // Do not let writes into the source float below the arraycopy. insert_mem_bar(Op_MemBarCPUOrder); @@ -4589,6 +4776,40 @@ return true; } + if (src_elem == T_OBJECT) { + // If both arrays are object arrays then having the exact types + // for both will remove the need for a subtype check at runtime + // before the call and may make it possible to pick a faster copy + // routine (without a subtype check on every element) + // Do we have the exact type of src? + bool could_have_src = src_spec; + // Do we have the exact type of dest? + bool could_have_dest = dest_spec; + ciKlass* src_k = top_src->klass(); + ciKlass* dest_k = top_dest->klass(); + if (!src_spec) { + src_k = src_type->speculative_type(); + if (src_k != NULL && src_k->is_array_klass()) { + could_have_src = true; + } + } + if (!dest_spec) { + dest_k = dest_type->speculative_type(); + if (dest_k != NULL && dest_k->is_array_klass()) { + could_have_dest = true; + } + } + if (could_have_src && could_have_dest) { + // If we can have both exact types, emit the missing guards + if (could_have_src && !src_spec) { + src = maybe_cast_profiled_obj(src, src_k); + } + if (could_have_dest && !dest_spec) { + dest = maybe_cast_profiled_obj(dest, dest_k); + } + } + } + //--------------------------------------------------------------------------- // We will make a fast path for this call to arraycopy. diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/loopPredicate.cpp --- a/src/share/vm/opto/loopPredicate.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/loopPredicate.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -41,63 +41,6 @@ * checks (such as null checks). */ -//-------------------------------is_uncommon_trap_proj---------------------------- -// Return true if proj is the form of "proj->[region->..]call_uct" -bool PhaseIdealLoop::is_uncommon_trap_proj(ProjNode* proj, Deoptimization::DeoptReason reason) { - int path_limit = 10; - assert(proj, "invalid argument"); - Node* out = proj; - for (int ct = 0; ct < path_limit; ct++) { - out = out->unique_ctrl_out(); - if (out == NULL) - return false; - if (out->is_CallStaticJava()) { - int req = out->as_CallStaticJava()->uncommon_trap_request(); - if (req != 0) { - Deoptimization::DeoptReason trap_reason = Deoptimization::trap_request_reason(req); - if (trap_reason == reason || reason == Deoptimization::Reason_none) { - return true; - } - } - return false; // don't do further after call - } - if (out->Opcode() != Op_Region) - return false; - } - return false; -} - -//-------------------------------is_uncommon_trap_if_pattern------------------------- -// Return true for "if(test)-> proj -> ... -// | -// V -// other_proj->[region->..]call_uct" -// -// "must_reason_predicate" means the uct reason must be Reason_predicate -bool PhaseIdealLoop::is_uncommon_trap_if_pattern(ProjNode *proj, Deoptimization::DeoptReason reason) { - Node *in0 = proj->in(0); - if (!in0->is_If()) return false; - // Variation of a dead If node. - if (in0->outcnt() < 2) return false; - IfNode* iff = in0->as_If(); - - // we need "If(Conv2B(Opaque1(...)))" pattern for reason_predicate - if (reason != Deoptimization::Reason_none) { - if (iff->in(1)->Opcode() != Op_Conv2B || - iff->in(1)->in(1)->Opcode() != Op_Opaque1) { - return false; - } - } - - ProjNode* other_proj = iff->proj_out(1-proj->_con)->as_Proj(); - if (is_uncommon_trap_proj(other_proj, reason)) { - assert(reason == Deoptimization::Reason_none || - Compile::current()->is_predicate_opaq(iff->in(1)->in(1)), "should be on the list"); - return true; - } - return false; -} - //-------------------------------register_control------------------------- void PhaseIdealLoop::register_control(Node* n, IdealLoopTree *loop, Node* pred) { assert(n->is_CFG(), "must be control node"); @@ -147,7 +90,7 @@ // This code is also used to clone predicates to clonned loops. ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry, Deoptimization::DeoptReason reason) { - assert(is_uncommon_trap_if_pattern(cont_proj, reason), "must be a uct if pattern!"); + assert(cont_proj->is_uncommon_trap_if_pattern(reason), "must be a uct if pattern!"); IfNode* iff = cont_proj->in(0)->as_If(); ProjNode *uncommon_proj = iff->proj_out(1 - cont_proj->_con); @@ -235,7 +178,7 @@ ProjNode* PhaseIterGVN::create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry, Deoptimization::DeoptReason reason) { assert(new_entry != 0, "only used for clone predicate"); - assert(PhaseIdealLoop::is_uncommon_trap_if_pattern(cont_proj, reason), "must be a uct if pattern!"); + assert(cont_proj->is_uncommon_trap_if_pattern(reason), "must be a uct if pattern!"); IfNode* iff = cont_proj->in(0)->as_If(); ProjNode *uncommon_proj = iff->proj_out(1 - cont_proj->_con); @@ -422,7 +365,7 @@ ProjNode* PhaseIdealLoop::find_predicate_insertion_point(Node* start_c, Deoptimization::DeoptReason reason) { if (start_c == NULL || !start_c->is_Proj()) return NULL; - if (is_uncommon_trap_if_pattern(start_c->as_Proj(), reason)) { + if (start_c->as_Proj()->is_uncommon_trap_if_pattern(reason)) { return start_c->as_Proj(); } return NULL; @@ -773,7 +716,7 @@ ProjNode* proj = if_proj_list.pop()->as_Proj(); IfNode* iff = proj->in(0)->as_If(); - if (!is_uncommon_trap_if_pattern(proj, Deoptimization::Reason_none)) { + if (!proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none)) { if (loop->is_loop_exit(iff)) { // stop processing the remaining projs in the list because the execution of them // depends on the condition of "iff" (iff->in(1)). diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/loopnode.cpp --- a/src/share/vm/opto/loopnode.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/loopnode.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -167,7 +167,7 @@ // expensive nodes will notice the loop and skip over it to try to // move the node further up. if (ctl->is_CountedLoop() && ctl->in(1) != NULL && ctl->in(1)->in(0) != NULL && ctl->in(1)->in(0)->is_If()) { - if (!is_uncommon_trap_if_pattern(ctl->in(1)->as_Proj(), Deoptimization::Reason_none)) { + if (!ctl->in(1)->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none)) { break; } next = idom(ctl->in(1)->in(0)); @@ -181,7 +181,7 @@ } else if (parent_ctl->is_CountedLoopEnd() && parent_ctl->as_CountedLoopEnd()->loopnode() != NULL) { next = parent_ctl->as_CountedLoopEnd()->loopnode()->init_control(); } else if (parent_ctl->is_If()) { - if (!is_uncommon_trap_if_pattern(ctl->as_Proj(), Deoptimization::Reason_none)) { + if (!ctl->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none)) { break; } assert(idom(ctl) == parent_ctl, "strange"); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/loopnode.hpp --- a/src/share/vm/opto/loopnode.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/loopnode.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -876,13 +876,6 @@ // Return true if exp is a scaled induction var plus (or minus) constant bool is_scaled_iv_plus_offset(Node* exp, Node* iv, int* p_scale, Node** p_offset, int depth = 0); - // Return true if proj is for "proj->[region->..]call_uct" - static bool is_uncommon_trap_proj(ProjNode* proj, Deoptimization::DeoptReason reason); - // Return true for "if(test)-> proj -> ... - // | - // V - // other_proj->[region->..]call_uct" - static bool is_uncommon_trap_if_pattern(ProjNode* proj, Deoptimization::DeoptReason reason); // Create a new if above the uncommon_trap_if_pattern for the predicate to be promoted ProjNode* create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry, Deoptimization::DeoptReason reason); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/loopopts.cpp --- a/src/share/vm/opto/loopopts.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/loopopts.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -238,7 +238,7 @@ ProjNode* dp_proj = dp->as_Proj(); ProjNode* unc_proj = iff->as_If()->proj_out(1 - dp_proj->_con)->as_Proj(); if (exclude_loop_predicate && - is_uncommon_trap_proj(unc_proj, Deoptimization::Reason_predicate)) + unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate)) return; // Let IGVN transformation change control dependence. IdealLoopTree *old_loop = get_loop(dp); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/matcher.hpp --- a/src/share/vm/opto/matcher.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/matcher.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -338,6 +338,7 @@ static RegMask modL_proj_mask(); static const RegMask mathExactI_result_proj_mask(); + static const RegMask mathExactL_result_proj_mask(); static const RegMask mathExactI_flags_proj_mask(); // Use hardware DIV instruction when it is faster than diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/mathexactnode.cpp --- a/src/share/vm/opto/mathexactnode.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/mathexactnode.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -25,18 +25,86 @@ #include "precompiled.hpp" #include "memory/allocation.inline.hpp" #include "opto/addnode.hpp" +#include "opto/cfgnode.hpp" #include "opto/machnode.hpp" +#include "opto/matcher.hpp" #include "opto/mathexactnode.hpp" -#include "opto/matcher.hpp" #include "opto/subnode.hpp" -MathExactNode::MathExactNode(Node* ctrl, Node* n1, Node* n2) : MultiNode(3) { +MathExactNode::MathExactNode(Node* ctrl, Node* in1) : MultiNode(2) { + init_class_id(Class_MathExact); + init_req(0, ctrl); + init_req(1, in1); +} + +MathExactNode::MathExactNode(Node* ctrl, Node* in1, Node* in2) : MultiNode(3) { + init_class_id(Class_MathExact); init_req(0, ctrl); - init_req(1, n1); - init_req(2, n2); + init_req(1, in1); + init_req(2, in2); +} + +BoolNode* MathExactNode::bool_node() const { + Node* flags = flags_node(); + BoolNode* boolnode = flags->unique_out()->as_Bool(); + assert(boolnode != NULL, "must have BoolNode"); + return boolnode; +} + +IfNode* MathExactNode::if_node() const { + BoolNode* boolnode = bool_node(); + IfNode* ifnode = boolnode->unique_out()->as_If(); + assert(ifnode != NULL, "must have IfNode"); + return ifnode; +} + +Node* MathExactNode::control_node() const { + IfNode* ifnode = if_node(); + return ifnode->in(0); } -Node* AddExactINode::match(const ProjNode* proj, const Matcher* m) { +Node* MathExactNode::non_throwing_branch() const { + IfNode* ifnode = if_node(); + if (bool_node()->_test._test == BoolTest::overflow) { + return ifnode->proj_out(0); + } + return ifnode->proj_out(1); +} + +// If the MathExactNode won't overflow we have to replace the +// FlagsProjNode and ProjNode that is generated by the MathExactNode +Node* MathExactNode::no_overflow(PhaseGVN* phase, Node* new_result) { + PhaseIterGVN* igvn = phase->is_IterGVN(); + if (igvn) { + ProjNode* result = result_node(); + ProjNode* flags = flags_node(); + + if (result != NULL) { + igvn->replace_node(result, new_result); + } + + if (flags != NULL) { + BoolNode* boolnode = bool_node(); + switch (boolnode->_test._test) { + case BoolTest::overflow: + // if the check is for overflow - never taken + igvn->replace_node(boolnode, phase->intcon(0)); + break; + case BoolTest::no_overflow: + // if the check is for no overflow - always taken + igvn->replace_node(boolnode, phase->intcon(1)); + break; + default: + fatal("Unexpected value of BoolTest"); + break; + } + flags->del_req(0); + } + } + return new_result; +} + +Node* MathExactINode::match(const ProjNode* proj, const Matcher* m) { uint ideal_reg = proj->ideal_reg(); RegMask rm; if (proj->_con == result_proj_node) { @@ -49,42 +117,22 @@ return new (m->C) MachProjNode(this, proj->_con, rm, ideal_reg); } -// If the MathExactNode won't overflow we have to replace the -// FlagsProjNode and ProjNode that is generated by the MathExactNode -Node* MathExactNode::no_overflow(PhaseGVN *phase, Node* new_result) { - PhaseIterGVN *igvn = phase->is_IterGVN(); - if (igvn) { - ProjNode* result = result_node(); - ProjNode* flags = flags_node(); - - if (result != NULL) { - igvn->replace_node(result, new_result); - } - - if (flags != NULL) { - BoolNode* bolnode = (BoolNode *) flags->unique_out(); - switch (bolnode->_test._test) { - case BoolTest::overflow: - // if the check is for overflow - never taken - igvn->replace_node(bolnode, phase->intcon(0)); - break; - case BoolTest::no_overflow: - // if the check is for no overflow - always taken - igvn->replace_node(bolnode, phase->intcon(1)); - break; - default: - fatal("Unexpected value of BoolTest"); - break; - } - flags->del_req(0); - } +Node* MathExactLNode::match(const ProjNode* proj, const Matcher* m) { + uint ideal_reg = proj->ideal_reg(); + RegMask rm; + if (proj->_con == result_proj_node) { + rm = m->mathExactL_result_proj_mask(); + } else { + assert(proj->_con == flags_proj_node, "must be result or flags"); + assert(ideal_reg == Op_RegFlags, "sanity"); + rm = m->mathExactI_flags_proj_mask(); } - return new_result; + return new (m->C) MachProjNode(this, proj->_con, rm, ideal_reg); } -Node *AddExactINode::Ideal(PhaseGVN *phase, bool can_reshape) { - Node *arg1 = in(1); - Node *arg2 = in(2); +Node* AddExactINode::Ideal(PhaseGVN* phase, bool can_reshape) { + Node* arg1 = in(1); + Node* arg2 = in(2); const Type* type1 = phase->type(arg1); const Type* type2 = phase->type(arg2); @@ -102,12 +150,7 @@ return NULL; } - if (type1 == TypeInt::ZERO) { // (Add 0 x) == x - Node* add_result = new (phase->C) AddINode(arg1, arg2); - return no_overflow(phase, add_result); - } - - if (type2 == TypeInt::ZERO) { // (Add x 0) == x + if (type1 == TypeInt::ZERO || type2 == TypeInt::ZERO) { // (Add 0 x) == x Node* add_result = new (phase->C) AddINode(arg1, arg2); return no_overflow(phase, add_result); } @@ -141,3 +184,247 @@ return NULL; } +Node* AddExactLNode::Ideal(PhaseGVN* phase, bool can_reshape) { + Node* arg1 = in(1); + Node* arg2 = in(2); + + const Type* type1 = phase->type(arg1); + const Type* type2 = phase->type(arg2); + + if (type1 != Type::TOP && type1->singleton() && + type2 != Type::TOP && type2->singleton()) { + jlong val1 = arg1->get_long(); + jlong val2 = arg2->get_long(); + jlong result = val1 + val2; + // Hacker's Delight 2-12 Overflow if both arguments have the opposite sign of the result + if ( (((val1 ^ result) & (val2 ^ result)) >= 0)) { + Node* con_result = ConLNode::make(phase->C, result); + return no_overflow(phase, con_result); + } + return NULL; + } + + if (type1 == TypeLong::ZERO || type2 == TypeLong::ZERO) { // (Add 0 x) == x + Node* add_result = new (phase->C) AddLNode(arg1, arg2); + return no_overflow(phase, add_result); + } + + if (type2->singleton()) { + return NULL; // no change - keep constant on the right + } + + if (type1->singleton()) { + // Make it x + Constant - move constant to the right + swap_edges(1, 2); + return this; + } + + if (arg2->is_Load()) { + return NULL; // no change - keep load on the right + } + + if (arg1->is_Load()) { + // Make it x + Load - move load to the right + swap_edges(1, 2); + return this; + } + + if (arg1->_idx > arg2->_idx) { + // Sort the edges + swap_edges(1, 2); + return this; + } + + return NULL; +} + +Node* SubExactINode::Ideal(PhaseGVN* phase, bool can_reshape) { + Node* arg1 = in(1); + Node* arg2 = in(2); + + const Type* type1 = phase->type(arg1); + const Type* type2 = phase->type(arg2); + + if (type1 != Type::TOP && type1->singleton() && + type2 != Type::TOP && type2->singleton()) { + jint val1 = arg1->get_int(); + jint val2 = arg2->get_int(); + jint result = val1 - val2; + + // Hacker's Delight 2-12 Overflow iff the arguments have different signs and + // the sign of the result is different than the sign of arg1 + if (((val1 ^ val2) & (val1 ^ result)) >= 0) { + Node* con_result = ConINode::make(phase->C, result); + return no_overflow(phase, con_result); + } + return NULL; + } + + if (type1 == TypeInt::ZERO || type2 == TypeInt::ZERO) { + // Sub with zero is the same as add with zero + Node* add_result = new (phase->C) AddINode(arg1, arg2); + return no_overflow(phase, add_result); + } + + return NULL; +} + +Node* SubExactLNode::Ideal(PhaseGVN* phase, bool can_reshape) { + Node* arg1 = in(1); + Node* arg2 = in(2); + + const Type* type1 = phase->type(arg1); + const Type* type2 = phase->type(arg2); + + if (type1 != Type::TOP && type1->singleton() && + type2 != Type::TOP && type2->singleton()) { + jlong val1 = arg1->get_long(); + jlong val2 = arg2->get_long(); + jlong result = val1 - val2; + + // Hacker's Delight 2-12 Overflow iff the arguments have different signs and + // the sign of the result is different than the sign of arg1 + if (((val1 ^ val2) & (val1 ^ result)) >= 0) { + Node* con_result = ConLNode::make(phase->C, result); + return no_overflow(phase, con_result); + } + return NULL; + } + + if (type1 == TypeLong::ZERO || type2 == TypeLong::ZERO) { + // Sub with zero is the same as add with zero + Node* add_result = new (phase->C) AddLNode(arg1, arg2); + return no_overflow(phase, add_result); + } + + return NULL; +} + +Node* NegExactINode::Ideal(PhaseGVN* phase, bool can_reshape) { + Node *arg = in(1); + + const Type* type = phase->type(arg); + if (type != Type::TOP && type->singleton()) { + jint value = arg->get_int(); + if (value != min_jint) { + Node* neg_result = ConINode::make(phase->C, -value); + return no_overflow(phase, neg_result); + } + } + return NULL; +} + +Node* NegExactLNode::Ideal(PhaseGVN* phase, bool can_reshape) { + Node *arg = in(1); + + const Type* type = phase->type(arg); + if (type != Type::TOP && type->singleton()) { + jlong value = arg->get_long(); + if (value != min_jlong) { + Node* neg_result = ConLNode::make(phase->C, -value); + return no_overflow(phase, neg_result); + } + } + return NULL; +} + +Node* MulExactINode::Ideal(PhaseGVN* phase, bool can_reshape) { + Node* arg1 = in(1); + Node* arg2 = in(2); + + const Type* type1 = phase->type(arg1); + const Type* type2 = phase->type(arg2); + + if (type1 != Type::TOP && type1->singleton() && + type2 != Type::TOP && type2->singleton()) { + jint val1 = arg1->get_int(); + jint val2 = arg2->get_int(); + jlong result = (jlong) val1 * (jlong) val2; + if ((jint) result == result) { + // no overflow + Node* mul_result = ConINode::make(phase->C, result); + return no_overflow(phase, mul_result); + } + } + + if (type1 == TypeInt::ZERO || type2 == TypeInt::ZERO) { + return no_overflow(phase, ConINode::make(phase->C, 0)); + } + + if (type1 == TypeInt::ONE) { + Node* mul_result = new (phase->C) AddINode(arg2, phase->intcon(0)); + return no_overflow(phase, mul_result); + } + if (type2 == TypeInt::ONE) { + Node* mul_result = new (phase->C) AddINode(arg1, phase->intcon(0)); + return no_overflow(phase, mul_result); + } + + if (type1 == TypeInt::MINUS_1) { + return new (phase->C) NegExactINode(NULL, arg2); + } + + if (type2 == TypeInt::MINUS_1) { + return new (phase->C) NegExactINode(NULL, arg1); + } + + return NULL; +} + +Node* MulExactLNode::Ideal(PhaseGVN* phase, bool can_reshape) { + Node* arg1 = in(1); + Node* arg2 = in(2); + + const Type* type1 = phase->type(arg1); + const Type* type2 = phase->type(arg2); + + if (type1 != Type::TOP && type1->singleton() && + type2 != Type::TOP && type2->singleton()) { + jlong val1 = arg1->get_long(); + jlong val2 = arg2->get_long(); + + jlong result = val1 * val2; + jlong ax = (val1 < 0 ? -val1 : val1); + jlong ay = (val2 < 0 ? -val2 : val2); + + bool overflow = false; + if ((ax | ay) & CONST64(0xFFFFFFFF00000000)) { + // potential overflow if any bit in upper 32 bits are set + if ((val1 == min_jlong && val2 == -1) || (val2 == min_jlong && val1 == -1)) { + // -1 * Long.MIN_VALUE will overflow + overflow = true; + } else if (val2 != 0 && (result / val2 != val1)) { + overflow = true; + } + } + + if (!overflow) { + Node* mul_result = ConLNode::make(phase->C, result); + return no_overflow(phase, mul_result); + } + } + + if (type1 == TypeLong::ZERO || type2 == TypeLong::ZERO) { + return no_overflow(phase, ConLNode::make(phase->C, 0)); + } + + if (type1 == TypeLong::ONE) { + Node* mul_result = new (phase->C) AddLNode(arg2, phase->longcon(0)); + return no_overflow(phase, mul_result); + } + if (type2 == TypeLong::ONE) { + Node* mul_result = new (phase->C) AddLNode(arg1, phase->longcon(0)); + return no_overflow(phase, mul_result); + } + + if (type1 == TypeLong::MINUS_1) { + return new (phase->C) NegExactLNode(NULL, arg2); + } + + if (type2 == TypeLong::MINUS_1) { + return new (phase->C) NegExactLNode(NULL, arg1); + } + + return NULL; +} + diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/mathexactnode.hpp --- a/src/share/vm/opto/mathexactnode.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/mathexactnode.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -27,8 +27,11 @@ #include "opto/multnode.hpp" #include "opto/node.hpp" +#include "opto/subnode.hpp" #include "opto/type.hpp" +class BoolNode; +class IfNode; class Node; class PhaseGVN; @@ -36,6 +39,7 @@ class MathExactNode : public MultiNode { public: + MathExactNode(Node* ctrl, Node* in1); MathExactNode(Node* ctrl, Node* in1, Node* in2); enum { result_proj_node = 0, @@ -49,19 +53,88 @@ virtual bool is_CFG() const { return false; } virtual uint ideal_reg() const { return NotAMachineReg; } - ProjNode* result_node() { return proj_out(result_proj_node); } - ProjNode* flags_node() { return proj_out(flags_proj_node); } + ProjNode* result_node() const { return proj_out(result_proj_node); } + ProjNode* flags_node() const { return proj_out(flags_proj_node); } + Node* control_node() const; + Node* non_throwing_branch() const; protected: + IfNode* if_node() const; + BoolNode* bool_node() const; Node* no_overflow(PhaseGVN *phase, Node* new_result); }; -class AddExactINode : public MathExactNode { +class MathExactINode : public MathExactNode { + public: + MathExactINode(Node* ctrl, Node* in1) : MathExactNode(ctrl, in1) {} + MathExactINode(Node* ctrl, Node* in1, Node* in2) : MathExactNode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual Node* match(const ProjNode* proj, const Matcher* m); + virtual const Type* bottom_type() const { return TypeTuple::INT_CC_PAIR; } +}; + +class MathExactLNode : public MathExactNode { public: - AddExactINode(Node* ctrl, Node* in1, Node* in2) : MathExactNode(ctrl, in1, in2) {} + MathExactLNode(Node* ctrl, Node* in1) : MathExactNode(ctrl, in1) {} + MathExactLNode(Node* ctrl, Node* in1, Node* in2) : MathExactNode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual Node* match(const ProjNode* proj, const Matcher* m); + virtual const Type* bottom_type() const { return TypeTuple::LONG_CC_PAIR; } +}; + +class AddExactINode : public MathExactINode { +public: + AddExactINode(Node* ctrl, Node* in1, Node* in2) : MathExactINode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); +}; + +class AddExactLNode : public MathExactLNode { +public: + AddExactLNode(Node* ctrl, Node* in1, Node* in2) : MathExactLNode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); +}; + +class SubExactINode : public MathExactINode { +public: + SubExactINode(Node* ctrl, Node* in1, Node* in2) : MathExactINode(ctrl, in1, in2) {} virtual int Opcode() const; - virtual const Type* bottom_type() const { return TypeTuple::INT_CC_PAIR; } - virtual Node* match(const ProjNode* proj, const Matcher* m); - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); +}; + +class SubExactLNode : public MathExactLNode { +public: + SubExactLNode(Node* ctrl, Node* in1, Node* in2) : MathExactLNode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); +}; + +class NegExactINode : public MathExactINode { +public: + NegExactINode(Node* ctrl, Node* in1) : MathExactINode(ctrl, in1) {} + virtual int Opcode() const; + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); +}; + +class NegExactLNode : public MathExactLNode { +public: + NegExactLNode(Node* ctrl, Node* in1) : MathExactLNode(ctrl, in1) {} + virtual int Opcode() const; + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); +}; + +class MulExactINode : public MathExactINode { +public: + MulExactINode(Node* ctrl, Node* in1, Node* in2) : MathExactINode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); +}; + +class MulExactLNode : public MathExactLNode { +public: + MulExactLNode(Node* ctrl, Node* in1, Node* in2) : MathExactLNode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); }; class FlagsProjNode : public ProjNode { diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/multnode.cpp --- a/src/share/vm/opto/multnode.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/multnode.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "opto/callnode.hpp" +#include "opto/cfgnode.hpp" #include "opto/matcher.hpp" #include "opto/mathexactnode.hpp" #include "opto/multnode.hpp" @@ -150,3 +151,59 @@ uint ProjNode::ideal_reg() const { return bottom_type()->ideal_reg(); } + +//-------------------------------is_uncommon_trap_proj---------------------------- +// Return true if proj is the form of "proj->[region->..]call_uct" +bool ProjNode::is_uncommon_trap_proj(Deoptimization::DeoptReason reason) { + int path_limit = 10; + Node* out = this; + for (int ct = 0; ct < path_limit; ct++) { + out = out->unique_ctrl_out(); + if (out == NULL) + return false; + if (out->is_CallStaticJava()) { + int req = out->as_CallStaticJava()->uncommon_trap_request(); + if (req != 0) { + Deoptimization::DeoptReason trap_reason = Deoptimization::trap_request_reason(req); + if (trap_reason == reason || reason == Deoptimization::Reason_none) { + return true; + } + } + return false; // don't do further after call + } + if (out->Opcode() != Op_Region) + return false; + } + return false; +} + +//-------------------------------is_uncommon_trap_if_pattern------------------------- +// Return true for "if(test)-> proj -> ... +// | +// V +// other_proj->[region->..]call_uct" +// +// "must_reason_predicate" means the uct reason must be Reason_predicate +bool ProjNode::is_uncommon_trap_if_pattern(Deoptimization::DeoptReason reason) { + Node *in0 = in(0); + if (!in0->is_If()) return false; + // Variation of a dead If node. + if (in0->outcnt() < 2) return false; + IfNode* iff = in0->as_If(); + + // we need "If(Conv2B(Opaque1(...)))" pattern for reason_predicate + if (reason != Deoptimization::Reason_none) { + if (iff->in(1)->Opcode() != Op_Conv2B || + iff->in(1)->in(1)->Opcode() != Op_Opaque1) { + return false; + } + } + + ProjNode* other_proj = iff->proj_out(1-_con)->as_Proj(); + if (other_proj->is_uncommon_trap_proj(reason)) { + assert(reason == Deoptimization::Reason_none || + Compile::current()->is_predicate_opaq(iff->in(1)->in(1)), "should be on the list"); + return true; + } + return false; +} diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/multnode.hpp --- a/src/share/vm/opto/multnode.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/multnode.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -88,6 +88,14 @@ #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; #endif + + // Return true if proj is for "proj->[region->..]call_uct" + bool is_uncommon_trap_proj(Deoptimization::DeoptReason reason); + // Return true for "if(test)-> proj -> ... + // | + // V + // other_proj->[region->..]call_uct" + bool is_uncommon_trap_if_pattern(Deoptimization::DeoptReason reason); }; #endif // SHARE_VM_OPTO_MULTNODE_HPP diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/node.hpp --- a/src/share/vm/opto/node.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/node.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -100,6 +100,7 @@ class MachSpillCopyNode; class MachTempNode; class Matcher; +class MathExactNode; class MemBarNode; class MemBarStoreStoreNode; class MemNode; @@ -568,6 +569,7 @@ DEFINE_CLASS_ID(MemBar, Multi, 3) DEFINE_CLASS_ID(Initialize, MemBar, 0) DEFINE_CLASS_ID(MemBarStoreStore, MemBar, 1) + DEFINE_CLASS_ID(MathExact, Multi, 4) DEFINE_CLASS_ID(Mach, Node, 1) DEFINE_CLASS_ID(MachReturn, Mach, 0) @@ -757,6 +759,7 @@ DEFINE_CLASS_QUERY(MachSafePoint) DEFINE_CLASS_QUERY(MachSpillCopy) DEFINE_CLASS_QUERY(MachTemp) + DEFINE_CLASS_QUERY(MathExact) DEFINE_CLASS_QUERY(Mem) DEFINE_CLASS_QUERY(MemBar) DEFINE_CLASS_QUERY(MemBarStoreStore) diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/parse.hpp --- a/src/share/vm/opto/parse.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/parse.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -73,6 +73,7 @@ bool try_to_inline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, + JVMState* jvms, ciCallProfile& profile, WarmCallInfo* wci_result, bool& should_delay); @@ -83,6 +84,7 @@ WarmCallInfo* wci_result); bool should_not_inline(ciMethod* callee_method, ciMethod* caller_method, + JVMState* jvms, WarmCallInfo* wci_result); void print_inlining(ciMethod* callee_method, int caller_bci, bool success) const; @@ -347,13 +349,15 @@ int _est_switch_depth; // Debugging SwitchRanges. #endif + // parser for the caller of the method of this object + Parse* const _parent; + public: // Constructor - Parse(JVMState* caller, ciMethod* parse_method, float expected_uses); + Parse(JVMState* caller, ciMethod* parse_method, float expected_uses, Parse* parent); virtual Parse* is_Parse() const { return (Parse*)this; } - public: // Accessors. JVMState* caller() const { return _caller; } float expected_uses() const { return _expected_uses; } @@ -405,6 +409,8 @@ return block()->successor_for_bci(bci); } + Parse* parent_parser() const { return _parent; } + private: // Create a JVMS & map for the initial state of this method. SafePointNode* create_entry_map(); @@ -601,6 +607,9 @@ // Assumes that there is no applicable local handler. void throw_to_exit(SafePointNode* ex_map); + // Use speculative type to optimize CmpP node + Node* optimize_cmp_with_klass(Node* c); + public: #ifndef PRODUCT // Handle PrintOpto, etc. diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/parse1.cpp --- a/src/share/vm/opto/parse1.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/parse1.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -381,8 +381,8 @@ //------------------------------Parse------------------------------------------ // Main parser constructor. -Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) - : _exits(caller) +Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses, Parse* parent) + : _exits(caller), _parent(parent) { // Init some variables _caller = caller; @@ -1102,6 +1102,10 @@ _synch_lock = shared_lock(lock_obj); } + // Feed profiling data for parameters to the type system so it can + // propagate it as speculative types + record_profiled_parameters_for_speculation(); + if (depth() == 1) { increment_and_test_invocation_counter(Tier2CompileThreshold); } diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/parse2.cpp --- a/src/share/vm/opto/parse2.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/parse2.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -268,7 +268,7 @@ return adjoinRange(value, value, dest, table_index); } - void print(ciEnv* env) { + void print() { if (is_singleton()) tty->print(" {%d}=>%d", lo(), dest()); else if (lo() == min_jint) @@ -471,8 +471,8 @@ // These are the switch destinations hanging off the jumpnode int i = 0; for (SwitchRange* r = lo; r <= hi; r++) { - for (int j = r->lo(); j <= r->hi(); j++, i++) { - Node* input = _gvn.transform(new (C) JumpProjNode(jtn, i, r->dest(), j - lowval)); + for (int64 j = r->lo(); j <= r->hi(); j++, i++) { + Node* input = _gvn.transform(new (C) JumpProjNode(jtn, i, r->dest(), (int)(j - lowval))); { PreserveJVMState pjvms(this); set_control(input); @@ -632,7 +632,7 @@ } tty->print(" "); for( r = lo; r <= hi; r++ ) { - r->print(env()); + r->print(); } tty->print_cr(""); } @@ -1366,6 +1366,56 @@ } } +/** + * Use speculative type to optimize CmpP node: if comparison is + * against the low level class, cast the object to the speculative + * type if any. CmpP should then go away. + * + * @param c expected CmpP node + * @return result of CmpP on object casted to speculative type + * + */ +Node* Parse::optimize_cmp_with_klass(Node* c) { + // If this is transformed by the _gvn to a comparison with the low + // level klass then we may be able to use speculation + if (c->Opcode() == Op_CmpP && + (c->in(1)->Opcode() == Op_LoadKlass || c->in(1)->Opcode() == Op_DecodeNKlass) && + c->in(2)->is_Con()) { + Node* load_klass = NULL; + Node* decode = NULL; + if (c->in(1)->Opcode() == Op_DecodeNKlass) { + decode = c->in(1); + load_klass = c->in(1)->in(1); + } else { + load_klass = c->in(1); + } + if (load_klass->in(2)->is_AddP()) { + Node* addp = load_klass->in(2); + Node* obj = addp->in(AddPNode::Address); + const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr(); + if (obj_type->speculative_type() != NULL) { + ciKlass* k = obj_type->speculative_type(); + inc_sp(2); + obj = maybe_cast_profiled_obj(obj, k); + dec_sp(2); + // Make the CmpP use the casted obj + addp = basic_plus_adr(obj, addp->in(AddPNode::Offset)); + load_klass = load_klass->clone(); + load_klass->set_req(2, addp); + load_klass = _gvn.transform(load_klass); + if (decode != NULL) { + decode = decode->clone(); + decode->set_req(1, load_klass); + load_klass = _gvn.transform(decode); + } + c = c->clone(); + c->set_req(1, load_klass); + c = _gvn.transform(c); + } + } + } + return c; +} //------------------------------do_one_bytecode-------------------------------- // Parse this bytecode, and alter the Parsers JVM->Node mapping @@ -2239,6 +2289,7 @@ a = pop(); b = pop(); c = _gvn.transform( new (C) CmpPNode(b, a) ); + c = optimize_cmp_with_klass(c); do_if(btest, c); break; diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/parseHelper.cpp --- a/src/share/vm/opto/parseHelper.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/parseHelper.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -128,7 +128,7 @@ } // Push the bool result back on stack - Node* res = gen_instanceof(peek(), makecon(TypeKlassPtr::make(klass))); + Node* res = gen_instanceof(peek(), makecon(TypeKlassPtr::make(klass)), true); // Pop from stack AFTER gen_instanceof because it can uncommon trap. pop(); @@ -343,10 +343,14 @@ // Get the Method* node. ciMethod* m = method(); - address counters_adr = m->ensure_method_counters(); + MethodCounters* counters_adr = m->ensure_method_counters(); + if (counters_adr == NULL) { + C->record_failure("method counters allocation failed"); + return; + } Node* ctrl = control(); - const TypePtr* adr_type = TypeRawPtr::make(counters_adr); + const TypePtr* adr_type = TypeRawPtr::make((address) counters_adr); Node *counters_node = makecon(adr_type); Node* adr_iic_node = basic_plus_adr(counters_node, counters_node, MethodCounters::interpreter_invocation_counter_offset_in_bytes()); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/phaseX.cpp --- a/src/share/vm/opto/phaseX.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/phaseX.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -1385,6 +1385,20 @@ } } +/** + * Remove the speculative part of all types that we know of + */ +void PhaseIterGVN::remove_speculative_types() { + assert(UseTypeSpeculation, "speculation is off"); + for (uint i = 0; i < _types.Size(); i++) { + const Type* t = _types.fast_lookup(i); + if (t != NULL && t->isa_oopptr()) { + const TypeOopPtr* to = t->is_oopptr(); + _types.map(i, to->remove_speculative()); + } + } +} + //============================================================================= #ifndef PRODUCT uint PhaseCCP::_total_invokes = 0; diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/phaseX.hpp --- a/src/share/vm/opto/phaseX.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/phaseX.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -500,6 +500,8 @@ ProjNode* create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry, Deoptimization::DeoptReason reason); + void remove_speculative_types(); + #ifndef PRODUCT protected: // Sub-quadratic implementation of VerifyIterativeGVN. diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/reg_split.cpp --- a/src/share/vm/opto/reg_split.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/reg_split.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -51,15 +51,6 @@ static const char out_of_nodes[] = "out of nodes during split"; -static bool contains_no_live_range_input(const Node* def) { - for (uint i = 1; i < def->req(); ++i) { - if (def->in(i) != NULL && def->in_RegMask(i).is_NotEmpty()) { - return false; - } - } - return true; -} - //------------------------------get_spillcopy_wide----------------------------- // Get a SpillCopy node with wide-enough masks. Use the 'wide-mask', the // wide ideal-register spill-mask if possible. If the 'wide-mask' does @@ -326,12 +317,11 @@ if( def->req() > 1 ) { for( uint i = 1; i < def->req(); i++ ) { Node *in = def->in(i); - // Check for single-def (LRG cannot redefined) uint lidx = _lrg_map.live_range_id(in); - if (lidx >= _lrg_map.max_lrg_id()) { - continue; // Value is a recent spill-copy - } - if (lrgs(lidx).is_singledef()) { + // We do not need this for live ranges that are only defined once. + // However, this is not true for spill copies that are added in this + // Split() pass, since they might get coalesced later on in this pass. + if (lidx < _lrg_map.max_lrg_id() && lrgs(lidx).is_singledef()) { continue; } @@ -485,7 +475,6 @@ uint bidx, pidx, slidx, insidx, inpidx, twoidx; uint non_phi = 1, spill_cnt = 0; - Node **Reachblock; Node *n1, *n2, *n3; Node_List *defs,*phis; bool *UPblock; @@ -568,7 +557,7 @@ b = _cfg.get_block(bidx); // Reaches & UP arrays for this block - Reachblock = Reaches[b->_pre_order]; + Node** Reachblock = Reaches[b->_pre_order]; UPblock = UP[b->_pre_order]; // Reset counter of start of non-Phi nodes in block non_phi = 1; @@ -1324,9 +1313,10 @@ pidx = pred->_pre_order; // Grab reaching def Node *def = Reaches[pidx][slidx]; + Node** Reachblock = Reaches[pidx]; assert( def, "must have reaching def" ); // If input up/down sense and reg-pressure DISagree - if (def->rematerialize() && contains_no_live_range_input(def)) { + if (def->rematerialize()) { // Place the rematerialized node above any MSCs created during // phi node splitting. end_idx points at the insertion point // so look at the node before it. diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/runtime.cpp --- a/src/share/vm/opto/runtime.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/runtime.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -138,9 +138,10 @@ #define gen(env, var, type_func_gen, c_func, fancy_jump, pass_tls, save_arg_regs, return_pc) \ - var = generate_stub(env, type_func_gen, CAST_FROM_FN_PTR(address, c_func), #var, fancy_jump, pass_tls, save_arg_regs, return_pc) + var = generate_stub(env, type_func_gen, CAST_FROM_FN_PTR(address, c_func), #var, fancy_jump, pass_tls, save_arg_regs, return_pc); \ + if (var == NULL) { return false; } -void OptoRuntime::generate(ciEnv* env) { +bool OptoRuntime::generate(ciEnv* env) { generate_exception_blob(); @@ -158,7 +159,7 @@ gen(env, _multianewarrayN_Java , multianewarrayN_Type , multianewarrayN_C , 0 , true , false, false); gen(env, _g1_wb_pre_Java , g1_wb_pre_Type , SharedRuntime::g1_wb_pre , 0 , false, false, false); gen(env, _g1_wb_post_Java , g1_wb_post_Type , SharedRuntime::g1_wb_post , 0 , false, false, false); - gen(env, _complete_monitor_locking_Java , complete_monitor_enter_Type , SharedRuntime::complete_monitor_locking_C , 0 , false, false, false); + gen(env, _complete_monitor_locking_Java , complete_monitor_enter_Type , SharedRuntime::complete_monitor_locking_C, 0, false, false, false); gen(env, _rethrow_Java , rethrow_Type , rethrow_C , 2 , true , false, true ); gen(env, _slow_arraycopy_Java , slow_arraycopy_Type , SharedRuntime::slow_arraycopy_C , 0 , false, false, false); @@ -168,7 +169,7 @@ gen(env, _zap_dead_Java_locals_Java , zap_dead_locals_Type , zap_dead_Java_locals_C , 0 , false, true , false ); gen(env, _zap_dead_native_locals_Java , zap_dead_locals_Type , zap_dead_native_locals_C , 0 , false, true , false ); # endif - + return true; } #undef gen @@ -976,30 +977,36 @@ address handler_address = NULL; Handle exception(thread, thread->exception_oop()); + address pc = thread->exception_pc(); + + // Clear out the exception oop and pc since looking up an + // exception handler can cause class loading, which might throw an + // exception and those fields are expected to be clear during + // normal bytecode execution. + thread->clear_exception_oop_and_pc(); if (TraceExceptions) { - trace_exception(exception(), thread->exception_pc(), ""); + trace_exception(exception(), pc, ""); } + // for AbortVMOnException flag NOT_PRODUCT(Exceptions::debug_check_abort(exception)); - #ifdef ASSERT - if (!(exception->is_a(SystemDictionary::Throwable_klass()))) { - // should throw an exception here - ShouldNotReachHere(); - } - #endif - +#ifdef ASSERT + if (!(exception->is_a(SystemDictionary::Throwable_klass()))) { + // should throw an exception here + ShouldNotReachHere(); + } +#endif // new exception handling: this method is entered only from adapters // exceptions from compiled java methods are handled in compiled code // using rethrow node - address pc = thread->exception_pc(); nm = CodeCache::find_nmethod(pc); assert(nm != NULL, "No NMethod found"); if (nm->is_native_method()) { - fatal("Native mathod should not have path to exception handling"); + fatal("Native method should not have path to exception handling"); } else { // we are switching to old paradigm: search for exception handler in caller_frame // instead in exception handler of caller_frame.sender() @@ -1346,7 +1353,8 @@ tty->print(" in "); CodeBlob* blob = CodeCache::find_blob(exception_pc); if (blob->is_nmethod()) { - ((nmethod*)blob)->method()->print_value(); + nmethod* nm = blob->as_nmethod_or_null(); + nm->method()->print_value(); } else if (blob->is_runtime_stub()) { tty->print(""); } else { diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/runtime.hpp --- a/src/share/vm/opto/runtime.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/runtime.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -203,8 +203,10 @@ static bool is_callee_saved_register(MachRegisterNumbers reg); - // One time only generate runtime code stubs - static void generate(ciEnv* env); + // One time only generate runtime code stubs. Returns true + // when runtime stubs have been generated successfully and + // false otherwise. + static bool generate(ciEnv* env); // Returns the name of a stub static const char* stub_name(address entry); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/stringopts.cpp --- a/src/share/vm/opto/stringopts.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/stringopts.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2013, 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 @@ -50,10 +50,11 @@ Node* _arguments; // The list of arguments to be concatenated GrowableArray _mode; // into a String along with a mode flag // indicating how to treat the value. - + Node_List _constructors; // List of constructors (many in case of stacked concat) Node_List _control; // List of control nodes that will be deleted Node_List _uncommon_traps; // Uncommon traps that needs to be rewritten // to restart at the initial JVMState. + public: // Mode for converting arguments to Strings enum { @@ -73,6 +74,7 @@ _arguments->del_req(0); } + bool validate_mem_flow(); bool validate_control_flow(); void merge_add() { @@ -189,6 +191,10 @@ assert(!_control.contains(ctrl), "only push once"); _control.push(ctrl); } + void add_constructor(Node* init) { + assert(!_constructors.contains(init), "only push once"); + _constructors.push(init); + } CallStaticJavaNode* end() { return _end; } AllocateNode* begin() { return _begin; } Node* string_alloc() { return _string_alloc; } @@ -301,6 +307,12 @@ } } result->set_allocation(other->_begin); + for (uint i = 0; i < _constructors.size(); i++) { + result->add_constructor(_constructors.at(i)); + } + for (uint i = 0; i < other->_constructors.size(); i++) { + result->add_constructor(other->_constructors.at(i)); + } result->_multiple = true; return result; } @@ -510,7 +522,8 @@ sc->add_control(constructor); sc->add_control(alloc); sc->set_allocation(alloc); - if (sc->validate_control_flow()) { + sc->add_constructor(constructor); + if (sc->validate_control_flow() && sc->validate_mem_flow()) { return sc; } else { return NULL; @@ -620,7 +633,7 @@ #endif StringConcat* merged = sc->merge(other, arg); - if (merged->validate_control_flow()) { + if (merged->validate_control_flow() && merged->validate_mem_flow()) { #ifndef PRODUCT if (PrintOptimizeStringConcat) { tty->print_cr("stacking would succeed"); @@ -708,6 +721,139 @@ } +bool StringConcat::validate_mem_flow() { + Compile* C = _stringopts->C; + + for (uint i = 0; i < _control.size(); i++) { +#ifndef PRODUCT + Node_List path; +#endif + Node* curr = _control.at(i); + if (curr->is_Call() && curr != _begin) { // For all calls except the first allocation + // Now here's the main invariant in our case: + // For memory between the constructor, and appends, and toString we should only see bottom memory, + // produced by the previous call we know about. + if (!_constructors.contains(curr)) { + NOT_PRODUCT(path.push(curr);) + Node* mem = curr->in(TypeFunc::Memory); + assert(mem != NULL, "calls should have memory edge"); + assert(!mem->is_Phi(), "should be handled by control flow validation"); + NOT_PRODUCT(path.push(mem);) + while (mem->is_MergeMem()) { + for (uint i = 1; i < mem->req(); i++) { + if (i != Compile::AliasIdxBot && mem->in(i) != C->top()) { +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print("fusion has incorrect memory flow (side effects) for "); + _begin->jvms()->dump_spec(tty); tty->cr(); + path.dump(); + } +#endif + return false; + } + } + // skip through a potential MergeMem chain, linked through Bot + mem = mem->in(Compile::AliasIdxBot); + NOT_PRODUCT(path.push(mem);) + } + // now let it fall through, and see if we have a projection + if (mem->is_Proj()) { + // Should point to a previous known call + Node *prev = mem->in(0); + NOT_PRODUCT(path.push(prev);) + if (!prev->is_Call() || !_control.contains(prev)) { +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print("fusion has incorrect memory flow (unknown call) for "); + _begin->jvms()->dump_spec(tty); tty->cr(); + path.dump(); + } +#endif + return false; + } + } else { + assert(mem->is_Store() || mem->is_LoadStore(), err_msg_res("unexpected node type: %s", mem->Name())); +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print("fusion has incorrect memory flow (unexpected source) for "); + _begin->jvms()->dump_spec(tty); tty->cr(); + path.dump(); + } +#endif + return false; + } + } else { + // For memory that feeds into constructors it's more complicated. + // However the advantage is that any side effect that happens between the Allocate/Initialize and + // the constructor will have to be control-dependent on Initialize. + // So we actually don't have to do anything, since it's going to be caught by the control flow + // analysis. +#ifdef ASSERT + // Do a quick verification of the control pattern between the constructor and the initialize node + assert(curr->is_Call(), "constructor should be a call"); + // Go up the control starting from the constructor call + Node* ctrl = curr->in(0); + IfNode* iff = NULL; + RegionNode* copy = NULL; + + while (true) { + // skip known check patterns + if (ctrl->is_Region()) { + if (ctrl->as_Region()->is_copy()) { + copy = ctrl->as_Region(); + ctrl = copy->is_copy(); + } else { // a cast + assert(ctrl->req() == 3 && + ctrl->in(1) != NULL && ctrl->in(1)->is_Proj() && + ctrl->in(2) != NULL && ctrl->in(2)->is_Proj() && + ctrl->in(1)->in(0) == ctrl->in(2)->in(0) && + ctrl->in(1)->in(0) != NULL && ctrl->in(1)->in(0)->is_If(), + "must be a simple diamond"); + Node* true_proj = ctrl->in(1)->is_IfTrue() ? ctrl->in(1) : ctrl->in(2); + for (SimpleDUIterator i(true_proj); i.has_next(); i.next()) { + Node* use = i.get(); + assert(use == ctrl || use->is_ConstraintCast(), + err_msg_res("unexpected user: %s", use->Name())); + } + + iff = ctrl->in(1)->in(0)->as_If(); + ctrl = iff->in(0); + } + } else if (ctrl->is_IfTrue()) { // null checks, class checks + iff = ctrl->in(0)->as_If(); + assert(iff->is_If(), "must be if"); + // Verify that the other arm is an uncommon trap + Node* otherproj = iff->proj_out(1 - ctrl->as_Proj()->_con); + CallStaticJavaNode* call = otherproj->unique_out()->isa_CallStaticJava(); + assert(strcmp(call->_name, "uncommon_trap") == 0, "must be uncommond trap"); + ctrl = iff->in(0); + } else { + break; + } + } + + assert(ctrl->is_Proj(), "must be a projection"); + assert(ctrl->in(0)->is_Initialize(), "should be initialize"); + for (SimpleDUIterator i(ctrl); i.has_next(); i.next()) { + Node* use = i.get(); + assert(use == copy || use == iff || use == curr || use->is_CheckCastPP() || use->is_Load(), + err_msg_res("unexpected user: %s", use->Name())); + } +#endif // ASSERT + } + } + } + +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print("fusion has correct memory flow for "); + _begin->jvms()->dump_spec(tty); tty->cr(); + tty->cr(); + } +#endif + return true; +} + bool StringConcat::validate_control_flow() { // We found all the calls and arguments now lets see if it's // safe to transform the graph as we would expect. @@ -753,7 +899,7 @@ } } - // Skip backwards through the control checking for unexpected contro flow + // Skip backwards through the control checking for unexpected control flow Node* ptr = _end; bool fail = false; while (ptr != _begin) { @@ -936,7 +1082,7 @@ if (PrintOptimizeStringConcat && !fail) { ttyLocker ttyl; tty->cr(); - tty->print("fusion would succeed (%d %d) for ", null_check_count, _uncommon_traps.size()); + tty->print("fusion has correct control flow (%d %d) for ", null_check_count, _uncommon_traps.size()); _begin->jvms()->dump_spec(tty); tty->cr(); for (int i = 0; i < num_arguments(); i++) { argument(i)->dump(); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/type.cpp --- a/src/share/vm/opto/type.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/type.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -358,7 +358,7 @@ false, 0, oopDesc::mark_offset_in_bytes()); TypeInstPtr::KLASS = TypeInstPtr::make(TypePtr::BotPTR, current->env()->Object_klass(), false, 0, oopDesc::klass_offset_in_bytes()); - TypeOopPtr::BOTTOM = TypeOopPtr::make(TypePtr::BotPTR, OffsetBot, TypeOopPtr::InstanceBot); + TypeOopPtr::BOTTOM = TypeOopPtr::make(TypePtr::BotPTR, OffsetBot, TypeOopPtr::InstanceBot, NULL); TypeMetadataPtr::BOTTOM = TypeMetadataPtr::make(TypePtr::BotPTR, NULL, OffsetBot); @@ -435,6 +435,11 @@ intccpair[1] = TypeInt::CC; TypeTuple::INT_CC_PAIR = TypeTuple::make(2, intccpair); + const Type **longccpair = TypeTuple::fields(2); + longccpair[0] = TypeLong::LONG; + longccpair[1] = TypeInt::CC; + TypeTuple::LONG_CC_PAIR = TypeTuple::make(2, longccpair); + _const_basic_type[T_NARROWOOP] = TypeNarrowOop::BOTTOM; _const_basic_type[T_NARROWKLASS] = Type::BOTTOM; _const_basic_type[T_BOOLEAN] = TypeInt::BOOL; @@ -577,7 +582,7 @@ //----------------------interface_vs_oop--------------------------------------- #ifdef ASSERT -bool Type::interface_vs_oop(const Type *t) const { +bool Type::interface_vs_oop_helper(const Type *t) const { bool result = false; const TypePtr* this_ptr = this->make_ptr(); // In case it is narrow_oop @@ -595,6 +600,29 @@ return result; } + +bool Type::interface_vs_oop(const Type *t) const { + if (interface_vs_oop_helper(t)) { + return true; + } + // Now check the speculative parts as well + const TypeOopPtr* this_spec = isa_oopptr() != NULL ? isa_oopptr()->speculative() : NULL; + const TypeOopPtr* t_spec = t->isa_oopptr() != NULL ? t->isa_oopptr()->speculative() : NULL; + if (this_spec != NULL && t_spec != NULL) { + if (this_spec->interface_vs_oop_helper(t_spec)) { + return true; + } + return false; + } + if (this_spec != NULL && this_spec->interface_vs_oop_helper(t)) { + return true; + } + if (t_spec != NULL && interface_vs_oop_helper(t_spec)) { + return true; + } + return false; +} + #endif //------------------------------meet------------------------------------------- @@ -1652,6 +1680,7 @@ const TypeTuple *TypeTuple::INT_PAIR; const TypeTuple *TypeTuple::LONG_PAIR; const TypeTuple *TypeTuple::INT_CC_PAIR; +const TypeTuple *TypeTuple::LONG_CC_PAIR; //------------------------------make------------------------------------------- @@ -2407,14 +2436,15 @@ const TypeOopPtr *TypeOopPtr::BOTTOM; //------------------------------TypeOopPtr------------------------------------- -TypeOopPtr::TypeOopPtr( TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id ) +TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, const TypeOopPtr* speculative) : TypePtr(t, ptr, offset), _const_oop(o), _klass(k), _klass_is_exact(xk), _is_ptr_to_narrowoop(false), _is_ptr_to_narrowklass(false), _is_ptr_to_boxed_value(false), - _instance_id(instance_id) { + _instance_id(instance_id), + _speculative(speculative) { if (Compile::current()->eliminate_boxing() && (t == InstPtr) && (offset > 0) && xk && (k != 0) && k->is_instance_klass()) { _is_ptr_to_boxed_value = k->as_instance_klass()->is_boxed_value_offset(offset); @@ -2481,12 +2511,12 @@ //------------------------------make------------------------------------------- const TypeOopPtr *TypeOopPtr::make(PTR ptr, - int offset, int instance_id) { + int offset, int instance_id, const TypeOopPtr* speculative) { assert(ptr != Constant, "no constant generic pointers"); ciKlass* k = Compile::current()->env()->Object_klass(); bool xk = false; ciObject* o = NULL; - return (TypeOopPtr*)(new TypeOopPtr(OopPtr, ptr, k, xk, o, offset, instance_id))->hashcons(); + return (TypeOopPtr*)(new TypeOopPtr(OopPtr, ptr, k, xk, o, offset, instance_id, speculative))->hashcons(); } @@ -2494,7 +2524,7 @@ const Type *TypeOopPtr::cast_to_ptr_type(PTR ptr) const { assert(_base == OopPtr, "subclass must override cast_to_ptr_type"); if( ptr == _ptr ) return this; - return make(ptr, _offset, _instance_id); + return make(ptr, _offset, _instance_id, _speculative); } //-----------------------------cast_to_instance_id---------------------------- @@ -2524,10 +2554,31 @@ return TypeKlassPtr::make(xk? Constant: NotNull, k, 0); } +const Type *TypeOopPtr::xmeet(const Type *t) const { + const Type* res = xmeet_helper(t); + if (res->isa_oopptr() == NULL) { + return res; + } + + if (res->isa_oopptr() != NULL) { + // type->speculative() == NULL means that speculation is no better + // than type, i.e. type->speculative() == type. So there are 2 + // ways to represent the fact that we have no useful speculative + // data and we should use a single one to be able to test for + // equality between types. Check whether type->speculative() == + // type and set speculative to NULL if it is the case. + const TypeOopPtr* res_oopptr = res->is_oopptr(); + if (res_oopptr->remove_speculative() == res_oopptr->speculative()) { + return res_oopptr->remove_speculative(); + } + } + + return res; +} //------------------------------meet------------------------------------------- // Compute the MEET of two types. It returns a new Type object. -const Type *TypeOopPtr::xmeet( const Type *t ) const { +const Type *TypeOopPtr::xmeet_helper(const Type *t) const { // Perform a fast test for common case; meeting the same types together. if( this == t ) return this; // Meeting same type-rep? @@ -2569,7 +2620,8 @@ case TopPTR: case AnyNull: { int instance_id = meet_instance_id(InstanceTop); - return make(ptr, offset, instance_id); + const TypeOopPtr* speculative = _speculative; + return make(ptr, offset, instance_id, speculative); } case BotPTR: case NotNull: @@ -2581,7 +2633,8 @@ case OopPtr: { // Meeting to other OopPtrs const TypeOopPtr *tp = t->is_oopptr(); int instance_id = meet_instance_id(tp->instance_id()); - return make( meet_ptr(tp->ptr()), meet_offset(tp->offset()), instance_id ); + const TypeOopPtr* speculative = meet_speculative(tp); + return make(meet_ptr(tp->ptr()), meet_offset(tp->offset()), instance_id, speculative); } case InstPtr: // For these, flip the call around to cut down @@ -2598,7 +2651,7 @@ const Type *TypeOopPtr::xdual() const { assert(klass() == Compile::current()->env()->Object_klass(), "no klasses here"); assert(const_oop() == NULL, "no constants here"); - return new TypeOopPtr(_base, dual_ptr(), klass(), klass_is_exact(), const_oop(), dual_offset(), dual_instance_id() ); + return new TypeOopPtr(_base, dual_ptr(), klass(), klass_is_exact(), const_oop(), dual_offset(), dual_instance_id(), dual_speculative()); } //--------------------------make_from_klass_common----------------------------- @@ -2689,7 +2742,7 @@ } else if (!o->should_be_constant()) { return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0); } - const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0, InstanceBot, is_autobox_cache); + const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0, InstanceBot, NULL, is_autobox_cache); return arr; } else if (klass->is_type_array_klass()) { // Element is an typeArray @@ -2789,7 +2842,8 @@ bool TypeOopPtr::eq( const Type *t ) const { const TypeOopPtr *a = (const TypeOopPtr*)t; if (_klass_is_exact != a->_klass_is_exact || - _instance_id != a->_instance_id) return false; + _instance_id != a->_instance_id || + !eq_speculative(a)) return false; ciObject* one = const_oop(); ciObject* two = a->const_oop(); if (one == NULL || two == NULL) { @@ -2806,6 +2860,7 @@ (const_oop() ? const_oop()->hash() : 0) + _klass_is_exact + _instance_id + + hash_speculative() + TypePtr::hash(); } @@ -2825,6 +2880,19 @@ st->print(",iid=top"); else if (_instance_id != InstanceBot) st->print(",iid=%d",_instance_id); + + dump_speculative(st); +} + +/** + *dump the speculative part of the type + */ +void TypeOopPtr::dump_speculative(outputStream *st) const { + if (_speculative != NULL) { + st->print(" (speculative="); + _speculative->dump_on(st); + st->print(")"); + } } #endif @@ -2838,8 +2906,15 @@ } //------------------------------add_offset------------------------------------- -const TypePtr *TypeOopPtr::add_offset( intptr_t offset ) const { - return make( _ptr, xadd_offset(offset), _instance_id); +const TypePtr *TypeOopPtr::add_offset(intptr_t offset) const { + return make(_ptr, xadd_offset(offset), _instance_id, add_offset_speculative(offset)); +} + +/** + * Return same type without a speculative part + */ +const TypeOopPtr* TypeOopPtr::remove_speculative() const { + return make(_ptr, _offset, _instance_id, NULL); } //------------------------------meet_instance_id-------------------------------- @@ -2859,6 +2934,89 @@ return _instance_id; // Map everything else into self } +/** + * meet of the speculative parts of 2 types + * + * @param other type to meet with + */ +const TypeOopPtr* TypeOopPtr::meet_speculative(const TypeOopPtr* other) const { + bool this_has_spec = (_speculative != NULL); + bool other_has_spec = (other->speculative() != NULL); + + if (!this_has_spec && !other_has_spec) { + return NULL; + } + + // If we are at a point where control flow meets and one branch has + // a speculative type and the other has not, we meet the speculative + // type of one branch with the actual type of the other. If the + // actual type is exact and the speculative is as well, then the + // result is a speculative type which is exact and we can continue + // speculation further. + const TypeOopPtr* this_spec = _speculative; + const TypeOopPtr* other_spec = other->speculative(); + + if (!this_has_spec) { + this_spec = this; + } + + if (!other_has_spec) { + other_spec = other; + } + + return this_spec->meet(other_spec)->is_oopptr(); +} + +/** + * dual of the speculative part of the type + */ +const TypeOopPtr* TypeOopPtr::dual_speculative() const { + if (_speculative == NULL) { + return NULL; + } + return _speculative->dual()->is_oopptr(); +} + +/** + * add offset to the speculative part of the type + * + * @param offset offset to add + */ +const TypeOopPtr* TypeOopPtr::add_offset_speculative(intptr_t offset) const { + if (_speculative == NULL) { + return NULL; + } + return _speculative->add_offset(offset)->is_oopptr(); +} + +/** + * Are the speculative parts of 2 types equal? + * + * @param other type to compare this one to + */ +bool TypeOopPtr::eq_speculative(const TypeOopPtr* other) const { + if (_speculative == NULL || other->speculative() == NULL) { + return _speculative == other->speculative(); + } + + if (_speculative->base() != other->speculative()->base()) { + return false; + } + + return _speculative->eq(other->speculative()); +} + +/** + * Hash of the speculative part of the type + */ +int TypeOopPtr::hash_speculative() const { + if (_speculative == NULL) { + return 0; + } + + return _speculative->hash(); +} + //============================================================================= // Convenience common pre-built types. @@ -2869,8 +3027,8 @@ const TypeInstPtr *TypeInstPtr::KLASS; //------------------------------TypeInstPtr------------------------------------- -TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int off, int instance_id) - : TypeOopPtr(InstPtr, ptr, k, xk, o, off, instance_id), _name(k->name()) { +TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int off, int instance_id, const TypeOopPtr* speculative) + : TypeOopPtr(InstPtr, ptr, k, xk, o, off, instance_id, speculative), _name(k->name()) { assert(k != NULL && (k->is_loaded() || o == NULL), "cannot have constants with non-loaded klass"); @@ -2882,7 +3040,8 @@ bool xk, ciObject* o, int offset, - int instance_id) { + int instance_id, + const TypeOopPtr* speculative) { assert( !k->is_loaded() || k->is_instance_klass(), "Must be for instance"); // Either const_oop() is NULL or else ptr is Constant assert( (!o && ptr != Constant) || (o && ptr == Constant), @@ -2903,7 +3062,7 @@ // Now hash this baby TypeInstPtr *result = - (TypeInstPtr*)(new TypeInstPtr(ptr, k, xk, o ,offset, instance_id))->hashcons(); + (TypeInstPtr*)(new TypeInstPtr(ptr, k, xk, o ,offset, instance_id, speculative))->hashcons(); return result; } @@ -2936,7 +3095,7 @@ if( ptr == _ptr ) return this; // Reconstruct _sig info here since not a problem with later lazy // construction, _sig will show up on demand. - return make(ptr, klass(), klass_is_exact(), const_oop(), _offset, _instance_id); + return make(ptr, klass(), klass_is_exact(), const_oop(), _offset, _instance_id, _speculative); } @@ -2948,13 +3107,13 @@ ciInstanceKlass* ik = _klass->as_instance_klass(); if( (ik->is_final() || _const_oop) ) return this; // cannot clear xk if( ik->is_interface() ) return this; // cannot set xk - return make(ptr(), klass(), klass_is_exact, const_oop(), _offset, _instance_id); + return make(ptr(), klass(), klass_is_exact, const_oop(), _offset, _instance_id, _speculative); } //-----------------------------cast_to_instance_id---------------------------- const TypeOopPtr *TypeInstPtr::cast_to_instance_id(int instance_id) const { if( instance_id == _instance_id ) return this; - return make(_ptr, klass(), _klass_is_exact, const_oop(), _offset, instance_id); + return make(_ptr, klass(), _klass_is_exact, const_oop(), _offset, instance_id, _speculative); } //------------------------------xmeet_unloaded--------------------------------- @@ -2964,6 +3123,7 @@ int off = meet_offset(tinst->offset()); PTR ptr = meet_ptr(tinst->ptr()); int instance_id = meet_instance_id(tinst->instance_id()); + const TypeOopPtr* speculative = meet_speculative(tinst); const TypeInstPtr *loaded = is_loaded() ? this : tinst; const TypeInstPtr *unloaded = is_loaded() ? tinst : this; @@ -2984,7 +3144,7 @@ assert(loaded->ptr() != TypePtr::Null, "insanity check"); // if( loaded->ptr() == TypePtr::TopPTR ) { return unloaded; } - else if (loaded->ptr() == TypePtr::AnyNull) { return TypeInstPtr::make( ptr, unloaded->klass(), false, NULL, off, instance_id ); } + else if (loaded->ptr() == TypePtr::AnyNull) { return TypeInstPtr::make(ptr, unloaded->klass(), false, NULL, off, instance_id, speculative); } else if (loaded->ptr() == TypePtr::BotPTR ) { return TypeInstPtr::BOTTOM; } else if (loaded->ptr() == TypePtr::Constant || loaded->ptr() == TypePtr::NotNull) { if (unloaded->ptr() == TypePtr::BotPTR ) { return TypeInstPtr::BOTTOM; } @@ -3006,7 +3166,7 @@ //------------------------------meet------------------------------------------- // Compute the MEET of two types. It returns a new Type object. -const Type *TypeInstPtr::xmeet( const Type *t ) const { +const Type *TypeInstPtr::xmeet_helper(const Type *t) const { // Perform a fast test for common case; meeting the same types together. if( this == t ) return this; // Meeting same type-rep? @@ -3040,16 +3200,20 @@ int offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); int instance_id = meet_instance_id(tp->instance_id()); + const TypeOopPtr* speculative = meet_speculative(tp); switch (ptr) { case TopPTR: case AnyNull: // Fall 'down' to dual of object klass - if (klass()->equals(ciEnv::current()->Object_klass())) { - return TypeAryPtr::make(ptr, tp->ary(), tp->klass(), tp->klass_is_exact(), offset, instance_id); + // For instances when a subclass meets a superclass we fall + // below the centerline when the superclass is exact. We need to + // do the same here. + if (klass()->equals(ciEnv::current()->Object_klass()) && !klass_is_exact()) { + return TypeAryPtr::make(ptr, tp->ary(), tp->klass(), tp->klass_is_exact(), offset, instance_id, speculative); } else { // cannot subclass, so the meet has to fall badly below the centerline ptr = NotNull; instance_id = InstanceBot; - return TypeInstPtr::make( ptr, ciEnv::current()->Object_klass(), false, NULL, offset, instance_id); + return TypeInstPtr::make( ptr, ciEnv::current()->Object_klass(), false, NULL, offset, instance_id, speculative); } case Constant: case NotNull: @@ -3058,10 +3222,13 @@ if( above_centerline(_ptr) ) { // if( _ptr == TopPTR || _ptr == AnyNull ) // If 'this' (InstPtr) is above the centerline and it is Object class // then we can subclass in the Java class hierarchy. - if (klass()->equals(ciEnv::current()->Object_klass())) { + // For instances when a subclass meets a superclass we fall + // below the centerline when the superclass is exact. We need + // to do the same here. + if (klass()->equals(ciEnv::current()->Object_klass()) && !klass_is_exact()) { // that is, tp's array type is a subtype of my klass return TypeAryPtr::make(ptr, (ptr == Constant ? tp->const_oop() : NULL), - tp->ary(), tp->klass(), tp->klass_is_exact(), offset, instance_id); + tp->ary(), tp->klass(), tp->klass_is_exact(), offset, instance_id, speculative); } } // The other case cannot happen, since I cannot be a subtype of an array. @@ -3069,7 +3236,7 @@ if( ptr == Constant ) ptr = NotNull; instance_id = InstanceBot; - return make( ptr, ciEnv::current()->Object_klass(), false, NULL, offset, instance_id ); + return make(ptr, ciEnv::current()->Object_klass(), false, NULL, offset, instance_id, speculative); default: typerr(t); } } @@ -3083,13 +3250,15 @@ case TopPTR: case AnyNull: { int instance_id = meet_instance_id(InstanceTop); + const TypeOopPtr* speculative = meet_speculative(tp); return make(ptr, klass(), klass_is_exact(), - (ptr == Constant ? const_oop() : NULL), offset, instance_id); + (ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative); } case NotNull: case BotPTR: { int instance_id = meet_instance_id(tp->instance_id()); - return TypeOopPtr::make(ptr, offset, instance_id); + const TypeOopPtr* speculative = meet_speculative(tp); + return TypeOopPtr::make(ptr, offset, instance_id, speculative); } default: typerr(t); } @@ -3102,17 +3271,18 @@ PTR ptr = meet_ptr(tp->ptr()); switch (tp->ptr()) { case Null: - if( ptr == Null ) return TypePtr::make( AnyPtr, ptr, offset ); + if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset); // else fall through to AnyNull case TopPTR: case AnyNull: { int instance_id = meet_instance_id(InstanceTop); - return make( ptr, klass(), klass_is_exact(), - (ptr == Constant ? const_oop() : NULL), offset, instance_id); + const TypeOopPtr* speculative = _speculative; + return make(ptr, klass(), klass_is_exact(), + (ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative); } case NotNull: case BotPTR: - return TypePtr::make( AnyPtr, ptr, offset ); + return TypePtr::make(AnyPtr, ptr, offset); default: typerr(t); } } @@ -3139,13 +3309,14 @@ int off = meet_offset( tinst->offset() ); PTR ptr = meet_ptr( tinst->ptr() ); int instance_id = meet_instance_id(tinst->instance_id()); + const TypeOopPtr* speculative = meet_speculative(tinst); // Check for easy case; klasses are equal (and perhaps not loaded!) // If we have constants, then we created oops so classes are loaded // and we can handle the constants further down. This case handles // both-not-loaded or both-loaded classes if (ptr != Constant && klass()->equals(tinst->klass()) && klass_is_exact() == tinst->klass_is_exact()) { - return make( ptr, klass(), klass_is_exact(), NULL, off, instance_id ); + return make(ptr, klass(), klass_is_exact(), NULL, off, instance_id, speculative); } // Classes require inspection in the Java klass hierarchy. Must be loaded. @@ -3167,7 +3338,8 @@ } // Handle mixing oops and interfaces first. - if( this_klass->is_interface() && !tinst_klass->is_interface() ) { + if( this_klass->is_interface() && !(tinst_klass->is_interface() || + tinst_klass == ciEnv::current()->Object_klass())) { ciKlass *tmp = tinst_klass; // Swap interface around tinst_klass = this_klass; this_klass = tmp; @@ -3208,7 +3380,7 @@ // Find out which constant. o = (this_klass == klass()) ? const_oop() : tinst->const_oop(); } - return make( ptr, k, xk, o, off, instance_id ); + return make(ptr, k, xk, o, off, instance_id, speculative); } // Either oop vs oop or interface vs interface or interface vs Object @@ -3285,7 +3457,7 @@ else ptr = NotNull; } - return make( ptr, this_klass, this_xk, o, off, instance_id ); + return make(ptr, this_klass, this_xk, o, off, instance_id, speculative); } // Else classes are not equal // Since klasses are different, we require a LCA in the Java @@ -3296,7 +3468,7 @@ // Now we find the LCA of Java classes ciKlass* k = this_klass->least_common_ancestor(tinst_klass); - return make( ptr, k, false, NULL, off, instance_id ); + return make(ptr, k, false, NULL, off, instance_id, speculative); } // End of case InstPtr } // End of switch @@ -3320,7 +3492,7 @@ // Dual: do NOT dual on klasses. This means I do NOT understand the Java // inheritance mechanism. const Type *TypeInstPtr::xdual() const { - return new TypeInstPtr( dual_ptr(), klass(), klass_is_exact(), const_oop(), dual_offset(), dual_instance_id() ); + return new TypeInstPtr(dual_ptr(), klass(), klass_is_exact(), const_oop(), dual_offset(), dual_instance_id(), dual_speculative()); } //------------------------------eq--------------------------------------------- @@ -3376,12 +3548,18 @@ st->print(",iid=top"); else if (_instance_id != InstanceBot) st->print(",iid=%d",_instance_id); + + dump_speculative(st); } #endif //------------------------------add_offset------------------------------------- -const TypePtr *TypeInstPtr::add_offset( intptr_t offset ) const { - return make( _ptr, klass(), klass_is_exact(), const_oop(), xadd_offset(offset), _instance_id ); +const TypePtr *TypeInstPtr::add_offset(intptr_t offset) const { + return make(_ptr, klass(), klass_is_exact(), const_oop(), xadd_offset(offset), _instance_id, add_offset_speculative(offset)); +} + +const TypeOopPtr *TypeInstPtr::remove_speculative() const { + return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, _instance_id, NULL); } //============================================================================= @@ -3398,30 +3576,30 @@ const TypeAryPtr *TypeAryPtr::DOUBLES; //------------------------------make------------------------------------------- -const TypeAryPtr *TypeAryPtr::make( PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id ) { +const TypeAryPtr *TypeAryPtr::make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id, const TypeOopPtr* speculative) { assert(!(k == NULL && ary->_elem->isa_int()), "integral arrays must be pre-equipped with a class"); if (!xk) xk = ary->ary_must_be_exact(); assert(instance_id <= 0 || xk || !UseExactTypes, "instances are always exactly typed"); if (!UseExactTypes) xk = (ptr == Constant); - return (TypeAryPtr*)(new TypeAryPtr(ptr, NULL, ary, k, xk, offset, instance_id, false))->hashcons(); + return (TypeAryPtr*)(new TypeAryPtr(ptr, NULL, ary, k, xk, offset, instance_id, false, speculative))->hashcons(); } //------------------------------make------------------------------------------- -const TypeAryPtr *TypeAryPtr::make( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id, bool is_autobox_cache) { +const TypeAryPtr *TypeAryPtr::make(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id, const TypeOopPtr* speculative, bool is_autobox_cache) { assert(!(k == NULL && ary->_elem->isa_int()), "integral arrays must be pre-equipped with a class"); assert( (ptr==Constant && o) || (ptr!=Constant && !o), "" ); if (!xk) xk = (o != NULL) || ary->ary_must_be_exact(); assert(instance_id <= 0 || xk || !UseExactTypes, "instances are always exactly typed"); if (!UseExactTypes) xk = (ptr == Constant); - return (TypeAryPtr*)(new TypeAryPtr(ptr, o, ary, k, xk, offset, instance_id, is_autobox_cache))->hashcons(); + return (TypeAryPtr*)(new TypeAryPtr(ptr, o, ary, k, xk, offset, instance_id, is_autobox_cache, speculative))->hashcons(); } //------------------------------cast_to_ptr_type------------------------------- const Type *TypeAryPtr::cast_to_ptr_type(PTR ptr) const { if( ptr == _ptr ) return this; - return make(ptr, const_oop(), _ary, klass(), klass_is_exact(), _offset, _instance_id); + return make(ptr, const_oop(), _ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative); } @@ -3430,13 +3608,13 @@ if( klass_is_exact == _klass_is_exact ) return this; if (!UseExactTypes) return this; if (_ary->ary_must_be_exact()) return this; // cannot clear xk - return make(ptr(), const_oop(), _ary, klass(), klass_is_exact, _offset, _instance_id); + return make(ptr(), const_oop(), _ary, klass(), klass_is_exact, _offset, _instance_id, _speculative); } //-----------------------------cast_to_instance_id---------------------------- const TypeOopPtr *TypeAryPtr::cast_to_instance_id(int instance_id) const { if( instance_id == _instance_id ) return this; - return make(_ptr, const_oop(), _ary, klass(), _klass_is_exact, _offset, instance_id); + return make(_ptr, const_oop(), _ary, klass(), _klass_is_exact, _offset, instance_id, _speculative); } //-----------------------------narrow_size_type------------------------------- @@ -3499,7 +3677,7 @@ new_size = narrow_size_type(new_size); if (new_size == size()) return this; const TypeAry* new_ary = TypeAry::make(elem(), new_size, is_stable()); - return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id); + return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative); } @@ -3548,7 +3726,7 @@ //------------------------------meet------------------------------------------- // Compute the MEET of two types. It returns a new Type object. -const Type *TypeAryPtr::xmeet( const Type *t ) const { +const Type *TypeAryPtr::xmeet_helper(const Type *t) const { // Perform a fast test for common case; meeting the same types together. if( this == t ) return this; // Meeting same type-rep? // Current "this->_base" is Pointer @@ -3582,13 +3760,15 @@ case TopPTR: case AnyNull: { int instance_id = meet_instance_id(InstanceTop); + const TypeOopPtr* speculative = meet_speculative(tp); return make(ptr, (ptr == Constant ? const_oop() : NULL), - _ary, _klass, _klass_is_exact, offset, instance_id); + _ary, _klass, _klass_is_exact, offset, instance_id, speculative); } case BotPTR: case NotNull: { int instance_id = meet_instance_id(tp->instance_id()); - return TypeOopPtr::make(ptr, offset, instance_id); + const TypeOopPtr* speculative = meet_speculative(tp); + return TypeOopPtr::make(ptr, offset, instance_id, speculative); } default: ShouldNotReachHere(); } @@ -3610,8 +3790,9 @@ // else fall through to AnyNull case AnyNull: { int instance_id = meet_instance_id(InstanceTop); - return make( ptr, (ptr == Constant ? const_oop() : NULL), - _ary, _klass, _klass_is_exact, offset, instance_id); + const TypeOopPtr* speculative = _speculative; + return make(ptr, (ptr == Constant ? const_oop() : NULL), + _ary, _klass, _klass_is_exact, offset, instance_id, speculative); } default: ShouldNotReachHere(); } @@ -3627,6 +3808,7 @@ const TypeAry *tary = _ary->meet(tap->_ary)->is_ary(); PTR ptr = meet_ptr(tap->ptr()); int instance_id = meet_instance_id(tap->instance_id()); + const TypeOopPtr* speculative = meet_speculative(tap); ciKlass* lazy_klass = NULL; if (tary->_elem->isa_int()) { // Integral array element types have irrelevant lattice relations. @@ -3654,7 +3836,7 @@ // 'this' is exact and super or unrelated: (this->_klass_is_exact && !klass()->is_subtype_of(tap->klass())))) { tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable); - return make( NotNull, NULL, tary, lazy_klass, false, off, InstanceBot ); + return make(NotNull, NULL, tary, lazy_klass, false, off, InstanceBot); } bool xk = false; @@ -3662,8 +3844,12 @@ case AnyNull: case TopPTR: // Compute new klass on demand, do not use tap->_klass - xk = (tap->_klass_is_exact | this->_klass_is_exact); - return make( ptr, const_oop(), tary, lazy_klass, xk, off, instance_id ); + if (below_centerline(this->_ptr)) { + xk = this->_klass_is_exact; + } else { + xk = (tap->_klass_is_exact | this->_klass_is_exact); + } + return make(ptr, const_oop(), tary, lazy_klass, xk, off, instance_id, speculative); case Constant: { ciObject* o = const_oop(); if( _ptr == Constant ) { @@ -3675,25 +3861,23 @@ } else { xk = true; } - } else if( above_centerline(_ptr) ) { + } else if(above_centerline(_ptr)) { o = tap->const_oop(); xk = true; } else { // Only precise for identical arrays xk = this->_klass_is_exact && (klass() == tap->klass()); } - return TypeAryPtr::make( ptr, o, tary, lazy_klass, xk, off, instance_id ); + return TypeAryPtr::make(ptr, o, tary, lazy_klass, xk, off, instance_id, speculative); } case NotNull: case BotPTR: // Compute new klass on demand, do not use tap->_klass if (above_centerline(this->_ptr)) xk = tap->_klass_is_exact; - else if (above_centerline(tap->_ptr)) - xk = this->_klass_is_exact; else xk = (tap->_klass_is_exact & this->_klass_is_exact) && (klass() == tap->klass()); // Only precise for identical arrays - return TypeAryPtr::make( ptr, NULL, tary, lazy_klass, xk, off, instance_id ); + return TypeAryPtr::make(ptr, NULL, tary, lazy_klass, xk, off, instance_id, speculative); default: ShouldNotReachHere(); } } @@ -3704,16 +3888,20 @@ int offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); int instance_id = meet_instance_id(tp->instance_id()); + const TypeOopPtr* speculative = meet_speculative(tp); switch (ptr) { case TopPTR: case AnyNull: // Fall 'down' to dual of object klass - if( tp->klass()->equals(ciEnv::current()->Object_klass()) ) { - return TypeAryPtr::make( ptr, _ary, _klass, _klass_is_exact, offset, instance_id ); + // For instances when a subclass meets a superclass we fall + // below the centerline when the superclass is exact. We need to + // do the same here. + if (tp->klass()->equals(ciEnv::current()->Object_klass()) && !tp->klass_is_exact()) { + return TypeAryPtr::make(ptr, _ary, _klass, _klass_is_exact, offset, instance_id, speculative); } else { // cannot subclass, so the meet has to fall badly below the centerline ptr = NotNull; instance_id = InstanceBot; - return TypeInstPtr::make( ptr, ciEnv::current()->Object_klass(), false, NULL,offset, instance_id); + return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), false, NULL,offset, instance_id, speculative); } case Constant: case NotNull: @@ -3722,10 +3910,13 @@ if (above_centerline(tp->ptr())) { // If 'tp' is above the centerline and it is Object class // then we can subclass in the Java class hierarchy. - if( tp->klass()->equals(ciEnv::current()->Object_klass()) ) { + // For instances when a subclass meets a superclass we fall + // below the centerline when the superclass is exact. We need + // to do the same here. + if (tp->klass()->equals(ciEnv::current()->Object_klass()) && !tp->klass_is_exact()) { // that is, my array type is a subtype of 'tp' klass - return make( ptr, (ptr == Constant ? const_oop() : NULL), - _ary, _klass, _klass_is_exact, offset, instance_id ); + return make(ptr, (ptr == Constant ? const_oop() : NULL), + _ary, _klass, _klass_is_exact, offset, instance_id, speculative); } } // The other case cannot happen, since t cannot be a subtype of an array. @@ -3733,7 +3924,7 @@ if( ptr == Constant ) ptr = NotNull; instance_id = InstanceBot; - return TypeInstPtr::make( ptr, ciEnv::current()->Object_klass(), false, NULL,offset, instance_id); + return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), false, NULL,offset, instance_id, speculative); default: typerr(t); } } @@ -3744,7 +3935,7 @@ //------------------------------xdual------------------------------------------ // Dual: compute field-by-field dual const Type *TypeAryPtr::xdual() const { - return new TypeAryPtr( dual_ptr(), _const_oop, _ary->dual()->is_ary(),_klass, _klass_is_exact, dual_offset(), dual_instance_id(), is_autobox_cache() ); + return new TypeAryPtr(dual_ptr(), _const_oop, _ary->dual()->is_ary(),_klass, _klass_is_exact, dual_offset(), dual_instance_id(), is_autobox_cache(), dual_speculative()); } //----------------------interface_vs_oop--------------------------------------- @@ -3796,6 +3987,8 @@ st->print(",iid=top"); else if (_instance_id != InstanceBot) st->print(",iid=%d",_instance_id); + + dump_speculative(st); } #endif @@ -3805,10 +3998,13 @@ } //------------------------------add_offset------------------------------------- -const TypePtr *TypeAryPtr::add_offset( intptr_t offset ) const { - return make( _ptr, _const_oop, _ary, _klass, _klass_is_exact, xadd_offset(offset), _instance_id ); -} - +const TypePtr *TypeAryPtr::add_offset(intptr_t offset) const { + return make(_ptr, _const_oop, _ary, _klass, _klass_is_exact, xadd_offset(offset), _instance_id, add_offset_speculative(offset)); +} + +const TypeOopPtr *TypeAryPtr::remove_speculative() const { + return make(_ptr, _const_oop, _ary, _klass, _klass_is_exact, _offset, _instance_id, NULL); +} //============================================================================= diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/opto/type.hpp --- a/src/share/vm/opto/type.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/opto/type.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -159,6 +159,11 @@ // Table for efficient dualing of base types static const TYPES dual_type[lastype]; +#ifdef ASSERT + // One type is interface, the other is oop + virtual bool interface_vs_oop_helper(const Type *t) const; +#endif + protected: // Each class of type is also identified by its base. const TYPES _base; // Enum of Types type @@ -376,6 +381,9 @@ bool require_constant = false, bool is_autobox_cache = false); + // Speculative type. See TypeInstPtr + virtual ciKlass* speculative_type() const { return NULL; } + private: // support arrays static const BasicType _basic_type[]; @@ -585,6 +593,7 @@ static const TypeTuple *INT_PAIR; static const TypeTuple *LONG_PAIR; static const TypeTuple *INT_CC_PAIR; + static const TypeTuple *LONG_CC_PAIR; #ifndef PRODUCT virtual void dump2( Dict &d, uint, outputStream *st ) const; // Specialized per-Type dumping #endif @@ -784,7 +793,7 @@ // Some kind of oop (Java pointer), either klass or instance or array. class TypeOopPtr : public TypePtr { protected: - TypeOopPtr( TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id ); + TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, const TypeOopPtr* speculative); public: virtual bool eq( const Type *t ) const; virtual int hash() const; // Type specific hashing @@ -810,11 +819,27 @@ // This is the the node index of the allocation node creating this instance. int _instance_id; + // Extra type information profiling gave us. We propagate it the + // same way the rest of the type info is propagated. If we want to + // use it, then we have to emit a guard: this part of the type is + // not something we know but something we speculate about the type. + const TypeOopPtr* _speculative; + static const TypeOopPtr* make_from_klass_common(ciKlass* klass, bool klass_change, bool try_for_exact); int dual_instance_id() const; int meet_instance_id(int uid) const; + // utility methods to work on the speculative part of the type + const TypeOopPtr* dual_speculative() const; + const TypeOopPtr* meet_speculative(const TypeOopPtr* other) const; + bool eq_speculative(const TypeOopPtr* other) const; + int hash_speculative() const; + const TypeOopPtr* add_offset_speculative(intptr_t offset) const; +#ifndef PRODUCT + void dump_speculative(outputStream *st) const; +#endif + public: // Creates a type given a klass. Correctly handles multi-dimensional arrays // Respects UseUniqueSubclasses. @@ -841,7 +866,7 @@ bool not_null_elements = false); // Make a generic (unclassed) pointer to an oop. - static const TypeOopPtr* make(PTR ptr, int offset, int instance_id); + static const TypeOopPtr* make(PTR ptr, int offset, int instance_id, const TypeOopPtr* speculative); ciObject* const_oop() const { return _const_oop; } virtual ciKlass* klass() const { return _klass; } @@ -855,6 +880,7 @@ bool is_known_instance() const { return _instance_id > 0; } int instance_id() const { return _instance_id; } bool is_known_instance_field() const { return is_known_instance() && _offset >= 0; } + const TypeOopPtr* speculative() const { return _speculative; } virtual intptr_t get_con() const; @@ -868,9 +894,13 @@ const TypeKlassPtr* as_klass_type() const; virtual const TypePtr *add_offset( intptr_t offset ) const; + // Return same type without a speculative part + virtual const TypeOopPtr* remove_speculative() const; - virtual const Type *xmeet( const Type *t ) const; + virtual const Type *xmeet(const Type *t) const; virtual const Type *xdual() const; // Compute dual right now. + // the core of the computation of the meet for TypeOopPtr and for its subclasses + virtual const Type *xmeet_helper(const Type *t) const; // Do not allow interface-vs.-noninterface joins to collapse to top. virtual const Type *filter( const Type *kills ) const; @@ -880,13 +910,24 @@ #ifndef PRODUCT virtual void dump2( Dict &d, uint depth, outputStream *st ) const; #endif + + // Return the speculative type if any + ciKlass* speculative_type() const { + if (_speculative != NULL) { + const TypeOopPtr* speculative = _speculative->join(this)->is_oopptr(); + if (speculative->klass_is_exact()) { + return speculative->klass(); + } + } + return NULL; + } }; //------------------------------TypeInstPtr------------------------------------ // Class of Java object pointers, pointing either to non-array Java instances // or to a Klass* (including array klasses). class TypeInstPtr : public TypeOopPtr { - TypeInstPtr( PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id ); + TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, const TypeOopPtr* speculative); virtual bool eq( const Type *t ) const; virtual int hash() const; // Type specific hashing @@ -899,30 +940,30 @@ // Make a pointer to a constant oop. static const TypeInstPtr *make(ciObject* o) { - return make(TypePtr::Constant, o->klass(), true, o, 0); + return make(TypePtr::Constant, o->klass(), true, o, 0, InstanceBot); } // Make a pointer to a constant oop with offset. static const TypeInstPtr *make(ciObject* o, int offset) { - return make(TypePtr::Constant, o->klass(), true, o, offset); + return make(TypePtr::Constant, o->klass(), true, o, offset, InstanceBot); } // Make a pointer to some value of type klass. static const TypeInstPtr *make(PTR ptr, ciKlass* klass) { - return make(ptr, klass, false, NULL, 0); + return make(ptr, klass, false, NULL, 0, InstanceBot); } // Make a pointer to some non-polymorphic value of exactly type klass. static const TypeInstPtr *make_exact(PTR ptr, ciKlass* klass) { - return make(ptr, klass, true, NULL, 0); + return make(ptr, klass, true, NULL, 0, InstanceBot); } // Make a pointer to some value of type klass with offset. static const TypeInstPtr *make(PTR ptr, ciKlass* klass, int offset) { - return make(ptr, klass, false, NULL, offset); + return make(ptr, klass, false, NULL, offset, InstanceBot); } // Make a pointer to an oop. - static const TypeInstPtr *make(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id = InstanceBot ); + static const TypeInstPtr *make(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id = InstanceBot, const TypeOopPtr* speculative = NULL); /** Create constant type for a constant boxed value */ const Type* get_const_boxed_value() const; @@ -939,8 +980,11 @@ virtual const TypeOopPtr *cast_to_instance_id(int instance_id) const; virtual const TypePtr *add_offset( intptr_t offset ) const; + // Return same type without a speculative part + virtual const TypeOopPtr* remove_speculative() const; - virtual const Type *xmeet( const Type *t ) const; + // the core of the computation of the meet of 2 types + virtual const Type *xmeet_helper(const Type *t) const; virtual const TypeInstPtr *xmeet_unloaded( const TypeInstPtr *t ) const; virtual const Type *xdual() const; // Compute dual right now. @@ -959,8 +1003,8 @@ // Class of Java array pointers class TypeAryPtr : public TypeOopPtr { TypeAryPtr( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, - int offset, int instance_id, bool is_autobox_cache ) - : TypeOopPtr(AryPtr,ptr,k,xk,o,offset, instance_id), + int offset, int instance_id, bool is_autobox_cache, const TypeOopPtr* speculative) + : TypeOopPtr(AryPtr,ptr,k,xk,o,offset, instance_id, speculative), _ary(ary), _is_autobox_cache(is_autobox_cache) { @@ -998,9 +1042,9 @@ bool is_autobox_cache() const { return _is_autobox_cache; } - static const TypeAryPtr *make( PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot); + static const TypeAryPtr *make( PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot, const TypeOopPtr* speculative = NULL); // Constant pointer to array - static const TypeAryPtr *make( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot, bool is_autobox_cache = false); + static const TypeAryPtr *make( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot, const TypeOopPtr* speculative = NULL, bool is_autobox_cache = false); // Return a 'ptr' version of this type virtual const Type *cast_to_ptr_type(PTR ptr) const; @@ -1014,8 +1058,11 @@ virtual bool empty(void) const; // TRUE if type is vacuous virtual const TypePtr *add_offset( intptr_t offset ) const; + // Return same type without a speculative part + virtual const TypeOopPtr* remove_speculative() const; - virtual const Type *xmeet( const Type *t ) const; + // the core of the computation of the meet of 2 types + virtual const Type *xmeet_helper(const Type *t) const; virtual const Type *xdual() const; // Compute dual right now. const TypeAryPtr* cast_to_stable(bool stable, int stable_dimension = 1) const; diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/prims/jni.cpp --- a/src/share/vm/prims/jni.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/prims/jni.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -5059,6 +5059,8 @@ void TestReserveMemorySpecial_test(); void TestVirtualSpace_test(); void TestMetaspaceAux_test(); +void TestMetachunk_test(); +void TestVirtualSpaceNode_test(); #if INCLUDE_ALL_GCS void TestG1BiasedArray_test(); #endif @@ -5070,6 +5072,8 @@ run_unit_test(TestReserveMemorySpecial_test()); run_unit_test(TestVirtualSpace_test()); run_unit_test(TestMetaspaceAux_test()); + run_unit_test(TestMetachunk_test()); + run_unit_test(TestVirtualSpaceNode_test()); run_unit_test(GlobalDefinitions::test_globals()); run_unit_test(GCTimerAllTest::all()); run_unit_test(arrayOopDesc::test_max_array_length()); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/prims/jvmtiEnv.cpp --- a/src/share/vm/prims/jvmtiEnv.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/prims/jvmtiEnv.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -259,8 +259,7 @@ // bytes to the InstanceKlass here because they have not been // validated and we're not at a safepoint. constantPoolHandle constants(current_thread, ikh->constants()); - oop cplock = constants->lock(); - ObjectLocker ol(cplock, current_thread, cplock != NULL); // lock constant pool while we query it + MonitorLockerEx ml(constants->lock()); // lock constant pool while we query it JvmtiClassFileReconstituter reconstituter(ikh); if (reconstituter.get_error() != JVMTI_ERROR_NONE) { @@ -2418,8 +2417,7 @@ instanceKlassHandle ikh(thread, k_oop); constantPoolHandle constants(thread, ikh->constants()); - oop cplock = constants->lock(); - ObjectLocker ol(cplock, thread, cplock != NULL); // lock constant pool while we query it + MonitorLockerEx ml(constants->lock()); // lock constant pool while we query it JvmtiConstantPoolReconstituter reconstituter(ikh); if (reconstituter.get_error() != JVMTI_ERROR_NONE) { diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/prims/jvmtiImpl.cpp --- a/src/share/vm/prims/jvmtiImpl.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/prims/jvmtiImpl.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -225,18 +225,20 @@ _method = NULL; _bci = 0; _class_loader = NULL; -#ifdef CHECK_UNHANDLED_OOPS - // This one is always allocated with new, but check it just in case. - Thread *thread = Thread::current(); - if (thread->is_in_stack((address)&_method)) { - thread->allow_unhandled_oop((oop*)&_method); - } -#endif // CHECK_UNHANDLED_OOPS } JvmtiBreakpoint::JvmtiBreakpoint(Method* m_method, jlocation location) { _method = m_method; _class_loader = _method->method_holder()->class_loader_data()->class_loader(); +#ifdef CHECK_UNHANDLED_OOPS + // _class_loader can't be wrapped in a Handle, because JvmtiBreakpoint:s are + // eventually allocated on the heap. + // + // The code handling JvmtiBreakpoint:s allocated on the stack can't be + // interrupted by a GC until _class_loader is reachable by the GC via the + // oops_do method. + Thread::current()->allow_unhandled_oop(&_class_loader); +#endif // CHECK_UNHANDLED_OOPS assert(_method != NULL, "_method != NULL"); _bci = (int) location; assert(_bci >= 0, "_bci >= 0"); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/prims/methodHandles.cpp --- a/src/share/vm/prims/methodHandles.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/prims/methodHandles.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -1194,9 +1194,7 @@ } else if (vmtarget->is_klass()) { x = ((Klass*) vmtarget)->java_mirror(); } else if (vmtarget->is_method()) { - Handle mname2 = MethodHandles::new_MemberName(CHECK_NULL); - CallInfo info((Method*)vmtarget); - x = MethodHandles::init_method_MemberName(mname2, info); + x = mname(); } result->obj_at_put(1, x); return JNIHandles::make_local(env, result()); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/runtime/arguments.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -1957,12 +1957,6 @@ "please refer to the release notes for the combinations " "allowed\n"); status = false; - } else if (ReservedCodeCacheSize > 2*G) { - // Code cache size larger than MAXINT is not supported. - jio_fprintf(defaultStream::error_stream(), - "Invalid ReservedCodeCacheSize=%dM. Must be at most %uM.\n", ReservedCodeCacheSize/M, - (2*G)/M); - status = false; } return status; } @@ -2694,8 +2688,9 @@ FLAG_SET_CMDLINE(uintx, MaxHeapSize, (uintx)long_max_heap_size); // Xmaxf } else if (match_option(option, "-Xmaxf", &tail)) { - int maxf = (int)(atof(tail) * 100); - if (maxf < 0 || maxf > 100) { + char* err; + int maxf = (int)(strtod(tail, &err) * 100); + if (*err != '\0' || maxf < 0 || maxf > 100) { jio_fprintf(defaultStream::error_stream(), "Bad max heap free percentage size: %s\n", option->optionString); @@ -2705,8 +2700,9 @@ } // Xminf } else if (match_option(option, "-Xminf", &tail)) { - int minf = (int)(atof(tail) * 100); - if (minf < 0 || minf > 100) { + char* err; + int minf = (int)(strtod(tail, &err) * 100); + if (*err != '\0' || minf < 0 || minf > 100) { jio_fprintf(defaultStream::error_stream(), "Bad min heap free percentage size: %s\n", option->optionString); @@ -3719,6 +3715,18 @@ // incremental inlining: bump MaxNodeLimit FLAG_SET_DEFAULT(MaxNodeLimit, (intx)75000); } + if (!UseTypeSpeculation && FLAG_IS_DEFAULT(TypeProfileLevel)) { + // nothing to use the profiling, turn if off + FLAG_SET_DEFAULT(TypeProfileLevel, 0); + } + if (UseTypeSpeculation && FLAG_IS_DEFAULT(ReplaceInParentMaps)) { + // Doing the replace in parent maps helps speculation + FLAG_SET_DEFAULT(ReplaceInParentMaps, true); + } +#ifndef X86 + // Only on x86 for now + FLAG_SET_DEFAULT(TypeProfileLevel, 0); +#endif #endif if (PrintAssembly && FLAG_IS_DEFAULT(DebugNonSafepoints)) { diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/runtime/globals.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -1979,13 +1979,6 @@ develop(uintx, MetadataAllocationFailALotInterval, 1000, \ "Metadata allocation failure a lot interval") \ \ - develop(bool, MetaDataDeallocateALot, false, \ - "Deallocation bunches of metadata at intervals controlled by " \ - "MetaDataAllocateALotInterval") \ - \ - develop(uintx, MetaDataDeallocateALotInterval, 100, \ - "Metadata deallocation alot interval") \ - \ develop(bool, TraceMetadataChunkAllocation, false, \ "Trace chunk metadata allocations") \ \ @@ -2175,7 +2168,7 @@ "Minimum ratio of young generation/survivor space size") \ \ product(uintx, InitialSurvivorRatio, 8, \ - "Initial ratio of eden/survivor space size") \ + "Initial ratio of young generation/survivor space size") \ \ product(uintx, BaseFootPrintEstimate, 256*M, \ "Estimate of footprint other than Java Heap") \ @@ -2677,6 +2670,19 @@ product(bool, AggressiveOpts, false, \ "Enable aggressive optimizations - see arguments.cpp") \ \ + product_pd(uintx, TypeProfileLevel, \ + "=XYZ, with Z: Type profiling of arguments at call; " \ + "Y: Type profiling of return value at call; " \ + "X: Type profiling of parameters to methods; " \ + "X, Y and Z in 0=off ; 1=jsr292 only; 2=all methods") \ + \ + product(intx, TypeProfileArgsLimit, 2, \ + "max number of call arguments to consider for type profiling") \ + \ + product(intx, TypeProfileParmsLimit, 2, \ + "max number of incoming parameters to consider for type profiling"\ + ", -1 for all") \ + \ /* statistics */ \ develop(bool, CountCompiledCalls, false, \ "Count method invocations") \ @@ -3125,10 +3131,14 @@ "class pointers are used") \ \ product(uintx, MinHeapFreeRatio, 40, \ - "The minimum percentage of heap free after GC to avoid expansion")\ + "The minimum percentage of heap free after GC to avoid expansion."\ + " For most GCs this applies to the old generation. In G1 it" \ + " applies to the whole heap. Not supported by ParallelGC.") \ \ product(uintx, MaxHeapFreeRatio, 70, \ - "The maximum percentage of heap free after GC to avoid shrinking")\ + "The maximum percentage of heap free after GC to avoid shrinking."\ + " For most GCs this applies to the old generation. In G1 it" \ + " applies to the whole heap. Not supported by ParallelGC.") \ \ product(intx, SoftRefLRUPolicyMSPerMB, 1000, \ "Number of milliseconds per MB of free space in the heap") \ @@ -3823,7 +3833,6 @@ product(bool, UseLockedTracing, false, \ "Use locked-tracing when doing event-based tracing") - /* * Macros for factoring of globals */ diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/runtime/java.cpp --- a/src/share/vm/runtime/java.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/runtime/java.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -183,6 +183,7 @@ collected_profiled_methods->sort(&compare_methods); int count = collected_profiled_methods->length(); + int total_size = 0; if (count > 0) { for (int index = 0; index < count; index++) { Method* m = collected_profiled_methods->at(index); @@ -190,10 +191,18 @@ tty->print_cr("------------------------------------------------------------------------"); //m->print_name(tty); m->print_invocation_count(); + tty->print_cr(" mdo size: %d bytes", m->method_data()->size_in_bytes()); tty->cr(); + // Dump data on parameters if any + if (m->method_data() != NULL && m->method_data()->parameters_type_data() != NULL) { + tty->fill_to(2); + m->method_data()->parameters_type_data()->print_data_on(tty); + } m->print_codes(); + total_size += m->method_data()->size_in_bytes(); } tty->print_cr("------------------------------------------------------------------------"); + tty->print_cr("Total MDO size: %d bytes", total_size); } } diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/runtime/signature.cpp --- a/src/share/vm/runtime/signature.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/runtime/signature.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -378,6 +378,16 @@ return result; } +int SignatureStream::reference_parameter_count() { + int args_count = 0; + for ( ; !at_return_type(); next()) { + if (is_object()) { + args_count++; + } + } + return args_count; +} + bool SignatureVerifier::is_valid_signature(Symbol* sig) { const char* signature = (const char*)sig->bytes(); ssize_t len = sig->utf8_length(); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/runtime/signature.hpp --- a/src/share/vm/runtime/signature.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/runtime/signature.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -401,6 +401,9 @@ // return same as_symbol except allocation of new symbols is avoided. Symbol* as_symbol_or_null(); + + // count the number of references in the signature + int reference_parameter_count(); }; class SignatureVerifier : public StackObj { diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/runtime/thread.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -1454,7 +1454,6 @@ _interp_only_mode = 0; _special_runtime_exit_condition = _no_async_condition; _pending_async_exception = NULL; - _is_compiling = false; _thread_stat = NULL; _thread_stat = new ThreadStatistics(); _blocked_on_compilation = false; @@ -1815,7 +1814,8 @@ // Call Thread.exit(). We try 3 times in case we got another Thread.stop during // the execution of the method. If that is not enough, then we don't really care. Thread.stop // is deprecated anyhow. - { int count = 3; + if (!is_Compiler_thread()) { + int count = 3; while (java_lang_Thread::threadGroup(threadObj()) != NULL && (count-- > 0)) { EXCEPTION_MARK; JavaValue result(T_VOID); @@ -1828,7 +1828,6 @@ CLEAR_PENDING_EXCEPTION; } } - // notify JVMTI if (JvmtiExport::should_post_thread_life()) { JvmtiExport::post_thread_end(this); @@ -3239,6 +3238,7 @@ _counters = counters; _buffer_blob = NULL; _scanned_nmethod = NULL; + _compiler = NULL; #ifndef PRODUCT _ideal_graph_printer = NULL; @@ -3255,6 +3255,7 @@ } } + // ======= Threads ======== // The Threads class links together all active threads, and provides @@ -3275,8 +3276,6 @@ // All JavaThreads #define ALL_JAVA_THREADS(X) for (JavaThread* X = _thread_list; X; X = X->next()) -void os_stream(); - // All JavaThreads + all non-JavaThreads (i.e., every thread in the system) void Threads::threads_do(ThreadClosure* tc) { assert_locked_or_safepoint(Threads_lock); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/runtime/thread.hpp --- a/src/share/vm/runtime/thread.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/runtime/thread.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -923,9 +923,6 @@ volatile address _exception_handler_pc; // PC for handler of exception volatile int _is_method_handle_return; // true (== 1) if the current exception PC is a MethodHandle call site. - // support for compilation - bool _is_compiling; // is true if a compilation is active inthis thread (one compilation per thread possible) - // support for JNI critical regions jint _jni_active_critical; // count of entries into JNI critical region @@ -1005,10 +1002,6 @@ // Testers virtual bool is_Java_thread() const { return true; } - // compilation - void set_is_compiling(bool f) { _is_compiling = f; } - bool is_compiling() const { return _is_compiling; } - // Thread chain operations JavaThread* next() const { return _next; } void set_next(JavaThread* p) { _next = p; } @@ -1283,6 +1276,11 @@ void set_exception_handler_pc(address a) { _exception_handler_pc = a; } void set_is_method_handle_return(bool value) { _is_method_handle_return = value ? 1 : 0; } + void clear_exception_oop_and_pc() { + set_exception_oop(NULL); + set_exception_pc(NULL); + } + // Stack overflow support inline size_t stack_available(address cur_sp); address stack_yellow_zone_base() @@ -1811,13 +1809,14 @@ private: CompilerCounters* _counters; - ciEnv* _env; - CompileLog* _log; - CompileTask* _task; - CompileQueue* _queue; - BufferBlob* _buffer_blob; + ciEnv* _env; + CompileLog* _log; + CompileTask* _task; + CompileQueue* _queue; + BufferBlob* _buffer_blob; - nmethod* _scanned_nmethod; // nmethod being scanned by the sweeper + nmethod* _scanned_nmethod; // nmethod being scanned by the sweeper + AbstractCompiler* _compiler; public: @@ -1829,14 +1828,17 @@ // Hide this compiler thread from external view. bool is_hidden_from_external_view() const { return true; } - CompileQueue* queue() { return _queue; } - CompilerCounters* counters() { return _counters; } + void set_compiler(AbstractCompiler* c) { _compiler = c; } + AbstractCompiler* compiler() const { return _compiler; } + + CompileQueue* queue() const { return _queue; } + CompilerCounters* counters() const { return _counters; } // Get/set the thread's compilation environment. ciEnv* env() { return _env; } void set_env(ciEnv* env) { _env = env; } - BufferBlob* get_buffer_blob() { return _buffer_blob; } + BufferBlob* get_buffer_blob() const { return _buffer_blob; } void set_buffer_blob(BufferBlob* b) { _buffer_blob = b; }; // Get/set the thread's logging information diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/runtime/vmStructs.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -58,7 +58,7 @@ #include "memory/generation.hpp" #include "memory/generationSpec.hpp" #include "memory/heap.hpp" -#include "memory/metablock.hpp" +#include "memory/metachunk.hpp" #include "memory/referenceType.hpp" #include "memory/space.hpp" #include "memory/tenuredGeneration.hpp" @@ -917,7 +917,6 @@ volatile_nonstatic_field(JavaThread, _exception_oop, oop) \ volatile_nonstatic_field(JavaThread, _exception_pc, address) \ volatile_nonstatic_field(JavaThread, _is_method_handle_return, int) \ - nonstatic_field(JavaThread, _is_compiling, bool) \ nonstatic_field(JavaThread, _special_runtime_exit_condition, JavaThread::AsyncRequests) \ nonstatic_field(JavaThread, _saved_exception_pc, address) \ volatile_nonstatic_field(JavaThread, _thread_state, JavaThreadState) \ @@ -1465,6 +1464,7 @@ declare_toplevel_type(CheckedExceptionElement) \ declare_toplevel_type(LocalVariableTableElement) \ declare_toplevel_type(ExceptionTableElement) \ + declare_toplevel_type(MethodParametersElement) \ \ declare_toplevel_type(ClassLoaderData) \ declare_toplevel_type(ClassLoaderDataGraph) \ @@ -1939,7 +1939,13 @@ declare_c2_type(CmpDNode, CmpNode) \ declare_c2_type(CmpD3Node, CmpDNode) \ declare_c2_type(MathExactNode, MultiNode) \ - declare_c2_type(AddExactINode, MathExactNode) \ + declare_c2_type(MathExactINode, MathExactNode) \ + declare_c2_type(AddExactINode, MathExactINode) \ + declare_c2_type(AddExactLNode, MathExactLNode) \ + declare_c2_type(SubExactINode, MathExactINode) \ + declare_c2_type(SubExactLNode, MathExactLNode) \ + declare_c2_type(NegExactINode, MathExactINode) \ + declare_c2_type(MulExactINode, MathExactINode) \ declare_c2_type(FlagsProjNode, ProjNode) \ declare_c2_type(BoolNode, Node) \ declare_c2_type(AbsNode, Node) \ @@ -2337,6 +2343,7 @@ declare_constant(ConstMethod::_has_localvariable_table) \ declare_constant(ConstMethod::_has_exception_table) \ declare_constant(ConstMethod::_has_generic_signature) \ + declare_constant(ConstMethod::_has_method_parameters) \ declare_constant(ConstMethod::_has_method_annotations) \ declare_constant(ConstMethod::_has_parameter_annotations) \ declare_constant(ConstMethod::_has_default_annotations) \ diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/services/diagnosticCommand.cpp --- a/src/share/vm/services/diagnosticCommand.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/services/diagnosticCommand.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -505,7 +505,11 @@ _jdp_pause ("jdp.pause", - "set com.sun.management.jdp.pause", "INT", false) + "set com.sun.management.jdp.pause", "INT", false), + + _jdp_name + ("jdp.name", + "set com.sun.management.jdp.name", "STRING", false) { _dcmdparser.add_dcmd_option(&_config_file); @@ -527,6 +531,7 @@ _dcmdparser.add_dcmd_option(&_jdp_source_addr); _dcmdparser.add_dcmd_option(&_jdp_ttl); _dcmdparser.add_dcmd_option(&_jdp_pause); + _dcmdparser.add_dcmd_option(&_jdp_name); } @@ -596,6 +601,7 @@ PUT_OPTION(_jdp_source_addr); PUT_OPTION(_jdp_ttl); PUT_OPTION(_jdp_pause); + PUT_OPTION(_jdp_name); #undef PUT_OPTION diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/services/diagnosticCommand.hpp --- a/src/share/vm/services/diagnosticCommand.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/services/diagnosticCommand.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -302,6 +302,7 @@ DCmdArgument _jdp_source_addr; DCmdArgument _jdp_ttl; DCmdArgument _jdp_pause; + DCmdArgument _jdp_name; public: JMXStartRemoteDCmd(outputStream *output, bool heap_allocated); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/services/heapDumper.cpp --- a/src/share/vm/services/heapDumper.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/services/heapDumper.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -1545,7 +1545,9 @@ // writes a HPROF_GC_CLASS_DUMP record for the given class void VM_HeapDumper::do_class_dump(Klass* k) { - DumperSupport::dump_class_and_array_classes(writer(), k); + if (k->oop_is_instance()) { + DumperSupport::dump_class_and_array_classes(writer(), k); + } } // writes a HPROF_GC_CLASS_DUMP records for a given basic type @@ -1722,7 +1724,7 @@ SymbolTable::symbols_do(&sym_dumper); // write HPROF_LOAD_CLASS records - SystemDictionary::classes_do(&do_load_class); + ClassLoaderDataGraph::classes_do(&do_load_class); Universe::basic_type_classes_do(&do_load_class); // write HPROF_FRAME and HPROF_TRACE records @@ -1733,7 +1735,7 @@ write_dump_header(); // Writes HPROF_GC_CLASS_DUMP records - SystemDictionary::classes_do(&do_class_dump); + ClassLoaderDataGraph::classes_do(&do_class_dump); Universe::basic_type_classes_do(&do_basic_type_array_class_dump); check_segment_length(); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/services/runtimeService.cpp --- a/src/share/vm/services/runtimeService.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/services/runtimeService.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, 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 @@ -119,7 +119,7 @@ #endif /* USDT2 */ // Print the time interval in which the app was executing - if (PrintGCApplicationConcurrentTime) { + if (PrintGCApplicationConcurrentTime && _app_timer.is_updated()) { gclog_or_tty->date_stamp(PrintGCDateStamps); gclog_or_tty->stamp(PrintGCTimeStamps); gclog_or_tty->print_cr("Application time: %3.7f seconds", diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/shark/sharkCompiler.cpp --- a/src/share/vm/shark/sharkCompiler.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/shark/sharkCompiler.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -133,11 +133,10 @@ exit(1); } - execution_engine()->addModule( - _native_context->module()); + execution_engine()->addModule(_native_context->module()); // All done - mark_initialized(); + set_state(initialized); } void SharkCompiler::initialize() { diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/shark/sharkCompiler.hpp --- a/src/share/vm/shark/sharkCompiler.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/shark/sharkCompiler.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -50,10 +50,6 @@ return ! (method->is_method_handle_intrinsic() || method->is_compiled_lambda_form()); } - // Customization - bool needs_adapters() { return false; } - bool needs_stubs() { return false; } - // Initialization void initialize(); diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/trace/traceEventClasses.xsl --- a/src/share/vm/trace/traceEventClasses.xsl Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/trace/traceEventClasses.xsl Sun Nov 03 07:50:24 2013 +0000 @@ -23,8 +23,8 @@ --> + - diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/trace/traceEventIds.xsl --- a/src/share/vm/trace/traceEventIds.xsl Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/trace/traceEventIds.xsl Sun Nov 03 07:50:24 2013 +0000 @@ -23,8 +23,8 @@ --> + - diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/trace/traceTypes.xsl --- a/src/share/vm/trace/traceTypes.xsl Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/trace/traceTypes.xsl Sun Nov 03 07:50:24 2013 +0000 @@ -23,8 +23,8 @@ --> + - diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/utilities/constantTag.cpp --- a/src/share/vm/utilities/constantTag.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/utilities/constantTag.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -51,7 +51,9 @@ case JVM_CONSTANT_ClassIndex : case JVM_CONSTANT_StringIndex : case JVM_CONSTANT_MethodHandle : + case JVM_CONSTANT_MethodHandleInError : case JVM_CONSTANT_MethodType : + case JVM_CONSTANT_MethodTypeInError : return T_OBJECT; default: ShouldNotReachHere(); @@ -60,6 +62,19 @@ } +jbyte constantTag::non_error_value() const { + switch (_tag) { + case JVM_CONSTANT_UnresolvedClassInError: + return JVM_CONSTANT_UnresolvedClass; + case JVM_CONSTANT_MethodHandleInError: + return JVM_CONSTANT_MethodHandle; + case JVM_CONSTANT_MethodTypeInError: + return JVM_CONSTANT_MethodType; + default: + return _tag; + } +} + const char* constantTag::internal_name() const { switch (_tag) { diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/utilities/constantTag.hpp --- a/src/share/vm/utilities/constantTag.hpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/utilities/constantTag.hpp Sun Nov 03 07:50:24 2013 +0000 @@ -108,7 +108,8 @@ _tag = tag; } - jbyte value() { return _tag; } + jbyte value() const { return _tag; } + jbyte non_error_value() const; BasicType basic_type() const; // if used with ldc, what kind of value gets pushed? diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/utilities/ostream.cpp --- a/src/share/vm/utilities/ostream.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/utilities/ostream.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -465,7 +465,7 @@ } // log_name comes from -XX:LogFile=log_name or -Xloggc:log_name -// in log_name, %p => pipd1234 and +// in log_name, %p => pid1234 and // %t => YYYY-MM-DD_HH-MM-SS static const char* make_log_name(const char* log_name, const char* force_directory) { char timestr[32]; @@ -792,7 +792,7 @@ void defaultStream::init_log() { // %%% Need a MutexLocker? - const char* log_name = LogFile != NULL ? LogFile : "hotspot_pid%p.log"; + const char* log_name = LogFile != NULL ? LogFile : "hotspot_%p.log"; const char* try_name = make_log_name(log_name, NULL); fileStream* file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name); if (!file->is_open()) { diff -r 6795fcebbf42 -r c31f0cbe6d9e src/share/vm/utilities/vmError.cpp --- a/src/share/vm/utilities/vmError.cpp Mon Oct 21 14:08:09 2013 +0100 +++ b/src/share/vm/utilities/vmError.cpp Sun Nov 03 07:50:24 2013 +0000 @@ -1050,7 +1050,7 @@ FILE* replay_data_file = os::open(fd, "w"); if (replay_data_file != NULL) { fileStream replay_data_stream(replay_data_file, /*need_close=*/true); - env->dump_replay_data(&replay_data_stream); + env->dump_replay_data_unsafe(&replay_data_stream); out.print_raw("#\n# Compiler replay data is saved as:\n# "); out.print_raw_cr(buffer); } else { diff -r 6795fcebbf42 -r c31f0cbe6d9e test/TEST.groups --- a/test/TEST.groups Mon Oct 21 14:08:09 2013 +0100 +++ b/test/TEST.groups Sun Nov 03 07:50:24 2013 +0000 @@ -64,6 +64,7 @@ gc/TestG1ZeroPGCTJcmdThreadPrint.java \ gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java \ gc/metaspace/TestMetaspacePerfCounters.java \ + gc/metaspace/TestPerfCountersAndMemoryPools.java \ runtime/6819213/TestBootNativeLibraryPath.java \ runtime/6925573/SortMethodsTest.java \ runtime/7107135/Test7107135.sh \ @@ -101,7 +102,9 @@ needs_jre = \ compiler/6852078/Test6852078.java \ compiler/7047069/Test7047069.java \ - runtime/6294277/SourceDebugExtension.java + runtime/6294277/SourceDebugExtension.java \ + runtime/ClassFile/JsrRewriting.java \ + runtime/ClassFile/OomWhileParsingRepeatedJsr.java # Compact 3 adds further tests to compact2 # @@ -125,7 +128,7 @@ compiler/whitebox/IsMethodCompilableTest.java \ gc/6581734/Test6581734.java \ gc/7072527/TestFullGCCount.java \ - gc/7168848/HumongousAlloc.java \ + gc/g1/TestHumongousAllocInitialMark.java \ gc/arguments/TestG1HeapRegionSize.java \ gc/metaspace/TestMetaspaceMemoryPool.java \ runtime/InternalApi/ThreadCpuTimesDeadlock.java \ diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/8013496/Test8013496.sh --- a/test/compiler/8013496/Test8013496.sh Mon Oct 21 14:08:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2013, 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 8013496 -# @summary Test checks that the order in which ReversedCodeCacheSize and -# InitialCodeCacheSize are passed to the VM is irrelevant. -# @run shell Test8013496.sh -# -# -## some tests require path to find test source dir -if [ "${TESTSRC}" = "" ] -then - TESTSRC=${PWD} - echo "TESTSRC not set. Using "${TESTSRC}" as default" -fi -echo "TESTSRC=${TESTSRC}" -## Adding common setup Variables for running shell tests. -. ${TESTSRC}/../../test_env.sh -set -x - -${TESTJAVA}/bin/java ${TESTVMOPTS} -XX:ReservedCodeCacheSize=2m -XX:InitialCodeCacheSize=500K -version > 1.out 2>&1 -${TESTJAVA}/bin/java ${TESTVMOPTS} -XX:InitialCodeCacheSize=500K -XX:ReservedCodeCacheSize=2m -version > 2.out 2>&1 - -diff 1.out 2.out - -result=$? -if [ $result -eq 0 ] ; then - echo "Test Passed" - exit 0 -else - echo "Test Failed" - exit 1 -fi diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/codecache/CheckReservedInitialCodeCacheSizeArgOrder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/codecache/CheckReservedInitialCodeCacheSizeArgOrder.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013, 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 8013496 + * @summary Test checks that the order in which ReversedCodeCacheSize and + * InitialCodeCacheSize are passed to the VM is irrelevant. + * @library /testlibrary + * + */ +import com.oracle.java.testlibrary.*; + +public class CheckReservedInitialCodeCacheSizeArgOrder { + public static void main(String[] args) throws Exception { + ProcessBuilder pb1, pb2; + OutputAnalyzer out1, out2; + + pb1 = ProcessTools.createJavaProcessBuilder("-XX:InitialCodeCacheSize=4m", "-XX:ReservedCodeCacheSize=8m", "-version"); + pb2 = ProcessTools.createJavaProcessBuilder("-XX:ReservedCodeCacheSize=8m", "-XX:InitialCodeCacheSize=4m", "-version"); + + out1 = new OutputAnalyzer(pb1.start()); + out2 = new OutputAnalyzer(pb2.start()); + + // Check that the outputs are equal + if (out1.getStdout().compareTo(out2.getStdout()) != 0) { + throw new RuntimeException("Test failed"); + } + + out1.shouldHaveExitValue(0); + out2.shouldHaveExitValue(0); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/AddExactICondTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/AddExactICondTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013, 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 8024924 + * @summary Test non constant addExact + * @compile AddExactICondTest.java + * @run main AddExactICondTest + * + */ + +public class AddExactICondTest { + public static int result = 0; + + public static void main(String[] args) { + for (int i = 0; i < 50000; ++i) { + runTest(); + } + } + + public static void runTest() { + int i = 7; + while (java.lang.Math.addExact(i, result) < 89361) { + if ((java.lang.Math.addExact(i, i) & 1) == 1) { + i += 3; + } else if ((i & 5) == 4) { + i += 7; + } else if ((i & 0xf) == 6) { + i += 2; + } else { + i += 1; + } + result += 2; + } + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/AddExactIConstantTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/AddExactIConstantTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, 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 8024924 + * @summary Test constant addExact + * @compile AddExactIConstantTest.java Verify.java + * @run main AddExactIConstantTest + * + */ + +public class AddExactIConstantTest { + public static void main(String[] args) { + Verify.ConstantTest.verify(new Verify.AddExactI()); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/AddExactILoadTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/AddExactILoadTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2013, 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 8024924 + * @summary Test non constant addExact + * @compile AddExactILoadTest.java Verify.java + * @run main AddExactILoadTest + * + */ + +public class AddExactILoadTest { + public static void main(String[] args) { + Verify.LoadTest.init(); + Verify.LoadTest.verify(new Verify.AddExactI()); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/AddExactILoopDependentTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/AddExactILoopDependentTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, 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 8024924 + * @summary Test non constant addExact + * @compile AddExactILoopDependentTest.java Verify.java + * @run main AddExactILoopDependentTest + * + */ + +public class AddExactILoopDependentTest { + public static void main(String[] args) { + Verify.LoopDependentTest.verify(new Verify.AddExactI()); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/AddExactINonConstantTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/AddExactINonConstantTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, 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 8024924 + * @summary Test non constant addExact + * @compile AddExactINonConstantTest.java Verify.java + * @run main AddExactINonConstantTest + * + */ + +public class AddExactINonConstantTest { + public static void main(String[] args) { + Verify.NonConstantTest.verify(new Verify.AddExactI()); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/AddExactIRepeatTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/AddExactIRepeatTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2013, 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 8025657 + * @summary Test repeating addExact + * @compile AddExactIRepeatTest.java Verify.java + * @run main AddExactIRepeatTest + * + */ + +public class AddExactIRepeatTest { + public static void main(String[] args) { + runTest(new Verify.AddExactI()); + } + + public static int nonExact(int x, int y, Verify.BinaryMethod method) { + int result = method.unchecked(x, y); + result += method.unchecked(x, y); + result += method.unchecked(x, y); + result += method.unchecked(x, y); + return result; + } + + public static void runTest(Verify.BinaryMethod method) { + java.util.Random rnd = new java.util.Random(); + for (int i = 0; i < 50000; ++i) { + int x = Integer.MAX_VALUE - 10; + int y = Integer.MAX_VALUE - 10 + rnd.nextInt(5); + + int c = rnd.nextInt() / 2; + int d = rnd.nextInt() / 2; + + int a = catchingExact(x, y, method); + + if (a != 36) { + throw new RuntimeException("a != 36 : " + a); + } + + int b = nonExact(c, d, method); + int n = exact(c, d, method); + + + if (n != b) { + throw new RuntimeException("n != b : " + n + " != " + b); + } + } + } + + public static int exact(int x, int y, Verify.BinaryMethod method) { + int result = 0; + result += method.checkMethod(x, y); + result += method.checkMethod(x, y); + result += method.checkMethod(x, y); + result += method.checkMethod(x, y); + return result; + } + + public static int catchingExact(int x, int y, Verify.BinaryMethod method) { + int result = 0; + try { + result += 5; + result = method.checkMethod(x, y); + } catch (ArithmeticException e) { + result += 1; + } + try { + result += 6; + + result += method.checkMethod(x, y); + } catch (ArithmeticException e) { + result += 2; + } + try { + result += 7; + result += method.checkMethod(x, y); + } catch (ArithmeticException e) { + result += 3; + } + try { + result += 8; + result += method.checkMethod(x, y); + } catch (ArithmeticException e) { + result += 4; + } + return result; + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/AddExactLConstantTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/AddExactLConstantTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test constant addExact + * @compile AddExactLConstantTest.java Verify.java + * @run main AddExactLConstantTest + * + */ + +public class AddExactLConstantTest { + public static void main(String[] args) { + Verify.ConstantLongTest.verify(new Verify.AddExactL()); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/AddExactLNonConstantTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/AddExactLNonConstantTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test non constant addExact + * @compile AddExactLNonConstantTest.java Verify.java + * @run main AddExactLNonConstantTest + * + */ + +public class AddExactLNonConstantTest { + public static void main(String[] args) { + Verify.NonConstantLongTest.verify(new Verify.AddExactL()); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/CondTest.java --- a/test/compiler/intrinsics/mathexact/CondTest.java Mon Oct 21 14:08:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2013, 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 8024924 - * @summary Test non constant addExact - * @compile CondTest.java Verify.java - * @run main CondTest - * - */ - -import java.lang.ArithmeticException; - -public class CondTest { - public static int result = 0; - - public static void main(String[] args) { - for (int i = 0; i < 50000; ++i) { - runTest(); - } - } - - public static void runTest() { - int i = 7; - while (java.lang.Math.addExact(i, result) < 89361) { - if ((java.lang.Math.addExact(i, i) & 1) == 1) { - i += 3; - } else if ((i & 5) == 4) { - i += 7; - } else if ((i & 0xf) == 6) { - i += 2; - } else { - i += 1; - } - result += 2; - } - } -} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/ConstantTest.java --- a/test/compiler/intrinsics/mathexact/ConstantTest.java Mon Oct 21 14:08:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2013, 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 8024924 - * @summary Test constant addExact - * @compile ConstantTest.java Verify.java - * @run main ConstantTest - * - */ - -import java.lang.ArithmeticException; - -public class ConstantTest { - public static void main(String[] args) { - for (int i = 0; i < 50000; ++i) { - Verify.verify(5, 7); - Verify.verify(Integer.MAX_VALUE, 1); - Verify.verify(Integer.MIN_VALUE, -1); - Verify.verify(Integer.MAX_VALUE, -1); - Verify.verify(Integer.MIN_VALUE, 1); - Verify.verify(Integer.MAX_VALUE / 2, Integer.MAX_VALUE / 2); - Verify.verify(Integer.MAX_VALUE / 2, (Integer.MAX_VALUE / 2) + 3); - } - } -} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/DecExactITest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/DecExactITest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test decrementExact + * @compile DecExactITest.java Verify.java + * @run main DecExactITest + * + */ + +public class DecExactITest { + public static int[] values = {1, 1, 1, 1}; + public static int[] minvalues = {Integer.MIN_VALUE, Integer.MIN_VALUE}; + + public static void main(String[] args) { + runTest(new Verify.DecExactI()); + } + + public static void runTest(Verify.UnaryMethod method) { + for (int i = 0; i < 20000; ++i) { + Verify.verifyUnary(Integer.MIN_VALUE, method); + Verify.verifyUnary(minvalues[0], method); + Verify.verifyUnary(Integer.MIN_VALUE - values[2], method); + Verify.verifyUnary(0, method); + Verify.verifyUnary(values[2], method); + Verify.verifyUnary(Integer.MAX_VALUE, method); + Verify.verifyUnary(Integer.MIN_VALUE - values[0] + values[3], method); + Verify.verifyUnary(Integer.MIN_VALUE + 1 - values[0], method); + } + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/DecExactLTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/DecExactLTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test decrementExact + * @compile DecExactITest.java Verify.java + * @run main DecExactITest + * + */ + +public class DecExactLTest { + public static long[] values = {1, 1, 1, 1}; + public static long[] minvalues = {Long.MIN_VALUE, Long.MIN_VALUE}; + + public static void main(String[] args) { + runTest(new Verify.DecExactL()); + } + + public static void runTest(Verify.UnaryLongMethod method) { + for (int i = 0; i < 20000; ++i) { + Verify.verifyUnary(Long.MIN_VALUE, method); + Verify.verifyUnary(minvalues[0], method); + Verify.verifyUnary(Long.MIN_VALUE - values[2], method); + Verify.verifyUnary(0, method); + Verify.verifyUnary(values[2], method); + Verify.verifyUnary(Long.MAX_VALUE, method); + Verify.verifyUnary(Long.MIN_VALUE - values[0] + values[3], method); + Verify.verifyUnary(Long.MIN_VALUE + 1 - values[0], method); + } + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/IncExactITest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/IncExactITest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test incrementExact + * @compile IncExactITest.java Verify.java + * @run main IncExactITest + * + */ + + +public class IncExactITest { + public static int[] values = {1, 1, 1, 1}; + public static void main(String[] args) { + runTest(new Verify.IncExactI()); + } + + public static void runTest(Verify.UnaryMethod method) { + for (int i = 0; i < 20000; ++i) { + Verify.verifyUnary(Integer.MIN_VALUE, method); + Verify.verifyUnary(Integer.MAX_VALUE - 1, method); + Verify.verifyUnary(0, method); + Verify.verifyUnary(values[1], method); + Verify.verifyUnary(Integer.MAX_VALUE, method); + Verify.verifyUnary(Integer.MAX_VALUE - values[0] + values[3], method); + Verify.verifyUnary(Integer.MAX_VALUE - 1 + values[0], method); + } + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/IncExactLTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/IncExactLTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test incrementExact + * @compile IncExactLTest.java Verify.java + * @run main IncExactLTest + * + */ + +public class IncExactLTest { + public static long[] values = {1, 1, 1, 1}; + public static void main(String[] args) { + runTest(new Verify.IncExactL()); + } + + public static void runTest(Verify.UnaryLongMethod method) { + for (int i = 0; i < 20000; ++i) { + Verify.verifyUnary(Long.MIN_VALUE, method); + Verify.verifyUnary(Long.MAX_VALUE - 1, method); + Verify.verifyUnary(0, method); + Verify.verifyUnary(values[1], method); + Verify.verifyUnary(Long.MAX_VALUE, method); + Verify.verifyUnary(Long.MAX_VALUE - values[0] + values[3], method); + Verify.verifyUnary(Long.MAX_VALUE - 1 + values[0], method); + } + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/LoadTest.java --- a/test/compiler/intrinsics/mathexact/LoadTest.java Mon Oct 21 14:08:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2013, 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 8024924 - * @summary Test non constant addExact - * @compile LoadTest.java Verify.java - * @run main LoadTest - * - */ - -import java.lang.ArithmeticException; - -public class LoadTest { - public static java.util.Random rnd = new java.util.Random(); - public static int[] values = new int[256]; - - public static void main(String[] args) { - for (int i = 0; i < values.length; ++i) { - values[i] = rnd.nextInt(); - } - - for (int i = 0; i < 50000; ++i) { - Verify.verify(values[i & 255], values[i & 255] - i); - Verify.verify(values[i & 255] + i, values[i & 255] - i); - Verify.verify(values[i & 255], values[i & 255]); - if ((i & 1) == 1 && i > 5) { - Verify.verify(values[i & 255] + i, values[i & 255] - i); - } else { - Verify.verify(values[i & 255] - i, values[i & 255] + i); - } - } - } -} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/LoopDependentTest.java --- a/test/compiler/intrinsics/mathexact/LoopDependentTest.java Mon Oct 21 14:08:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2013, 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 8024924 - * @summary Test non constant addExact - * @compile LoopDependentTest.java Verify.java - * @run main LoopDependentTest - * - */ - -import java.lang.ArithmeticException; - -public class LoopDependentTest { - public static java.util.Random rnd = new java.util.Random(); - - public static void main(String[] args) { - int rnd1 = rnd.nextInt(), rnd2 = rnd.nextInt(); - for (int i = 0; i < 50000; ++i) { - Verify.verify(rnd1 + i, rnd2 + i); - Verify.verify(rnd1 + i, rnd2 + (i & 0xff)); - Verify.verify(rnd1 - i, rnd2 - (i & 0xff)); - Verify.verify(rnd1 + i + 1, rnd2 + i + 2); - Verify.verify(rnd1 + i * 2, rnd2 + i); - } - } -} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/MulExactICondTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/MulExactICondTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test multiplyExact as condition + * @compile MulExactICondTest.java + * @run main MulExactICondTest + * + */ + +public class MulExactICondTest { + public static int result = 0; + + public static void main(String[] args) { + for (int i = 0; i < 50000; ++i) { + runTest(); + } + } + + public static void runTest() { + int i = 7; + while (java.lang.Math.multiplyExact(i, result) < 89361) { + if ((java.lang.Math.multiplyExact(i, i) & 1) == 1) { + i += 3; + } else if ((i & 5) == 4) { + i += 7; + } else if ((i & 0xf) == 6) { + i += 2; + } else { + i += 1; + } + result += 2; + } + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/MulExactIConstantTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/MulExactIConstantTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test constant multiplyExact + * @compile MulExactIConstantTest.java Verify.java + * @run main MulExactIConstantTest + * + */ + +public class MulExactIConstantTest { + public static void main(String[] args) { + Verify.ConstantTest.verify(new Verify.MulExactI()); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/MulExactILoadTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/MulExactILoadTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test multiplyExact + * @compile MulExactILoadTest.java Verify.java + * @run main MulExactILoadTest + * + */ + +public class MulExactILoadTest { + public static void main(String[] args) { + Verify.LoadTest.init(); + Verify.LoadTest.verify(new Verify.MulExactI()); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/MulExactILoopDependentTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/MulExactILoopDependentTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test loop dependent multiplyExact + * @compile MulExactILoopDependentTest.java Verify.java + * @run main MulExactILoopDependentTest + * + */ +public class MulExactILoopDependentTest { + public static void main(String[] args) { + Verify.LoopDependentTest.verify(new Verify.MulExactI()); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/MulExactINonConstantTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/MulExactINonConstantTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test non constant multiplyExact + * @compile MulExactINonConstantTest.java Verify.java + * @run main MulExactINonConstantTest + * + */ + +public class MulExactINonConstantTest { + public static void main(String[] args) { + Verify.NonConstantTest.verify(new Verify.MulExactI()); + Verify.LoadTest.verify(new Verify.MulExactI()); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/MulExactIRepeatTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/MulExactIRepeatTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test repeating multiplyExact + * @compile MulExactIRepeatTest.java Verify.java + * @run main MulExactIRepeatTest + * + */ + +public class MulExactIRepeatTest { + public static void main(String[] args) { + runTest(new Verify.MulExactI()); + } + + public static int nonExact(int x, int y, Verify.BinaryMethod method) { + int result = method.unchecked(x, y); + result += method.unchecked(x, y); + result += method.unchecked(x, y); + result += method.unchecked(x, y); + return result; + } + + public static void runTest(Verify.BinaryMethod method) { + java.util.Random rnd = new java.util.Random(); + for (int i = 0; i < 50000; ++i) { + int x = Integer.MAX_VALUE - 10; + int y = Integer.MAX_VALUE - 10 + rnd.nextInt(5); + + int c = rnd.nextInt() / 10; + int d = rnd.nextInt(9); + + int a = catchingExact(x, y, method); + + if (a != 36) { + throw new RuntimeException("a != 36 : " + a); + } + + int b = nonExact(c, d, method); + int n = exact(c, d, method); + + + if (n != b) { + throw new RuntimeException("n != b : " + n + " != " + b); + } + } + } + + public static int exact(int x, int y, Verify.BinaryMethod method) { + int result = 0; + result += method.checkMethod(x, y); + result += method.checkMethod(x, y); + result += method.checkMethod(x, y); + result += method.checkMethod(x, y); + return result; + } + + public static int catchingExact(int x, int y, Verify.BinaryMethod method) { + int result = 0; + try { + result += 5; + result = method.checkMethod(x, y); + } catch (ArithmeticException e) { + result += 1; + } + try { + result += 6; + + result += method.checkMethod(x, y); + } catch (ArithmeticException e) { + result += 2; + } + try { + result += 7; + result += method.checkMethod(x, y); + } catch (ArithmeticException e) { + result += 3; + } + try { + result += 8; + result += method.checkMethod(x, y); + } catch (ArithmeticException e) { + result += 4; + } + return result; + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/MulExactLConstantTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/MulExactLConstantTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test constant mulExact + * @compile MulExactLConstantTest.java Verify.java + * @run main MulExactLConstantTest + * + */ + +public class MulExactLConstantTest { + public static void main(String[] args) { + Verify.ConstantLongTest.verify(new Verify.MulExactL()); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/MulExactLNonConstantTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/MulExactLNonConstantTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test non constant mulExact + * @compile MulExactLNonConstantTest.java Verify.java + * @run main MulExactLNonConstantTest + * + */ + +public class MulExactLNonConstantTest { + public static void main(String[] args) { + Verify.NonConstantLongTest.verify(new Verify.MulExactL()); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/NegExactIConstantTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/NegExactIConstantTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test constant negExact + * @compile NegExactIConstantTest.java Verify.java + * @run main NegExactIConstantTest + * + */ + +public class NegExactIConstantTest { + public static void main(String[] args) { + Verify.ConstantTest.verify(new Verify.UnaryToBinary(new Verify.NegExactI())); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/NegExactILoadTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/NegExactILoadTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test negExact + * @compile NegExactILoadTest.java Verify.java + * @run main NegExactILoadTest + * + */ + +public class NegExactILoadTest { + public static void main(String[] args) { + Verify.LoadTest.init(); + Verify.LoadTest.verify(new Verify.UnaryToBinary(new Verify.NegExactI())); + } + +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/NegExactILoopDependentTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/NegExactILoopDependentTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test negExact loop dependent + * @compile NegExactILoopDependentTest.java Verify.java + * @run main NegExactILoopDependentTest + * + */ +public class NegExactILoopDependentTest { + public static void main(String[] args) { + Verify.LoopDependentTest.verify(new Verify.UnaryToBinary(new Verify.NegExactI())); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/NegExactINonConstantTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/NegExactINonConstantTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test non constant negExact + * @compile NegExactINonConstantTest.java Verify.java + * @run main NegExactINonConstantTest + * + */ + +public class NegExactINonConstantTest { + public static void main(String[] args) { + Verify.NonConstantTest.verify(new Verify.UnaryToBinary(new Verify.NegExactI())); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/NegExactLConstantTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/NegExactLConstantTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test constant negExact + * @compile NegExactLConstantTest.java Verify.java + * @run main NegExactLConstantTest + * + */ + +public class NegExactLConstantTest { + public static void main(String[] args) { + Verify.ConstantLongTest.verify(new Verify.UnaryToBinaryLong(new Verify.NegExactL())); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/NegExactLNonConstantTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/NegExactLNonConstantTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test constant negExact + * @compile NegExactLNonConstantTest.java Verify.java + * @run main NegExactLNonConstantTest + * + */ + +public class NegExactLNonConstantTest { + public static void main(String[] args) { + Verify.NonConstantLongTest.verify(new Verify.UnaryToBinaryLong(new Verify.NegExactL())); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/NonConstantTest.java --- a/test/compiler/intrinsics/mathexact/NonConstantTest.java Mon Oct 21 14:08:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2013, 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 8024924 - * @summary Test non constant addExact - * @compile NonConstantTest.java Verify.java - * @run main NonConstantTest - * - */ - -import java.lang.ArithmeticException; - -public class NonConstantTest { - public static java.util.Random rnd = new java.util.Random(); - - public static void main(String[] args) { - for (int i = 0; i < 50000; ++i) { - int rnd1 = rnd.nextInt(), rnd2 = rnd.nextInt(); - Verify.verify(rnd1, rnd2); - Verify.verify(rnd1, rnd2 + 1); - Verify.verify(rnd1 + 1, rnd2); - Verify.verify(rnd1 - 1, rnd2); - Verify.verify(rnd1, rnd2 - 1); - } - } -} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/SubExactICondTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/SubExactICondTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test subtractExact as condition + * @compile SubExactICondTest.java Verify.java + * @run main SubExactICondTest + * + */ + +public class SubExactICondTest { + public static int result = 0; + + public static void main(String[] args) { + for (int i = 0; i < 50000; ++i) { + runTest(); + } + } + + public static void runTest() { + int i = 7; + while (java.lang.Math.subtractExact(i, result) > -31361) { + if ((java.lang.Math.subtractExact(i, i) & 1) == 1) { + i -= 3; + } else if ((i & 5) == 4) { + i -= 7; + } else if ((i & 0xf) == 6) { + i -= 2; + } else { + i -= 1; + } + result += 2; + } + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/SubExactIConstantTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/SubExactIConstantTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test constant subtractExact + * @compile SubExactIConstantTest.java Verify.java + * @run main SubExactIConstantTest + * + */ + +public class SubExactIConstantTest { + public static void main(String[] args) { + Verify.ConstantTest.verify(new Verify.SubExactI()); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/SubExactILoadTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/SubExactILoadTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test non constant subtractExact + * @compile SubExactILoadTest.java Verify.java + * @run main SubExactILoadTest + * + */ + +public class SubExactILoadTest { + public static void main(String[] args) { + Verify.LoadTest.init(); + Verify.LoadTest.verify(new Verify.SubExactI()); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/SubExactILoopDependentTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/SubExactILoopDependentTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test non constant subtractExact + * @compile SubExactILoopDependentTest.java Verify.java + * @run main SubExactILoopDependentTest + * + */ + +public class SubExactILoopDependentTest { + public static void main(String[] args) { + Verify.LoopDependentTest.verify(new Verify.SubExactI()); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/SubExactINonConstantTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/SubExactINonConstantTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test non constant subtractExact + * @compile SubExactINonConstantTest.java Verify.java + * @run main SubExactINonConstantTest + * + */ + +public class SubExactINonConstantTest { + public static void main(String[] args) { + Verify.NonConstantTest.verify(new Verify.SubExactI()); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/SubExactIRepeatTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/SubExactIRepeatTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test repeating subtractExact + * @compile SubExactIRepeatTest.java Verify.java + * @run main SubExactIRepeatTest + * + */ + +import java.lang.ArithmeticException; + +public class SubExactIRepeatTest { + public static void main(String[] args) { + runTest(new Verify.SubExactI()); + } + + public static int nonExact(int x, int y, Verify.BinaryMethod method) { + int result = method.unchecked(x, y); + result += method.unchecked(x, y); + result += method.unchecked(x, y); + result += method.unchecked(x, y); + return result; + } + + public static void runTest(Verify.BinaryMethod method) { + java.util.Random rnd = new java.util.Random(); + for (int i = 0; i < 50000; ++i) { + int x = Integer.MIN_VALUE + 10; + int y = Integer.MAX_VALUE - 10 + rnd.nextInt(5); + + int c = rnd.nextInt() / 2; + int d = rnd.nextInt() / 2; + + int a = catchingExact(x, y, method); + + if (a != 36) { + throw new RuntimeException("a != 36 : " + a); + } + + int b = nonExact(c, d, method); + int n = exact(c, d, method); + + + if (n != b) { + throw new RuntimeException("n != b : " + n + " != " + b); + } + } + } + + public static int exact(int x, int y, Verify.BinaryMethod method) { + int result = 0; + result += method.checkMethod(x, y); + result += method.checkMethod(x, y); + result += method.checkMethod(x, y); + result += method.checkMethod(x, y); + return result; + } + + public static int catchingExact(int x, int y, Verify.BinaryMethod method) { + int result = 0; + try { + result += 5; + result = method.checkMethod(x, y); + } catch (ArithmeticException e) { + result += 1; + } + try { + result += 6; + + result += method.checkMethod(x, y); + } catch (ArithmeticException e) { + result += 2; + } + try { + result += 7; + result += method.checkMethod(x, y); + } catch (ArithmeticException e) { + result += 3; + } + try { + result += 8; + result += method.checkMethod(x, y); + } catch (ArithmeticException e) { + result += 4; + } + return result; + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/SubExactLConstantTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/SubExactLConstantTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test constant subtractExact + * @compile SubExactLConstantTest.java Verify.java + * @run main SubExactLConstantTest + * + */ + +public class SubExactLConstantTest { + public static void main(String[] args) { + Verify.ConstantLongTest.verify(new Verify.SubExactL()); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/SubExactLNonConstantTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/SubExactLNonConstantTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, 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 8026844 + * @summary Test non constant subtractExact + * @compile SubExactLNonConstantTest.java Verify.java + * @run main SubExactLNonConstantTest + * + */ + +public class SubExactLNonConstantTest { + public static void main(String[] args) { + Verify.NonConstantLongTest.verify(new Verify.SubExactL()); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/intrinsics/mathexact/Verify.java --- a/test/compiler/intrinsics/mathexact/Verify.java Mon Oct 21 14:08:09 2013 +0100 +++ b/test/compiler/intrinsics/mathexact/Verify.java Sun Nov 03 07:50:24 2013 +0000 @@ -22,47 +22,641 @@ */ public class Verify { - public static String throwWord(boolean threw) { - return (threw ? "threw" : "didn't throw"); - } + public static String throwWord(boolean threw) { + return (threw ? "threw" : "didn't throw"); + } + + public static void verifyResult(UnaryMethod method, int result1, int result2, boolean exception1, boolean exception2, int value) { + if (exception1 != exception2) { + throw new RuntimeException("Intrinsic version [" + method.name() + "]" + throwWord(exception1) + " exception, NonIntrinsic version" + throwWord(exception2) + " for: " + value); + } + if (result1 != result2) { + throw new RuntimeException("Intrinsic version [" + method.name() + "] returned: " + result1 + " while NonIntrinsic version returned: " + result2); + } + } + + public static void verifyResult(UnaryLongMethod method, long result1, long result2, boolean exception1, boolean exception2, long value) { + if (exception1 != exception2) { + throw new RuntimeException("Intrinsic version [" + method.name() + "]" + throwWord(exception1) + " exception, NonIntrinsic version" + throwWord(exception2) + " for: " + value); + } + if (result1 != result2) { + throw new RuntimeException("Intrinsic version [" + method.name() + "] returned: " + result1 + " while NonIntrinsic version returned: " + result2); + } + } + + private static void verifyResult(BinaryMethod method, int result1, int result2, boolean exception1, boolean exception2, int a, int b) { + if (exception1 != exception2) { + throw new RuntimeException("Intrinsic version [" + method.name() + "]" + throwWord(exception1) + " exception, NonIntrinsic version " + throwWord(exception2) + " for: " + a + " + " + b); + } + if (result1 != result2) { + throw new RuntimeException("Intrinsic version [" + method.name() + "] returned: " + result1 + " while NonIntrinsic version returned: " + result2); + } + } + + private static void verifyResult(BinaryLongMethod method, long result1, long result2, boolean exception1, boolean exception2, long a, long b) { + if (exception1 != exception2) { + throw new RuntimeException("Intrinsic version [" + method.name() + "]" + throwWord(exception1) + " exception, NonIntrinsic version " + throwWord(exception2) + " for: " + a + " + " + b); + } + if (result1 != result2) { + throw new RuntimeException("Intrinsic version [" + method.name() + "] returned: " + result1 + " while NonIntrinsic version returned: " + result2); + } + } + + + public static void verifyUnary(int a, UnaryMethod method) { + boolean exception1 = false, exception2 = false; + int result1 = 0, result2 = 0; + try { + result1 = method.checkMethod(a); + } catch (ArithmeticException e) { + exception1 = true; + } + try { + result2 = method.safeMethod(a); + } catch (ArithmeticException e) { + exception2 = true; + } + + verifyResult(method, result1, result2, exception1, exception2, a); + } + + public static void verifyUnary(long a, UnaryLongMethod method) { + boolean exception1 = false, exception2 = false; + long result1 = 0, result2 = 0; + try { + result1 = method.checkMethod(a); + } catch (ArithmeticException e) { + exception1 = true; + } + try { + result2 = method.safeMethod(a); + } catch (ArithmeticException e) { + exception2 = true; + } + + verifyResult(method, result1, result2, exception1, exception2, a); + } + + + public static void verifyBinary(int a, int b, BinaryMethod method) { + boolean exception1 = false, exception2 = false; + int result1 = 0, result2 = 0; + try { + result1 = method.checkMethod(a, b); + } catch (ArithmeticException e) { + exception1 = true; + } + try { + result2 = method.safeMethod(a, b); + } catch (ArithmeticException e) { + exception2 = true; + } + + verifyResult(method, result1, result2, exception1, exception2, a, b); + } + + public static void verifyBinary(long a, long b, BinaryLongMethod method) { + boolean exception1 = false, exception2 = false; + long result1 = 0, result2 = 0; + try { + result1 = method.checkMethod(a, b); + } catch (ArithmeticException e) { + exception1 = true; + } + try { + result2 = method.safeMethod(a, b); + } catch (ArithmeticException e) { + exception2 = true; + } + + verifyResult(method, result1, result2, exception1, exception2, a, b); + } + + + public static class LoadTest { + public static java.util.Random rnd = new java.util.Random(); + public static int[] values = new int[256]; + + public static void init() { + for (int i = 0; i < values.length; ++i) { + values[i] = rnd.nextInt(); + } + } + + public static void verify(BinaryMethod method) { + for (int i = 0; i < 50000; ++i) { + Verify.verifyBinary(values[i & 255], values[i & 255] - i, method); + Verify.verifyBinary(values[i & 255] + i, values[i & 255] - i, method); + Verify.verifyBinary(values[i & 255], values[i & 255], method); + if ((i & 1) == 1 && i > 5) { + Verify.verifyBinary(values[i & 255] + i, values[i & 255] - i, method); + } else { + Verify.verifyBinary(values[i & 255] - i, values[i & 255] + i, method); + } + Verify.verifyBinary(values[i & 255], values[(i + 1) & 255], method); + } + } + } + + public static class NonConstantTest { + public static java.util.Random rnd = new java.util.Random(); + + public static void verify(BinaryMethod method) { + for (int i = 0; i < 50000; ++i) { + int rnd1 = rnd.nextInt(), rnd2 = rnd.nextInt(); + Verify.verifyBinary(rnd1, rnd2, method); + Verify.verifyBinary(rnd1, rnd2 + 1, method); + Verify.verifyBinary(rnd1 + 1, rnd2, method); + Verify.verifyBinary(rnd1 - 1, rnd2, method); + Verify.verifyBinary(rnd1, rnd2 - 1, method); + } + } + } - public static void verify(int a, int b) { - boolean exception1 = false, exception2 = false; - int result1 = 0, result2 = 0; - try { - result1 = testIntrinsic(a, b); - } catch (ArithmeticException e) { - exception1 = true; + public static class NonConstantLongTest { + public static long[] values = { Long.MIN_VALUE, Long.MAX_VALUE, 0, Long.MAX_VALUE - 1831 }; + public static java.util.Random rnd = new java.util.Random(); + + public static void verify(BinaryLongMethod method) { + for (int i = 0; i < 50000; ++i) { + long rnd1 = rnd.nextLong(), rnd2 = rnd.nextLong(); + Verify.verifyBinary(rnd1, rnd2, method); + Verify.verifyBinary(rnd1, rnd2 + 1, method); + Verify.verifyBinary(rnd1 + 1, rnd2, method); + Verify.verifyBinary(rnd1 - 1, rnd2, method); + Verify.verifyBinary(rnd1, rnd2 - 1, method); + Verify.verifyBinary(rnd1 + Long.MAX_VALUE - rnd2, rnd2 + 1, method); + Verify.verifyBinary(values[0], values[2], method); + Verify.verifyBinary(values[1], values[2], method); + Verify.verifyBinary(values[3], 74L, method); + } + } + } + + public static class LoopDependentTest { + public static java.util.Random rnd = new java.util.Random(); + + public static void verify(BinaryMethod method) { + int rnd1 = rnd.nextInt(), rnd2 = rnd.nextInt(); + runTest(rnd1, rnd2, method); + } + + private static void runTest(int rnd1, int rnd2, BinaryMethod method) { + for (int i = 0; i < 50000; ++i) { + Verify.verifyBinary(rnd1 + i, rnd2 + i, method); + Verify.verifyBinary(rnd1 + i, rnd2 + (i & 0xff), method); + Verify.verifyBinary(rnd1 - i, rnd2 - (i & 0xff), method); + Verify.verifyBinary(rnd1 + i + 1, rnd2 + i + 2, method); + Verify.verifyBinary(rnd1 + i * 2, rnd2 + i, method); + } + } + } + + public static class ConstantTest { + public static void verify(BinaryMethod method) { + for (int i = 0; i < 50000; ++i) { + Verify.verifyBinary(5, 7, method); + Verify.verifyBinary(Integer.MAX_VALUE, 1, method); + Verify.verifyBinary(Integer.MIN_VALUE, -1, method); + Verify.verifyBinary(Integer.MAX_VALUE, -1, method); + Verify.verifyBinary(Integer.MIN_VALUE, 1, method); + Verify.verifyBinary(Integer.MAX_VALUE / 2, Integer.MAX_VALUE / 2, method); + Verify.verifyBinary(Integer.MAX_VALUE / 2, (Integer.MAX_VALUE / 2) + 3, method); + Verify.verifyBinary(Integer.MAX_VALUE, Integer.MIN_VALUE, method); + } + } + } + + public static class ConstantLongTest { + public static void verify(BinaryLongMethod method) { + for (int i = 0; i < 50000; ++i) { + Verify.verifyBinary(5, 7, method); + Verify.verifyBinary(Long.MAX_VALUE, 1, method); + Verify.verifyBinary(Long.MIN_VALUE, -1, method); + Verify.verifyBinary(Long.MAX_VALUE, -1, method); + Verify.verifyBinary(Long.MIN_VALUE, 1, method); + Verify.verifyBinary(Long.MAX_VALUE / 2, Long.MAX_VALUE / 2, method); + Verify.verifyBinary(Long.MAX_VALUE / 2, (Long.MAX_VALUE / 2) + 3, method); + Verify.verifyBinary(Long.MAX_VALUE, Long.MIN_VALUE, method); + } + } + } + + public static interface BinaryMethod { + int safeMethod(int a, int b); + int checkMethod(int a, int b); + int unchecked(int a, int b); + String name(); } - try { - result2 = testNonIntrinsic(a, b); - } catch (ArithmeticException e) { - exception2 = true; + + public static interface UnaryMethod { + int safeMethod(int value); + int checkMethod(int value); + int unchecked(int value); + String name(); + } + + public static interface BinaryLongMethod { + long safeMethod(long a, long b); + long checkMethod(long a, long b); + long unchecked(long a, long b); + String name(); + } + + public static interface UnaryLongMethod { + long safeMethod(long value); + long checkMethod(long value); + long unchecked(long value); + String name(); + } + + public static class UnaryToBinary implements BinaryMethod { + private final UnaryMethod method; + public UnaryToBinary(UnaryMethod method) { + this.method = method; + } + + @Override + public int safeMethod(int a, int b) { + return method.safeMethod(a); + } + + @Override + public int checkMethod(int a, int b) { + return method.checkMethod(a); + } + + @Override + public int unchecked(int a, int b) { + return method.unchecked(a); + + } + + @Override + public String name() { + return method.name(); + } + } + + public static class UnaryToBinaryLong implements BinaryLongMethod { + private final UnaryLongMethod method; + public UnaryToBinaryLong(UnaryLongMethod method) { + this.method = method; + } + + @Override + public long safeMethod(long a, long b) { + return method.safeMethod(a); + } + + @Override + public long checkMethod(long a, long b) { + return method.checkMethod(a); + } + + @Override + public long unchecked(long a, long b) { + return method.unchecked(a); + + } + + @Override + public String name() { + return method.name(); + } } - if (exception1 != exception2) { - throw new RuntimeException("Intrinsic version " + throwWord(exception1) + " exception, NonIntrinsic version " + throwWord(exception2) + " for: " + a + " + " + b); + + public static class AddExactI implements BinaryMethod { + @Override + public int safeMethod(int x, int y) { + int r = x + y; + // HD 2-12 Overflow iff both arguments have the opposite sign of the result + if (((x ^ r) & (y ^ r)) < 0) { + throw new ArithmeticException("integer overflow"); + } + return r; + + } + + @Override + public int checkMethod(int a, int b) { + return Math.addExact(a, b); + } + + @Override + public String name() { + return "addExact"; + } + + @Override + public int unchecked(int a, int b) { + return a + b; + } } - if (result1 != result2) { - throw new RuntimeException("Intrinsic version returned: " + a + " while NonIntrinsic version returned: " + b); + + public static class AddExactL implements BinaryLongMethod { + @Override + public long safeMethod(long x, long y) { + long r = x + y; + // HD 2-12 Overflow iff both arguments have the opposite sign of the result + if (((x ^ r) & (y ^ r)) < 0) { + throw new ArithmeticException("integer overflow"); + } + return r; + + } + + @Override + public long checkMethod(long a, long b) { + return Math.addExact(a, b); + } + + @Override + public String name() { + return "addExactLong"; + } + + @Override + public long unchecked(long a, long b) { + return a + b; + } + } + + public static class MulExactI implements BinaryMethod { + @Override + public int safeMethod(int x, int y) { + long r = (long)x * (long)y; + if ((int)r != r) { + throw new ArithmeticException("integer overflow"); + } + return (int)r; + + } + + @Override + public int checkMethod(int a, int b) { + return Math.multiplyExact(a, b); + } + + @Override + public int unchecked(int a, int b) { + return a * b; + } + + @Override + public String name() { + return "multiplyExact"; + } } - } + + public static class MulExactL implements BinaryLongMethod { + @Override + public long safeMethod(long x, long y) { + long r = x * y; + long ax = Math.abs(x); + long ay = Math.abs(y); + if (((ax | ay) >>> 31 != 0)) { + // Some bits greater than 2^31 that might cause overflow + // Check the result using the divide operator + // and check for the special case of Long.MIN_VALUE * -1 + if (((y != 0) && (r / y != x)) || + (x == Long.MIN_VALUE && y == -1)) { + throw new ArithmeticException("long overflow"); + } + } + return r; + } + + @Override + public long checkMethod(long a, long b) { + return Math.multiplyExact(a, b); + } + + @Override + public long unchecked(long a, long b) { + return a * b; + } + + @Override + public String name() { + return "multiplyExact"; + } + } - public static int testIntrinsic(int a, int b) { - return java.lang.Math.addExact(a, b); - } + public static class NegExactL implements UnaryLongMethod { + @Override + public long safeMethod(long a) { + if (a == Long.MIN_VALUE) { + throw new ArithmeticException("long overflow"); + } + + return -a; + + } + + @Override + public long checkMethod(long value) { + return Math.negateExact(value); + } + + @Override + public long unchecked(long value) { + return -value; + } + + @Override + public String name() { + return "negateExactLong"; + } + } + + public static class NegExactI implements UnaryMethod { + @Override + public int safeMethod(int a) { + if (a == Integer.MIN_VALUE) { + throw new ArithmeticException("integer overflow"); + } + + return -a; + + } + + @Override + public int checkMethod(int value) { + return Math.negateExact(value); + } + + @Override + public int unchecked(int value) { + return -value; + } - public static int testNonIntrinsic(int a, int b) { - return safeAddExact(a, b); - } + @Override + public String name() { + return "negateExact"; + } + } + + public static class SubExactI implements BinaryMethod { + @Override + public int safeMethod(int x, int y) { + int r = x - y; + // HD 2-12 Overflow iff the arguments have different signs and + // the sign of the result is different than the sign of x + if (((x ^ y) & (x ^ r)) < 0) { + throw new ArithmeticException("integer overflow"); + } + return r; + } + + @Override + public int checkMethod(int a, int b) { + return Math.subtractExact(a, b); + } + + @Override + public int unchecked(int a, int b) { + return a - b; + } + + @Override + public String name() { + return "subtractExact"; + } + } + + public static class SubExactL implements BinaryLongMethod { + @Override + public long safeMethod(long x, long y) { + long r = x - y; + // HD 2-12 Overflow iff the arguments have different signs and + // the sign of the result is different than the sign of x + if (((x ^ y) & (x ^ r)) < 0) { + throw new ArithmeticException("integer overflow"); + } + return r; + } + + @Override + public long checkMethod(long a, long b) { + return Math.subtractExact(a, b); + } + + @Override + public long unchecked(long a, long b) { + return a - b; + } + + @Override + public String name() { + return "subtractExactLong"; + } + } + + static class IncExactL implements UnaryLongMethod { + @Override + public long safeMethod(long a) { + if (a == Long.MAX_VALUE) { + throw new ArithmeticException("long overflow"); + } + + return a + 1L; + + } + + @Override + public long checkMethod(long value) { + return Math.incrementExact(value); + } + + @Override + public long unchecked(long value) { + return value + 1; + } - // Copied java.lang.Math.addExact to avoid intrinsification - public static int safeAddExact(int x, int y) { - int r = x + y; - // HD 2-12 Overflow iff both arguments have the opposite sign of the result - if (((x ^ r) & (y ^ r)) < 0) { - throw new ArithmeticException("integer overflow"); + @Override + public String name() { + return "incrementExactLong"; + } + } + + static class IncExactI implements UnaryMethod { + @Override + public int safeMethod(int a) { + if (a == Integer.MAX_VALUE) { + throw new ArithmeticException("integer overflow"); + } + + return a + 1; + } + + @Override + public int checkMethod(int value) { + return Math.incrementExact(value); + } + + @Override + public int unchecked(int value) { + return value + 1; + } + + @Override + public String name() { + return "incrementExact"; + } } - return r; - } + + static class DecExactL implements UnaryLongMethod { + @Override + public long safeMethod(long a) { + if (a == Long.MIN_VALUE) { + throw new ArithmeticException("long overflow"); + } + + return a - 1L; + } + + @Override + public long checkMethod(long value) { + return Math.decrementExact(value); + } + + @Override + public long unchecked(long value) { + return value - 1; + } + + @Override + public String name() { + return "decExactLong"; + } + } + + static class DecExactI implements UnaryMethod { + @Override + public int safeMethod(int a) { + if (a == Integer.MIN_VALUE) { + throw new ArithmeticException("integer overflow"); + } + + return a - 1; + } + + @Override + public int checkMethod(int value) { + return Math.decrementExact(value); + } + + @Override + public int unchecked(int value) { + return value - 1; + } + + @Override + public String name() { + return "decrementExact"; + } + } + } diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/jsr292/CreatesInterfaceDotEqualsCallInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/jsr292/CreatesInterfaceDotEqualsCallInfo.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013, 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 8026124 + * @summary Javascript file provoked assertion failure in linkResolver.cpp + * + * @run main/othervm CreatesInterfaceDotEqualsCallInfo + */ + +public class CreatesInterfaceDotEqualsCallInfo { + public static void main(String[] args) throws java.io.IOException { + String[] jsargs = { System.getProperty("test.src", ".") + + "/createsInterfaceDotEqualsCallInfo.js" }; + jdk.nashorn.tools.Shell.main(System.in, System.out, System.err, jsargs); + System.out.println("PASS, did not crash running Javascript"); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/jsr292/createsInterfaceDotEqualsCallInfo.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/jsr292/createsInterfaceDotEqualsCallInfo.js Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2013, 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. + * + */ + +var path = new java.io.File("/Users/someone").toPath(); +path.toString(); diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/print/PrintInlining.java --- a/test/compiler/print/PrintInlining.java Mon Oct 21 14:08:09 2013 +0100 +++ b/test/compiler/print/PrintInlining.java Sun Nov 03 07:50:24 2013 +0000 @@ -25,7 +25,7 @@ * @test * @bug 8022585 * @summary VM crashes when ran with -XX:+PrintInlining - * @run main/othervm -Xcomp -XX:+PrintInlining PrintInlining + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining PrintInlining * */ diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/startup/SmallCodeCacheStartup.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/startup/SmallCodeCacheStartup.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2013, 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 8023014 + * @summary Test ensures that there is no crash when compiler initialization fails + * @library /testlibrary + * + */ +import com.oracle.java.testlibrary.*; + +public class SmallCodeCacheStartup { + public static void main(String[] args) throws Exception { + ProcessBuilder pb; + OutputAnalyzer out; + + pb = ProcessTools.createJavaProcessBuilder("-XX:ReservedCodeCacheSize=3m", "-XX:CICompilerCount=64", "-version"); + out = new OutputAnalyzer(pb.start()); + out.shouldContain("no space to run compiler"); + out.shouldHaveExitValue(0); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/tiered/CompLevelsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/tiered/CompLevelsTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2013, 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. + */ + +/** + * Abstract class for testing of used compilation levels correctness. + * + * @author igor.ignatyev@oracle.com + */ +public abstract class CompLevelsTest extends CompilerWhiteBoxTest { + protected CompLevelsTest(TestCase testCase) { + super(testCase); + // to prevent inlining of #method + WHITE_BOX.testSetDontInlineMethod(method, true); + } + + /** + * Checks that level is available. + * @param compLevel level to check + */ + protected void testAvailableLevel(int compLevel, int bci) { + if (IS_VERBOSE) { + System.out.printf("testAvailableLevel(level = %d, bci = %d)%n", + compLevel, bci); + } + WHITE_BOX.enqueueMethodForCompilation(method, compLevel, bci); + checkCompiled(); + checkLevel(compLevel, getCompLevel()); + deoptimize(); + } + + /** + * Checks that level is unavailable. + * @param compLevel level to check + */ + protected void testUnavailableLevel(int compLevel, int bci) { + if (IS_VERBOSE) { + System.out.printf("testUnavailableLevel(level = %d, bci = %d)%n", + compLevel, bci); + } + WHITE_BOX.enqueueMethodForCompilation(method, compLevel, bci); + checkNotCompiled(); + } + + /** + * Checks validity of compilation level. + * @param expected expected level + * @param actual actually level + */ + protected void checkLevel(int expected, int actual) { + if (expected != actual) { + throw new RuntimeException("expected[" + expected + "] != actual[" + + actual + "]"); + } + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/tiered/NonTieredLevelsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/tiered/NonTieredLevelsTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2013, 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.util.function.IntPredicate; + +/** + * @test NonTieredLevelsTest + * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * @build NonTieredLevelsTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:-TieredCompilation + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:CompileCommand=compileonly,TestCase$Helper::* + * NonTieredLevelsTest + * @summary Verify that only one level can be used + * @author igor.ignatyev@oracle.com + */ +public class NonTieredLevelsTest extends CompLevelsTest { + private static final int AVAILABLE_COMP_LEVEL; + private static final IntPredicate IS_AVAILABLE_COMPLEVEL; + static { + String vmName = System.getProperty("java.vm.name"); + if (vmName.endsWith(" Server VM")) { + AVAILABLE_COMP_LEVEL = COMP_LEVEL_FULL_OPTIMIZATION; + IS_AVAILABLE_COMPLEVEL = x -> x == COMP_LEVEL_FULL_OPTIMIZATION; + } else if (vmName.endsWith(" Client VM") + || vmName.endsWith(" Minimal VM")) { + AVAILABLE_COMP_LEVEL = COMP_LEVEL_SIMPLE; + IS_AVAILABLE_COMPLEVEL = x -> x >= COMP_LEVEL_SIMPLE + && x <= COMP_LEVEL_FULL_PROFILE; + } else { + throw new RuntimeException("Unknown VM: " + vmName); + } + + } + public static void main(String[] args) throws Exception { + if (TIERED_COMPILATION) { + System.err.println("Test isn't applicable w/ enabled " + + "TieredCompilation. Skip test."); + return; + } + for (TestCase test : TestCase.values()) { + new NonTieredLevelsTest(test).runTest(); + } + } + + private NonTieredLevelsTest(TestCase testCase) { + super(testCase); + // to prevent inlining of #method + WHITE_BOX.testSetDontInlineMethod(method, true); + } + + @Override + protected void test() throws Exception { + checkNotCompiled(); + compile(); + checkCompiled(); + + int compLevel = getCompLevel(); + checkLevel(AVAILABLE_COMP_LEVEL, compLevel); + int bci = WHITE_BOX.getMethodEntryBci(method); + deoptimize(); + if (!testCase.isOsr) { + for (int level = 1; level <= COMP_LEVEL_MAX; ++level) { + if (IS_AVAILABLE_COMPLEVEL.test(level)) { + testAvailableLevel(level, bci); + } else { + testUnavailableLevel(level, bci); + } + } + } else { + System.out.println("skip other levels testing in OSR"); + testAvailableLevel(AVAILABLE_COMP_LEVEL, bci); + } + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/tiered/TieredLevelsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/tiered/TieredLevelsTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2013, 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 TieredLevelsTest + * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * @build TieredLevelsTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+TieredCompilation + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:CompileCommand=compileonly,TestCase$Helper::* + * TieredLevelsTest + * @summary Verify that all levels < 'TieredStopAtLevel' can be used + * @author igor.ignatyev@oracle.com + */ +public class TieredLevelsTest extends CompLevelsTest { + public static void main(String[] args) throws Exception { + if (!TIERED_COMPILATION) { + System.err.println("Test isn't applicable w/ disabled " + + "TieredCompilation. Skip test."); + return; + } + for (TestCase test : TestCase.values()) { + new TieredLevelsTest(test).runTest(); + } + } + + private TieredLevelsTest(TestCase testCase) { + super(testCase); + // to prevent inlining of #method + WHITE_BOX.testSetDontInlineMethod(method, true); + } + + @Override + protected void test() throws Exception { + checkNotCompiled(); + compile(); + checkCompiled(); + + int compLevel = getCompLevel(); + if (compLevel > TIERED_STOP_AT_LEVEL) { + throw new RuntimeException("method.compLevel[" + compLevel + + "] > TieredStopAtLevel [" + TIERED_STOP_AT_LEVEL + "]"); + } + int bci = WHITE_BOX.getMethodEntryBci(method); + deoptimize(); + + for (int testedTier = 1; testedTier <= TIERED_STOP_AT_LEVEL; + ++testedTier) { + testAvailableLevel(testedTier, bci); + } + for (int testedTier = TIERED_STOP_AT_LEVEL + 1; + testedTier <= COMP_LEVEL_MAX; ++testedTier) { + testUnavailableLevel(testedTier, bci); + } + } + + + @Override + protected void checkLevel(int expected, int actual) { + if (expected == COMP_LEVEL_FULL_PROFILE + && actual == COMP_LEVEL_LIMITED_PROFILE) { + // for simple method full_profile may be replaced by limited_profile + return; + } + super.checkLevel(expected, actual); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/types/TypeSpeculation.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/types/TypeSpeculation.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2013, 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 8024070 + * @summary Test that type speculation doesn't cause incorrect execution + * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:TypeProfileLevel=222 TypeSpeculation + * + */ + +public class TypeSpeculation { + + interface I { + } + + static class A { + int m() { + return 1; + } + } + + static class B extends A implements I { + int m() { + return 2; + } + } + + static class C extends B { + int m() { + return 3; + } + } + + static int test1_invokevirtual(A a) { + return a.m(); + } + + static int test1_1(A a) { + return test1_invokevirtual(a); + } + + static boolean test1() { + A a = new A(); + B b = new B(); + C c = new C(); + + // pollute profile at test1_invokevirtual to make sure the + // compiler cannot rely on it + for (int i = 0; i < 5000; i++) { + test1_invokevirtual(a); + test1_invokevirtual(b); + test1_invokevirtual(c); + } + + // profiling + speculation should make test1_invokevirtual + // inline A.m() with a guard + for (int i = 0; i < 20000; i++) { + int res = test1_1(b); + if (res != b.m()) { + System.out.println("test1 failed with class B"); + return false; + } + } + // check that the guard works as expected by passing a + // different type + int res = test1_1(a); + if (res != a.m()) { + System.out.println("test1 failed with class A"); + return false; + } + return true; + } + + static int test2_invokevirtual(A a) { + return a.m(); + } + + static int test2_1(A a, boolean t) { + A aa; + if (t) { + aa = (B)a; + } else { + aa = a; + } + // if a of type B is passed to test2_1, the static type of aa + // here is no better than A but the profiled type is B so this + // should inline + return test2_invokevirtual(aa); + } + + static boolean test2() { + A a = new A(); + B b = new B(); + C c = new C(); + + // pollute profile at test2_invokevirtual to make sure the + // compiler cannot rely on it + for (int i = 0; i < 5000; i++) { + test2_invokevirtual(a); + test2_invokevirtual(b); + test2_invokevirtual(c); + } + + // profiling + speculation should make test2_invokevirtual + // inline A.m() with a guard + for (int i = 0; i < 20000; i++) { + int res = test2_1(b, (i % 2) == 0); + if (res != b.m()) { + System.out.println("test2 failed with class B"); + return false; + } + } + // check that the guard works as expected by passing a + // different type + int res = test2_1(a, false); + if (res != a.m()) { + System.out.println("test2 failed with class A"); + return false; + } + return true; + } + + static int test3_invokevirtual(A a) { + return a.m(); + } + + static void test3_2(A a) { + } + + static int test3_1(A a, int i) { + if (i == 0) { + return 0; + } + // If we come here and a is of type B but parameter profiling + // is polluted, both branches of the if below should have + // profiling that tell us and inlining of the virtual call + // should happen + if (i == 1) { + test3_2(a); + } else { + test3_2(a); + } + return test3_invokevirtual(a); + } + + static boolean test3() { + A a = new A(); + B b = new B(); + C c = new C(); + + // pollute profile at test3_invokevirtual and test3_1 to make + // sure the compiler cannot rely on it + for (int i = 0; i < 3000; i++) { + test3_invokevirtual(a); + test3_invokevirtual(b); + test3_invokevirtual(c); + test3_1(a, 0); + test3_1(b, 0); + } + + // profiling + speculation should make test3_invokevirtual + // inline A.m() with a guard + for (int i = 0; i < 20000; i++) { + int res = test3_1(b, (i % 2) + 1); + if (res != b.m()) { + System.out.println("test3 failed with class B"); + return false; + } + } + // check that the guard works as expected by passing a + // different type + int res = test3_1(a, 1); + if (res != a.m()) { + System.out.println("test3 failed with class A"); + return false; + } + return true; + } + + // Mix 2 incompatible profiled types + static int test4_invokevirtual(A a) { + return a.m(); + } + + static void test4_2(A a) { + } + + static int test4_1(A a, boolean b) { + if (b) { + test4_2(a); + } else { + test4_2(a); + } + // shouldn't inline + return test4_invokevirtual(a); + } + + static boolean test4() { + A a = new A(); + B b = new B(); + C c = new C(); + + // pollute profile at test3_invokevirtual and test3_1 to make + // sure the compiler cannot rely on it + for (int i = 0; i < 3000; i++) { + test4_invokevirtual(a); + test4_invokevirtual(b); + test4_invokevirtual(c); + } + + for (int i = 0; i < 20000; i++) { + if ((i % 2) == 0) { + int res = test4_1(a, true); + if (res != a.m()) { + System.out.println("test4 failed with class A"); + return false; + } + } else { + int res = test4_1(b, false); + if (res != b.m()) { + System.out.println("test4 failed with class B"); + return false; + } + } + } + return true; + } + + // Mix one profiled type with an incompatible type + static int test5_invokevirtual(A a) { + return a.m(); + } + + static void test5_2(A a) { + } + + static int test5_1(A a, boolean b) { + if (b) { + test5_2(a); + } else { + A aa = (B)a; + } + // shouldn't inline + return test5_invokevirtual(a); + } + + static boolean test5() { + A a = new A(); + B b = new B(); + C c = new C(); + + // pollute profile at test3_invokevirtual and test3_1 to make + // sure the compiler cannot rely on it + for (int i = 0; i < 3000; i++) { + test5_invokevirtual(a); + test5_invokevirtual(b); + test5_invokevirtual(c); + } + + for (int i = 0; i < 20000; i++) { + if ((i % 2) == 0) { + int res = test5_1(a, true); + if (res != a.m()) { + System.out.println("test5 failed with class A"); + return false; + } + } else { + int res = test5_1(b, false); + if (res != b.m()) { + System.out.println("test5 failed with class B"); + return false; + } + } + } + return true; + } + + // Mix incompatible profiled types + static void test6_2(Object o) { + } + + static Object test6_1(Object o, boolean b) { + if (b) { + test6_2(o); + } else { + test6_2(o); + } + return o; + } + + static boolean test6() { + A a = new A(); + A[] aa = new A[10]; + + for (int i = 0; i < 20000; i++) { + if ((i % 2) == 0) { + test6_1(a, true); + } else { + test6_1(aa, false); + } + } + return true; + } + + // Mix a profiled type with an incompatible type + static void test7_2(Object o) { + } + + static Object test7_1(Object o, boolean b) { + if (b) { + test7_2(o); + } else { + Object oo = (A[])o; + } + return o; + } + + static boolean test7() { + A a = new A(); + A[] aa = new A[10]; + + for (int i = 0; i < 20000; i++) { + if ((i % 2) == 0) { + test7_1(a, true); + } else { + test7_1(aa, false); + } + } + return true; + } + + // Mix a profiled type with an interface + static void test8_2(Object o) { + } + + static I test8_1(Object o) { + test8_2(o); + return (I)o; + } + + static boolean test8() { + A a = new A(); + B b = new B(); + C c = new C(); + + for (int i = 0; i < 20000; i++) { + test8_1(b); + } + return true; + } + + // Mix a profiled type with a constant + static void test9_2(Object o) { + } + + static Object test9_1(Object o, boolean b) { + Object oo; + if (b) { + test9_2(o); + oo = o; + } else { + oo = "some string"; + } + return oo; + } + + static boolean test9() { + A a = new A(); + + for (int i = 0; i < 20000; i++) { + if ((i % 2) == 0) { + test9_1(a, true); + } else { + test9_1(a, false); + } + } + return true; + } + + static public void main(String[] args) { + boolean success = true; + + success = test1() && success; + + success = test2() && success; + + success = test3() && success; + + success = test4() && success; + + success = test5() && success; + + success = test6() && success; + + success = test7() && success; + + success = test8() && success; + + success = test9() && success; + + if (success) { + System.out.println("TEST PASSED"); + } else { + throw new RuntimeException("TEST FAILED: erroneous bound check elimination"); + } + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/compiler/whitebox/CompilerWhiteBoxTest.java --- a/test/compiler/whitebox/CompilerWhiteBoxTest.java Mon Oct 21 14:08:09 2013 +0100 +++ b/test/compiler/whitebox/CompilerWhiteBoxTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -80,8 +80,7 @@ static { if (TIERED_COMPILATION) { - THRESHOLD = 150000; - BACKEDGE_THRESHOLD = 0xFFFFFFFFL; + BACKEDGE_THRESHOLD = THRESHOLD = 150000; } else { THRESHOLD = COMPILE_THRESHOLD; BACKEDGE_THRESHOLD = COMPILE_THRESHOLD * Long.parseLong(getVMOption( @@ -364,7 +363,7 @@ /** OSR constructor test case */ OSR_CONSTRUCTOR_TEST(Helper.OSR_CONSTRUCTOR, Helper.OSR_CONSTRUCTOR_CALLABLE, true), - /** OSR method test case */ + /** OSR method test case */ OSR_METOD_TEST(Helper.OSR_METHOD, Helper.OSR_METHOD_CALLABLE, true), /** OSR static method test case */ OSR_STATIC_TEST(Helper.OSR_STATIC, Helper.OSR_STATIC_CALLABLE, true); @@ -373,7 +372,7 @@ final Executable executable; /** object to invoke {@linkplain #executable} */ final Callable callable; - /** flag for OSR test case */ + /** flag for OSR test case */ final boolean isOsr; private TestCase(Executable executable, Callable callable, diff -r 6795fcebbf42 -r c31f0cbe6d9e test/gc/7168848/HumongousAlloc.java --- a/test/gc/7168848/HumongousAlloc.java Mon Oct 21 14:08:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2012, 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 Humongous.java - * @bug 7168848 - * @summary G1: humongous object allocations should initiate marking cycles when necessary - * @run main/othervm -Xms100m -Xmx100m -XX:+PrintGC -XX:G1HeapRegionSize=1m -XX:+UseG1GC HumongousAlloc - * - */ -import java.lang.management.GarbageCollectorMXBean; -import java.lang.management.ManagementFactory; -import java.util.List; - -public class HumongousAlloc { - - public static byte[] dummy; - private static int sleepFreq = 40; - private static int sleepTime = 1000; - private static double size = 0.75; - private static int iterations = 50; - private static int MB = 1024 * 1024; - - public static void allocate(int size, int sleepTime, int sleepFreq) throws InterruptedException { - System.out.println("Will allocate objects of size: " + size - + " bytes and sleep for " + sleepTime - + " ms after every " + sleepFreq + "th allocation."); - int count = 0; - while (count < iterations) { - for (int i = 0; i < sleepFreq; i++) { - dummy = new byte[size - 16]; - } - Thread.sleep(sleepTime); - count++; - } - } - - public static void main(String[] args) throws InterruptedException { - allocate((int) (size * MB), sleepTime, sleepFreq); - List collectors = ManagementFactory.getGarbageCollectorMXBeans(); - for (GarbageCollectorMXBean collector : collectors) { - if (collector.getName().contains("G1 Old")) { - long count = collector.getCollectionCount(); - if (count > 0) { - throw new RuntimeException("Failed: FullGCs should not have happened. The number of FullGC run is " + count); - } - else { - System.out.println("Passed."); - } - } - } - } -} - diff -r 6795fcebbf42 -r c31f0cbe6d9e test/gc/TestSystemGC.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/TestSystemGC.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,46 @@ +/* +* Copyright (c) 2013, 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 TestSystemGC + * @key gc + * @summary Runs System.gc() with different flags. + * @run main/othervm TestSystemGC + * @run main/othervm -XX:+UseSerialGC TestSystemGC + * @run main/othervm -XX:+UseParNewGC TestSystemGC + * @run main/othervm -XX:+UseParallelGC TestSystemGC + * @run main/othervm -XX:+UseParallelGC -XX:-UseParallelOldGC TestSystemGC + * @run main/othervm -XX:+UseConcMarkSweepGC TestSystemGC + * @run main/othervm -XX:+UseConcMarkSweepGC -XX:+ExplicitGCInvokesConcurrent TestSystemGC + * @run main/othervm -XX:+UseConcMarkSweepGC -XX:+ExplicitGCInvokesConcurrent -XX:-UseParNewGC TestSystemGC + * @run main/othervm -XX:+UseG1GC TestSystemGC + * @run main/othervm -XX:+UseG1GC -XX:+ExplicitGCInvokesConcurrent TestSystemGC + * @run main/othervm -XX:+UseLargePages TestSystemGC + * @run main/othervm -XX:+UseLargePages -XX:+UseLargePagesInMetaspace TestSystemGC + */ + +public class TestSystemGC { + public static void main(String args[]) throws Exception { + System.gc(); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/gc/arguments/TestHeapFreeRatio.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/arguments/TestHeapFreeRatio.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2013, 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 TestHeapFreeRatio + * @key gc + * @bug 8025661 + * @summary Test parsing of -Xminf and -Xmaxf + * @library /testlibrary + * @run main/othervm TestHeapFreeRatio + */ + +import com.oracle.java.testlibrary.*; + +public class TestHeapFreeRatio { + + enum Validation { + VALID, + MIN_INVALID, + MAX_INVALID, + COMBINATION_INVALID + } + + private static void testMinMaxFreeRatio(String min, String max, Validation type) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-Xminf" + min, + "-Xmaxf" + max, + "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + switch (type) { + case VALID: + output.shouldNotContain("Error"); + output.shouldHaveExitValue(0); + break; + case MIN_INVALID: + output.shouldContain("Bad min heap free percentage size: -Xminf" + min); + output.shouldContain("Error"); + output.shouldHaveExitValue(1); + break; + case MAX_INVALID: + output.shouldContain("Bad max heap free percentage size: -Xmaxf" + max); + output.shouldContain("Error"); + output.shouldHaveExitValue(1); + break; + case COMBINATION_INVALID: + output.shouldContain("must be less than or equal to MaxHeapFreeRatio"); + output.shouldContain("Error"); + output.shouldHaveExitValue(1); + break; + default: + throw new IllegalStateException("Must specify expected validation type"); + } + + System.out.println(output.getOutput()); + } + + public static void main(String args[]) throws Exception { + testMinMaxFreeRatio( "0.1", "0.5", Validation.VALID); + testMinMaxFreeRatio( ".1", ".5", Validation.VALID); + testMinMaxFreeRatio( "0.5", "0.5", Validation.VALID); + + testMinMaxFreeRatio("-0.1", "0.5", Validation.MIN_INVALID); + testMinMaxFreeRatio( "1.1", "0.5", Validation.MIN_INVALID); + testMinMaxFreeRatio("=0.1", "0.5", Validation.MIN_INVALID); + testMinMaxFreeRatio("0.1f", "0.5", Validation.MIN_INVALID); + testMinMaxFreeRatio( + "INVALID", "0.5", Validation.MIN_INVALID); + testMinMaxFreeRatio( + "2147483647", "0.5", Validation.MIN_INVALID); + + testMinMaxFreeRatio( "0.1", "-0.5", Validation.MAX_INVALID); + testMinMaxFreeRatio( "0.1", "1.5", Validation.MAX_INVALID); + testMinMaxFreeRatio( "0.1", "0.5f", Validation.MAX_INVALID); + testMinMaxFreeRatio( "0.1", "=0.5", Validation.MAX_INVALID); + testMinMaxFreeRatio( + "0.1", "INVALID", Validation.MAX_INVALID); + testMinMaxFreeRatio( + "0.1", "2147483647", Validation.MAX_INVALID); + + testMinMaxFreeRatio( "0.5", "0.1", Validation.COMBINATION_INVALID); + testMinMaxFreeRatio( ".5", ".10", Validation.COMBINATION_INVALID); + testMinMaxFreeRatio("0.12","0.100", Validation.COMBINATION_INVALID); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/gc/g1/TestHumongousAllocInitialMark.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/TestHumongousAllocInitialMark.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2012, 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 TestHumongousAllocInitialMark + * @bug 7168848 + * @summary G1: humongous object allocations should initiate marking cycles when necessary + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.*; + +public class TestHumongousAllocInitialMark { + private static final int heapSize = 200; // MB + private static final int heapRegionSize = 1; // MB + private static final int initiatingHeapOccupancyPercent = 50; // % + + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UseG1GC", + "-Xms" + heapSize + "m", + "-Xmx" + heapSize + "m", + "-XX:G1HeapRegionSize=" + heapRegionSize + "m", + "-XX:InitiatingHeapOccupancyPercent=" + initiatingHeapOccupancyPercent, + "-XX:+PrintGC", + HumongousObjectAllocator.class.getName()); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("GC pause (G1 Humongous Allocation) (young) (initial-mark)"); + output.shouldNotContain("Full GC"); + output.shouldHaveExitValue(0); + } + + static class HumongousObjectAllocator { + private static byte[] dummy; + + public static void main(String [] args) throws Exception { + // Make object size 75% of region size + final int humongousObjectSize = + (int)(heapRegionSize * 1024 * 1024 * 0.75); + + // Number of objects to allocate to go above IHOP + final int humongousObjectAllocations = + (int)((heapSize * initiatingHeapOccupancyPercent / 100.0) / heapRegionSize) + 1; + + // Allocate + for (int i = 1; i <= humongousObjectAllocations; i++) { + System.out.println("Allocating humongous object " + i + "/" + humongousObjectAllocations + + " of size " + humongousObjectSize + " bytes"); + dummy = new byte[humongousObjectSize]; + } + } + } +} + diff -r 6795fcebbf42 -r c31f0cbe6d9e test/gc/startup_warnings/TestCMS.java --- a/test/gc/startup_warnings/TestCMS.java Mon Oct 21 14:08:09 2013 +0100 +++ b/test/gc/startup_warnings/TestCMS.java Sun Nov 03 07:50:24 2013 +0000 @@ -38,7 +38,7 @@ public static void main(String args[]) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseConcMarkSweepGC", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldNotContain("warning"); + output.shouldNotContain("deprecated"); output.shouldNotContain("error"); output.shouldHaveExitValue(0); } diff -r 6795fcebbf42 -r c31f0cbe6d9e test/gc/startup_warnings/TestCMSNoIncrementalMode.java --- a/test/gc/startup_warnings/TestCMSNoIncrementalMode.java Mon Oct 21 14:08:09 2013 +0100 +++ b/test/gc/startup_warnings/TestCMSNoIncrementalMode.java Sun Nov 03 07:50:24 2013 +0000 @@ -37,7 +37,7 @@ public static void main(String args[]) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseConcMarkSweepGC", "-XX:-CMSIncrementalMode", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldNotContain("warning"); + output.shouldNotContain("deprecated"); output.shouldNotContain("error"); output.shouldHaveExitValue(0); } diff -r 6795fcebbf42 -r c31f0cbe6d9e test/gc/startup_warnings/TestG1.java --- a/test/gc/startup_warnings/TestG1.java Mon Oct 21 14:08:09 2013 +0100 +++ b/test/gc/startup_warnings/TestG1.java Sun Nov 03 07:50:24 2013 +0000 @@ -37,7 +37,7 @@ public static void main(String args[]) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldNotContain("warning"); + output.shouldNotContain("deprecated"); output.shouldNotContain("error"); output.shouldHaveExitValue(0); } diff -r 6795fcebbf42 -r c31f0cbe6d9e test/gc/startup_warnings/TestParNewCMS.java --- a/test/gc/startup_warnings/TestParNewCMS.java Mon Oct 21 14:08:09 2013 +0100 +++ b/test/gc/startup_warnings/TestParNewCMS.java Sun Nov 03 07:50:24 2013 +0000 @@ -38,7 +38,7 @@ public static void main(String args[]) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseParNewGC", "-XX:+UseConcMarkSweepGC", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldNotContain("warning"); + output.shouldNotContain("deprecated"); output.shouldNotContain("error"); output.shouldHaveExitValue(0); } diff -r 6795fcebbf42 -r c31f0cbe6d9e test/gc/startup_warnings/TestParallelGC.java --- a/test/gc/startup_warnings/TestParallelGC.java Mon Oct 21 14:08:09 2013 +0100 +++ b/test/gc/startup_warnings/TestParallelGC.java Sun Nov 03 07:50:24 2013 +0000 @@ -38,7 +38,7 @@ public static void main(String args[]) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseParallelGC", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldNotContain("warning"); + output.shouldNotContain("deprecated"); output.shouldNotContain("error"); output.shouldHaveExitValue(0); } diff -r 6795fcebbf42 -r c31f0cbe6d9e test/gc/startup_warnings/TestParallelScavengeSerialOld.java --- a/test/gc/startup_warnings/TestParallelScavengeSerialOld.java Mon Oct 21 14:08:09 2013 +0100 +++ b/test/gc/startup_warnings/TestParallelScavengeSerialOld.java Sun Nov 03 07:50:24 2013 +0000 @@ -38,7 +38,7 @@ public static void main(String args[]) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseParallelGC", "-XX:-UseParallelOldGC", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldNotContain("warning"); + output.shouldNotContain("deprecated"); output.shouldNotContain("error"); output.shouldHaveExitValue(0); } diff -r 6795fcebbf42 -r c31f0cbe6d9e test/gc/startup_warnings/TestSerialGC.java --- a/test/gc/startup_warnings/TestSerialGC.java Mon Oct 21 14:08:09 2013 +0100 +++ b/test/gc/startup_warnings/TestSerialGC.java Sun Nov 03 07:50:24 2013 +0000 @@ -38,7 +38,7 @@ public static void main(String args[]) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseSerialGC", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldNotContain("warning"); + output.shouldNotContain("deprecated"); output.shouldNotContain("error"); output.shouldHaveExitValue(0); } diff -r 6795fcebbf42 -r c31f0cbe6d9e test/runtime/8024804/RegisterNatives.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/8024804/RegisterNatives.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2013, 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 8024804 + * @summary registerNatives() interface resolution should receive IAE + * @run main RegisterNatives + */ +public class RegisterNatives { + interface I { void registerNatives(); } + interface J extends I {} + static class B implements J { public void registerNatives() { System.out.println("B"); } } + public static void main(String... args) { + System.out.println("Regression test for JDK-8024804, crash when InterfaceMethodref resolves to Object.registerNatives\n"); + J val = new B(); + try { + val.registerNatives(); + } catch (IllegalAccessError e) { + System.out.println("TEST PASSES - according to current JVM spec, IAE expected\n"); + return; + } + System.out.println("TEST FAILS - no IAE resulted\n"); + System.exit(1); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/runtime/8026394/InterfaceObjectTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/8026394/InterfaceObjectTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013, 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 8026394 + * @summary clone() and finalize() interface resolution should not receive IAE + * @run main InterfaceObjectTest + */ +interface IClone extends Cloneable { + void finalize() throws Throwable; + Object clone(); +} + +interface ICloneExtend extends IClone { } + +public class InterfaceObjectTest implements ICloneExtend { + + public Object clone() { + System.out.println("In InterfaceObjectTest's clone() method\n"); + return null; + } + + public void finalize() throws Throwable { + try { + System.out.println("In InterfaceObjectTest's finalize() method\n"); + } catch (Throwable t) { + throw new AssertionError(t); + } + } + + public static void tryIt(ICloneExtend o1) { + try { + Object o2 = o1.clone(); + o1.finalize(); + } catch (Throwable t) { + if (t instanceof IllegalAccessError) { + System.out.println("TEST FAILS - IAE resulted\n"); + System.exit(1); + } + } + } + + public static void main(String[] args) { + InterfaceObjectTest o1 = new InterfaceObjectTest(); + tryIt(o1); + System.out.println("TEST PASSES - no IAE resulted\n"); + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/runtime/CommandLine/PrintGCApplicationConcurrentTime.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/CommandLine/PrintGCApplicationConcurrentTime.java Sun Nov 03 07:50:24 2013 +0000 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013, 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 8026041 + * @run main/othervm -XX:+PrintGCApplicationConcurrentTime -Xcomp PrintGCApplicationConcurrentTime + */ + +public class PrintGCApplicationConcurrentTime { + + public static void main(String args[]) throws Exception { + } +} diff -r 6795fcebbf42 -r c31f0cbe6d9e test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java --- a/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java Mon Oct 21 14:08:09 2013 +0100 +++ b/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java Sun Nov 03 07:50:24 2013 +0000 @@ -59,7 +59,7 @@ // If we are on MacOSX, test if JMap tool is signed, otherwise return // since test will fail with privilege error. if (Platform.isOSX()) { - String jmapToolPath = JDKToolFinder.getCurrentJDKTool("jmap"); + String jmapToolPath = JDKToolFinder.getTestJDKTool("jmap"); ProcessBuilder codesignProcessBuilder = new ProcessBuilder( "codesign", "-v", jmapToolPath); Process codesignProcess = codesignProcessBuilder.start(); @@ -107,7 +107,7 @@ System.out.println("Extracted pid: " + pid); JDKToolLauncher jMapLauncher = JDKToolLauncher - .create("jmap", false); + .createUsingTestJDK("jmap"); jMapLauncher.addToolArg("-dump:format=b,file=" + pid + "-" + HEAP_DUMP_FILE_NAME); jMapLauncher.addToolArg(String.valueOf(pid)); diff -r 6795fcebbf42 -r c31f0cbe6d9e test/testlibrary/com/oracle/java/testlibrary/JDKToolLauncher.java --- a/test/testlibrary/com/oracle/java/testlibrary/JDKToolLauncher.java Mon Oct 21 14:08:09 2013 +0100 +++ b/test/testlibrary/com/oracle/java/testlibrary/JDKToolLauncher.java Sun Nov 03 07:50:24 2013 +0000 @@ -56,7 +56,7 @@ if (useCompilerJDK) { executable = JDKToolFinder.getJDKTool(tool); } else { - executable = JDKToolFinder.getCurrentJDKTool(tool); + executable = JDKToolFinder.getTestJDKTool(tool); } vmArgs.addAll(Arrays.asList(ProcessTools.getPlatformSpecificVMArgs())); } @@ -74,17 +74,15 @@ } /** - * Creates a new JDKToolLauncher for the specified tool. + * Creates a new JDKToolLauncher for the specified tool in the Tested JDK. * * @param tool * The name of the tool - * @param useCompilerPath - * If true use the compiler JDK path, otherwise use the tested - * JDK path. + * * @return A new JDKToolLauncher */ - public static JDKToolLauncher create(String tool, boolean useCompilerJDK) { - return new JDKToolLauncher(tool, useCompilerJDK); + public static JDKToolLauncher createUsingTestJDK(String tool) { + return new JDKToolLauncher(tool, false); } /** @@ -102,7 +100,7 @@ * @return The JDKToolLauncher instance */ public JDKToolLauncher addVMArg(String arg) { - vmArgs.add("-J" + arg); + vmArgs.add(arg); return this; } @@ -126,7 +124,10 @@ public String[] getCommand() { List command = new ArrayList(); command.add(executable); - command.addAll(vmArgs); + // Add -J in front of all vmArgs + for (String arg : vmArgs) { + command.add("-J" + arg); + } command.addAll(toolArgs); return command.toArray(new String[command.size()]); }