OpenJDK / jdk8 / jdk8 / hotspot
changeset 5779:c31f0cbe6d9e
Merge
author | chegar |
---|---|
date | Sun, 03 Nov 2013 07:50:24 +0000 |
parents | 6795fcebbf42 ddc3758f68db |
children | 0611ce949aaa |
files | src/share/vm/memory/metablock.cpp src/share/vm/memory/metablock.hpp test/compiler/8013496/Test8013496.sh test/compiler/intrinsics/mathexact/CondTest.java test/compiler/intrinsics/mathexact/ConstantTest.java test/compiler/intrinsics/mathexact/LoadTest.java test/compiler/intrinsics/mathexact/LoopDependentTest.java test/compiler/intrinsics/mathexact/NonConstantTest.java test/gc/7168848/HumongousAlloc.java |
diffstat | 278 files changed, 10649 insertions(+), 2369 deletions(-) [+] |
line wrap: on
line diff
--- 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
--- 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); } }
--- /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<HeapRegion> { + 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<HeapRegion> heapRegionIterator() { + return new HeapRegionIterator(addr); + } + + public G1HeapRegionTable(Address addr) { + super(addr); + } +}
--- 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<HeapRegion> { - 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<HeapRegion> heapRegionIterator() { - return new HeapRegionIterator(addr); + return regions().heapRegionIterator(); } public HeapRegionSeq(Address addr) {
--- 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();
--- 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 {
--- 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() {
--- 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); } }
--- 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); } }
--- 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() {
--- 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() {
--- 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) {
--- 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); } }
--- 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;
--- 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); } }
--- 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); } }
--- 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
--- 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;
--- 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); } }
--- 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) { <derived class> obj = new <derived class>; - 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.
--- 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); } }
--- 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() {
--- 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() {
--- 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/%
--- 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
--- 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)" && \
--- 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
--- 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
--- 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
--- 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
--- 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))
--- 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
--- 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
--- 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)
--- 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) $@
--- 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
--- 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
--- 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 $@
--- 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); }
--- 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); }
--- 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()));
--- 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, \
--- 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,
--- 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
--- 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(); }
--- 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)
--- 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-
--- 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
--- 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); }
--- 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(); }
--- 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, \
--- /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
--- /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
--- 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;
--- 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
--- 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;
--- 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
--- 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);
--- 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);
--- 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
--- 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;
--- 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;
--- 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);
--- 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);
--- 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"
--- 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"
--- 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));
--- 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) %{
--- 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
--- 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 ) {
--- 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;
--- 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) {}
--- 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);
--- 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);
--- 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); };
--- 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
--- 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);
--- 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) {
--- 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();)
--- 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 {
--- 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.
--- 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());
--- 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);
--- 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
--- 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)); }
--- 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);
--- 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()); }
--- 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);
--- 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
--- 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;
--- 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 */ };
--- 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
--- 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 */ };
--- 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") \ \
--- 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; \
--- 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); + ) +}
--- 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
--- 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();
--- 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); };
--- 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();
--- 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); };
--- 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();
--- 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
--- 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
--- 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)); }
--- 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; +}
--- 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
--- 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; }
--- 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; + } };
--- 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
--- 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; }
--- 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, "");
--- 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") \
--- 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();
--- 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
--- 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(); +}
--- 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<mtCompiler> { 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(); }
--- 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<CompilerThread*>* CompileBroker::_method_threads = NULL; +GrowableArray<CompilerThread*>* 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<CompilerThread*>(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; i<num_threads; i++) { - if (_method_threads->at(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);
--- 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<CompilerThread*>* _method_threads; + static GrowableArray<CompilerThread*>* _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
--- 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; }
--- 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);
--- 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++) {
--- 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 "
--- 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"
--- 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 <init>, 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");
--- 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);
--- 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"
--- 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"
--- 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"
--- 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"
--- 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; -}
--- 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
--- 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<Metachunk>(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
--- 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 T> +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<Metachunk> { + 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<Metablock> { + friend class VMStructs; + public: + Metablock(size_t word_size) : Metabase<Metablock>(word_size) {} +}; + #endif // SHARE_VM_MEMORY_METACHUNK_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<T>* 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()); }
--- 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<Metablock, FreeList> BlockTreeDictionary; typedef BinaryTreeDictionary<Metachunk, FreeList> 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<Metachunk> 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<mtInternal> { + 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<mtClass> { 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
--- 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,
--- 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 <clinit> 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;
--- 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<u1>* 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
--- 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; }
--- 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<Method*>* 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<Klass*>* 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<Klass*>(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<Klass*>(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<int>(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<Method*>(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<int>(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<Klass*>(loader_data, secondary_supers()); } set_secondary_supers(NULL); @@ -413,24 +421,32 @@ set_transitive_interfaces(NULL); set_local_interfaces(NULL); - MetadataFactory::free_array<jushort>(loader_data, fields()); + if (fields() != NULL && !fields()->is_shared()) { + MetadataFactory::free_array<jushort>(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<jushort>(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); }
--- 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
--- 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(); }
--- 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<int> _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(); +}
--- 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); }