# HG changeset patch # User lana # Date 1431057072 25200 # Node ID febd2373771cca0b4c4d1979ff01549a5c969c2d # Parent a4b1c7d6317a229e4dd0155307684175b612977b# Parent 6c651fa22980071918057768e010dbe4e0bc8e88 Merge diff -r a4b1c7d6317a -r febd2373771c hotspot/agent/src/os/bsd/libproc_impl.c --- a/hotspot/agent/src/os/bsd/libproc_impl.c Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/agent/src/os/bsd/libproc_impl.c Thu May 07 20:51:12 2015 -0700 @@ -215,7 +215,12 @@ return NULL; } - strncpy(newlib->name, libname, sizeof(newlib->name)); + if (strlen(libname) >= sizeof(newlib->name)) { + print_debug("libname %s too long\n", libname); + return NULL; + } + strcpy(newlib->name, libname); + newlib->base = base; if (fd == -1) { diff -r a4b1c7d6317a -r febd2373771c hotspot/agent/src/os/linux/libproc_impl.c --- a/hotspot/agent/src/os/linux/libproc_impl.c Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/agent/src/os/linux/libproc_impl.c Thu May 07 20:51:12 2015 -0700 @@ -159,7 +159,12 @@ return NULL; } - strncpy(newlib->name, libname, sizeof(newlib->name)); + if (strlen(libname) >= sizeof(newlib->name)) { + print_debug("libname %s too long\n", libname); + return NULL; + } + strcpy(newlib->name, libname); + newlib->base = base; if (fd == -1) { diff -r a4b1c7d6317a -r febd2373771c hotspot/agent/src/share/classes/com/sun/java/swing/action/ActionManager.java --- a/hotspot/agent/src/share/classes/com/sun/java/swing/action/ActionManager.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/agent/src/share/classes/com/sun/java/swing/action/ActionManager.java Thu May 07 20:51:12 2015 -0700 @@ -46,6 +46,11 @@ return manager; } + protected static void setInstance(ActionManager m) + { + manager = m; + } + protected abstract void addActions(); protected void addAction(String cmdname, Action action) @@ -90,6 +95,6 @@ private HashMap actions; private static ActionUtilities utilities = new ActionUtilities(); - protected static ActionManager manager; + private static ActionManager manager; } diff -r a4b1c7d6317a -r febd2373771c hotspot/agent/src/share/classes/com/sun/java/swing/ui/CommonToolBar.java --- a/hotspot/agent/src/share/classes/com/sun/java/swing/ui/CommonToolBar.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/agent/src/share/classes/com/sun/java/swing/ui/CommonToolBar.java Thu May 07 20:51:12 2015 -0700 @@ -46,7 +46,7 @@ { this.manager = manager; statusBar = status; - buttonSize = new Dimension(CommonUI.buttconPrefSize); + buttonSize = new Dimension(CommonUI.getButtconPrefSize()); buttonInsets = new Insets(0, 0, 0, 0); addComponents(); } diff -r a4b1c7d6317a -r febd2373771c hotspot/agent/src/share/classes/com/sun/java/swing/ui/CommonUI.java --- a/hotspot/agent/src/share/classes/com/sun/java/swing/ui/CommonUI.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/agent/src/share/classes/com/sun/java/swing/ui/CommonUI.java Thu May 07 20:51:12 2015 -0700 @@ -373,20 +373,25 @@ comp.setCursor(Cursor.getPredefinedCursor(0)); } - public static final int BUTTON_WIDTH = 100; - public static final int BUTTON_HEIGHT = 26; - public static final int BUTTCON_WIDTH = 28; - public static final int BUTTCON_HEIGHT = 28; - public static final int SM_BUTTON_WIDTH = 72; - public static final int SM_BUTTON_HEIGHT = 26; - public static final int LABEL_WIDTH = 100; - public static final int LABEL_HEIGHT = 20; - public static final int TEXT_WIDTH = 150; - public static final int TEXT_HEIGHT = 20; - public static Dimension buttonPrefSize = new Dimension(100, 26); - public static Dimension buttconPrefSize = new Dimension(28, 28); - public static Dimension smbuttonPrefSize = new Dimension(72, 26); - public static Dimension labelPrefSize = new Dimension(100, 20); - public static Dimension textPrefSize = new Dimension(150, 20); + public static Dimension getButtconPrefSize() + { + return buttconPrefSize; + } + + private static final int BUTTON_WIDTH = 100; + private static final int BUTTON_HEIGHT = 26; + private static final int BUTTCON_WIDTH = 28; + private static final int BUTTCON_HEIGHT = 28; + private static final int SM_BUTTON_WIDTH = 72; + private static final int SM_BUTTON_HEIGHT = 26; + private static final int LABEL_WIDTH = 100; + private static final int LABEL_HEIGHT = 20; + private static final int TEXT_WIDTH = 150; + private static final int TEXT_HEIGHT = 20; + private static final Dimension buttonPrefSize = new Dimension(100, 26); + private static final Dimension buttconPrefSize = new Dimension(28, 28); + private static final Dimension smbuttonPrefSize = new Dimension(72, 26); + private static final Dimension labelPrefSize = new Dimension(100, 20); + private static final Dimension textPrefSize = new Dimension(150, 20); } diff -r a4b1c7d6317a -r febd2373771c hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethodData.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethodData.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethodData.java Thu May 07 20:51:12 2015 -0700 @@ -148,7 +148,7 @@ ParametersTypeData parametersTypeData() { Address base = getAddress().addOffsetTo(origField.getOffset()); int di = (int)parametersTypeDataDi.getValue(base); - if (di == -1) { + if (di == -1 || di == -2) { return null; } DataLayout dataLayout = new DataLayout(dataField.getValue(getAddress()), di); diff -r a4b1c7d6317a -r febd2373771c hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1CollectedHeap.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1CollectedHeap.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1CollectedHeap.java Thu May 07 20:51:12 2015 -0700 @@ -29,9 +29,9 @@ import java.util.Observer; import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.gc_interface.CollectedHeap; import sun.jvm.hotspot.gc_interface.CollectedHeapName; import sun.jvm.hotspot.memory.MemRegion; -import sun.jvm.hotspot.memory.SharedHeap; import sun.jvm.hotspot.memory.SpaceClosure; import sun.jvm.hotspot.runtime.VM; import sun.jvm.hotspot.runtime.VMObjectFactory; @@ -41,7 +41,7 @@ // Mirror class for G1CollectedHeap. -public class G1CollectedHeap extends SharedHeap { +public class G1CollectedHeap extends CollectedHeap { // HeapRegionManager _hrm; static private long hrmFieldOffset; // MemRegion _g1_reserved; diff -r a4b1c7d6317a -r febd2373771c hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_interface/CollectedHeap.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_interface/CollectedHeap.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_interface/CollectedHeap.java Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ import sun.jvm.hotspot.runtime.*; import sun.jvm.hotspot.types.*; -public class CollectedHeap extends VMObject { +public abstract class CollectedHeap extends VMObject { private static long reservedFieldOffset; static { @@ -73,9 +73,7 @@ return reservedRegion().contains(a); } - public CollectedHeapName kind() { - return CollectedHeapName.ABSTRACT; - } + public abstract CollectedHeapName kind(); public void print() { printOn(System.out); } public void printOn(PrintStream tty) { diff -r a4b1c7d6317a -r febd2373771c hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_interface/CollectedHeapName.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_interface/CollectedHeapName.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_interface/CollectedHeapName.java Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,8 +31,6 @@ private CollectedHeapName(String name) { this.name = name; } - public static final CollectedHeapName ABSTRACT = new CollectedHeapName("abstract"); - public static final CollectedHeapName SHARED_HEAP = new CollectedHeapName("SharedHeap"); public static final CollectedHeapName GEN_COLLECTED_HEAP = new CollectedHeapName("GenCollectedHeap"); public static final CollectedHeapName G1_COLLECTED_HEAP = new CollectedHeapName("G1CollectedHeap"); public static final CollectedHeapName PARALLEL_SCAVENGE_HEAP = new CollectedHeapName("ParallelScavengeHeap"); diff -r a4b1c7d6317a -r febd2373771c hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/GenCollectedHeap.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/GenCollectedHeap.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/GenCollectedHeap.java Thu May 07 20:51:12 2015 -0700 @@ -33,8 +33,7 @@ import sun.jvm.hotspot.types.*; import sun.jvm.hotspot.utilities.*; -public class GenCollectedHeap extends SharedHeap { - private static CIntegerField nGensField; +public class GenCollectedHeap extends CollectedHeap { private static AddressField youngGenField; private static AddressField oldGenField; @@ -54,7 +53,6 @@ private static synchronized void initialize(TypeDataBase db) { Type type = db.lookupType("GenCollectedHeap"); - nGensField = type.getCIntegerField("_n_gens"); youngGenField = type.getAddressField("_young_gen"); oldGenField = type.getAddressField("_old_gen"); @@ -70,7 +68,7 @@ } public int nGens() { - return (int) nGensField.getValue(addr); + return 2; // Young + Old } public Generation getGen(int i) { diff -r a4b1c7d6317a -r febd2373771c hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/SharedHeap.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/SharedHeap.java Thu May 07 10:19:31 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2002, 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. - * - */ - -package sun.jvm.hotspot.memory; - -import java.io.*; -import java.util.*; - -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.gc_interface.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.types.*; - -public abstract class SharedHeap extends CollectedHeap { - private static VirtualConstructor ctor; - - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) { - Type type = db.lookupType("SharedHeap"); - ctor = new VirtualConstructor(db); - } - - public SharedHeap(Address addr) { - super(addr); - } - - public CollectedHeapName kind() { - return CollectedHeapName.SHARED_HEAP; - } - } diff -r a4b1c7d6317a -r febd2373771c hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -112,11 +112,7 @@ return ""; } public CollectedHeap heap() { - try { - return (CollectedHeap) heapConstructor.instantiateWrapperFor(collectedHeapField.getValue()); - } catch (WrongTypeException e) { - return new CollectedHeap(collectedHeapField.getValue()); - } + return (CollectedHeap) heapConstructor.instantiateWrapperFor(collectedHeapField.getValue()); } public static long getNarrowOopBase() { diff -r a4b1c7d6317a -r febd2373771c hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/VirtualSpace.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/VirtualSpace.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2000, 2002, 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.memory; + +import java.util.*; +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.types.*; + +public class VirtualSpace extends VMObject { + private static AddressField lowField; + private static AddressField highField; + private static AddressField lowBoundaryField; + private static AddressField highBoundaryField; + + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static synchronized void initialize(TypeDataBase db) { + Type type = db.lookupType("VirtualSpace"); + + lowField = type.getAddressField("_low"); + highField = type.getAddressField("_high"); + lowBoundaryField = type.getAddressField("_low_boundary"); + highBoundaryField = type.getAddressField("_high_boundary"); + } + + public VirtualSpace(Address addr) { + super(addr); + } + + public Address low() { return lowField.getValue(addr); } + public Address high() { return highField.getValue(addr); } + public Address lowBoundary() { return lowBoundaryField.getValue(addr); } + public Address highBoundary() { return highBoundaryField.getValue(addr); } + + /** Testers (all sizes are byte sizes) */ + public long committedSize() { return high().minus(low()); } + public long reservedSize() { return highBoundary().minus(lowBoundary()); } + public long uncommittedSize() { return reservedSize() - committedSize(); } + public boolean contains(Address addr) { return (low().lessThanOrEqual(addr) && addr.lessThan(high())); } +} diff -r a4b1c7d6317a -r febd2373771c hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java Thu May 07 20:51:12 2015 -0700 @@ -328,7 +328,7 @@ } public Symbol getUnresolvedStringAt(int which) { - return getSymbolAt(which); + return getSlotAt(which).getSymbol(); } // returns null, if not resolved. diff -r a4b1c7d6317a -r febd2373771c hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/PhaseCFG.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/PhaseCFG.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/PhaseCFG.java Thu May 07 20:51:12 2015 -0700 @@ -42,10 +42,10 @@ private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { Type type = db.lookupType("PhaseCFG"); - numBlocksField = new CIntField(type.getCIntegerField("_num_blocks"), 0); + numBlocksField = new CIntField(type.getCIntegerField("_number_of_blocks"), 0); blocksField = type.getAddressField("_blocks"); bbsField = type.getAddressField("_node_to_block_mapping"); - brootField = type.getAddressField("_broot"); + brootField = type.getAddressField("_root_block"); } private static CIntField numBlocksField; diff -r a4b1c7d6317a -r febd2373771c hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java Thu May 07 20:51:12 2015 -0700 @@ -259,8 +259,7 @@ saProps = new Properties(); URL url = null; try { - url = VM.class.getClassLoader().getResource("sa.properties"); - saProps.load(new BufferedInputStream(url.openStream())); + saProps.load(VM.class.getResourceAsStream("/sa.properties")); } catch (Exception e) { System.err.println("Unable to load properties " + (url == null ? "null" : url.toString()) + diff -r a4b1c7d6317a -r febd2373771c hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VirtualSpace.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VirtualSpace.java Thu May 07 10:19:31 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2000, 2002, 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.runtime; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.types.*; - -public class VirtualSpace extends VMObject { - private static AddressField lowField; - private static AddressField highField; - private static AddressField lowBoundaryField; - private static AddressField highBoundaryField; - - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) { - Type type = db.lookupType("VirtualSpace"); - - lowField = type.getAddressField("_low"); - highField = type.getAddressField("_high"); - lowBoundaryField = type.getAddressField("_low_boundary"); - highBoundaryField = type.getAddressField("_high_boundary"); - } - - public VirtualSpace(Address addr) { - super(addr); - } - - public Address low() { return lowField.getValue(addr); } - public Address high() { return highField.getValue(addr); } - public Address lowBoundary() { return lowBoundaryField.getValue(addr); } - public Address highBoundary() { return highBoundaryField.getValue(addr); } - - /** Testers (all sizes are byte sizes) */ - public long committedSize() { return high().minus(low()); } - public long reservedSize() { return highBoundary().minus(lowBoundary()); } - public long uncommittedSize() { return reservedSize() - committedSize(); } - public boolean contains(Address addr) { return (low().lessThanOrEqual(addr) && addr.lessThan(high())); } -} diff -r a4b1c7d6317a -r febd2373771c hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java Thu May 07 20:51:12 2015 -0700 @@ -314,26 +314,17 @@ //------------------------------------------------------------------------------ // frame::adjust_unextended_sp private void adjustUnextendedSP() { - // If we are returning to a compiled MethodHandle call site, the - // saved_fp will in fact be a saved value of the unextended SP. The - // simplest way to tell whether we are returning to such a call site - // is as follows: + // On x86, sites calling method handle intrinsics and lambda forms are treated + // as any other call site. Therefore, no special action is needed when we are + // returning to any of these call sites. CodeBlob cb = cb(); NMethod senderNm = (cb == null) ? null : cb.asNMethodOrNull(); if (senderNm != null) { - // If the sender PC is a deoptimization point, get the original - // PC. For MethodHandle call site the unextended_sp is stored in - // saved_fp. - if (senderNm.isDeoptMhEntry(getPC())) { - // DEBUG_ONLY(verifyDeoptMhOriginalPc(senderNm, getFP())); - raw_unextendedSP = getFP(); - } - else if (senderNm.isDeoptEntry(getPC())) { - // DEBUG_ONLY(verifyDeoptOriginalPc(senderNm, raw_unextendedSp)); - } - else if (senderNm.isMethodHandleReturn(getPC())) { - raw_unextendedSP = getFP(); + // If the sender PC is a deoptimization point, get the original PC. + if (senderNm.isDeoptEntry(getPC()) || + senderNm.isDeoptMhEntry(getPC())) { + // DEBUG_ONLY(verifyDeoptriginalPc(senderNm, raw_unextendedSp)); } } } diff -r a4b1c7d6317a -r febd2373771c hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java Thu May 07 20:51:12 2015 -0700 @@ -81,53 +81,48 @@ System.out.println(); System.out.println("Heap Usage:"); - if (heap instanceof SharedHeap) { - SharedHeap sharedHeap = (SharedHeap) heap; - if (sharedHeap instanceof GenCollectedHeap) { - GenCollectedHeap genHeap = (GenCollectedHeap) sharedHeap; - for (int n = 0; n < genHeap.nGens(); n++) { - Generation gen = genHeap.getGen(n); - if (gen instanceof sun.jvm.hotspot.memory.DefNewGeneration) { - System.out.println("New Generation (Eden + 1 Survivor Space):"); - printGen(gen); + if (heap instanceof GenCollectedHeap) { + GenCollectedHeap genHeap = (GenCollectedHeap) heap; + for (int n = 0; n < genHeap.nGens(); n++) { + Generation gen = genHeap.getGen(n); + if (gen instanceof sun.jvm.hotspot.memory.DefNewGeneration) { + System.out.println("New Generation (Eden + 1 Survivor Space):"); + printGen(gen); - ContiguousSpace eden = ((DefNewGeneration)gen).eden(); - System.out.println("Eden Space:"); - printSpace(eden); + ContiguousSpace eden = ((DefNewGeneration)gen).eden(); + System.out.println("Eden Space:"); + printSpace(eden); - ContiguousSpace from = ((DefNewGeneration)gen).from(); - System.out.println("From Space:"); - printSpace(from); + ContiguousSpace from = ((DefNewGeneration)gen).from(); + System.out.println("From Space:"); + printSpace(from); - ContiguousSpace to = ((DefNewGeneration)gen).to(); - System.out.println("To Space:"); - printSpace(to); - } else { - System.out.println(gen.name() + ":"); - printGen(gen); - } + ContiguousSpace to = ((DefNewGeneration)gen).to(); + System.out.println("To Space:"); + printSpace(to); + } else { + System.out.println(gen.name() + ":"); + printGen(gen); } - } else if (sharedHeap instanceof G1CollectedHeap) { - G1CollectedHeap g1h = (G1CollectedHeap) sharedHeap; - G1MonitoringSupport g1mm = g1h.g1mm(); - long edenRegionNum = g1mm.edenRegionNum(); - long survivorRegionNum = g1mm.survivorRegionNum(); - HeapRegionSetBase oldSet = g1h.oldSet(); - HeapRegionSetBase humongousSet = g1h.humongousSet(); - long oldRegionNum = oldSet.count().length() - + humongousSet.count().capacity() / HeapRegion.grainBytes(); - printG1Space("G1 Heap:", g1h.n_regions(), - g1h.used(), g1h.capacity()); - System.out.println("G1 Young Generation:"); - printG1Space("Eden Space:", edenRegionNum, - g1mm.edenUsed(), g1mm.edenCommitted()); - printG1Space("Survivor Space:", survivorRegionNum, - g1mm.survivorUsed(), g1mm.survivorCommitted()); - printG1Space("G1 Old Generation:", oldRegionNum, - g1mm.oldUsed(), g1mm.oldCommitted()); - } else { - throw new RuntimeException("unknown SharedHeap type : " + heap.getClass()); } + } else if (heap instanceof G1CollectedHeap) { + G1CollectedHeap g1h = (G1CollectedHeap) heap; + G1MonitoringSupport g1mm = g1h.g1mm(); + long edenRegionNum = g1mm.edenRegionNum(); + long survivorRegionNum = g1mm.survivorRegionNum(); + HeapRegionSetBase oldSet = g1h.oldSet(); + HeapRegionSetBase humongousSet = g1h.humongousSet(); + long oldRegionNum = oldSet.count().length() + + humongousSet.count().capacity() / HeapRegion.grainBytes(); + printG1Space("G1 Heap:", g1h.n_regions(), + g1h.used(), g1h.capacity()); + System.out.println("G1 Young Generation:"); + printG1Space("Eden Space:", edenRegionNum, + g1mm.edenUsed(), g1mm.edenCommitted()); + printG1Space("Survivor Space:", survivorRegionNum, + g1mm.survivorUsed(), g1mm.survivorCommitted()); + printG1Space("G1 Old Generation:", oldRegionNum, + g1mm.oldUsed(), g1mm.oldCommitted()); } else if (heap instanceof ParallelScavengeHeap) { ParallelScavengeHeap psh = (ParallelScavengeHeap) heap; PSYoungGen youngGen = psh.youngGen(); diff -r a4b1c7d6317a -r febd2373771c hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/action/HSDBActionManager.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/action/HSDBActionManager.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/action/HSDBActionManager.java Thu May 07 20:51:12 2015 -0700 @@ -32,10 +32,12 @@ public class HSDBActionManager extends ActionManager { public static ActionManager getInstance() { - if (manager == null) { - manager = new HSDBActionManager(); + ActionManager m = ActionManager.getInstance(); + if (m == null) { + m = new HSDBActionManager(); + ActionManager.setInstance(m); } - return manager; + return m; } protected void addActions() { diff -r a4b1c7d6317a -r febd2373771c hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -799,6 +799,18 @@ writeObjectID(klass.getJavaMirror()); ClassData cd = (ClassData) classDataCache.get(klass); + if (cd == null) { + // The class is not present in the system dictionary, probably Lambda. + // Add it to cache here + if (klass instanceof InstanceKlass) { + InstanceKlass ik = (InstanceKlass) klass; + List fields = getInstanceFields(ik); + int instSize = getSizeForFields(fields); + cd = new ClassData(instSize, fields); + classDataCache.put(ik, cd); + } + } + if (Assert.ASSERTS_ENABLED) { Assert.that(cd != null, "can not get class data for " + klass.getName().asString() + klass.getAddress()); } diff -r a4b1c7d6317a -r febd2373771c hotspot/make/Makefile --- a/hotspot/make/Makefile Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/Makefile Thu May 07 20:51:12 2015 -0700 @@ -98,7 +98,7 @@ COMMON_VM_OPTIMIZED_TARGETS=optimized optimized1 docs export_optimized # JDK directory list -JDK_DIRS=bin include jre lib demo +JDK_DIRS=bin include lib demo all: all_product all_fastdebug @@ -373,33 +373,33 @@ $(install-file) $(EXPORT_LIB_DIR)/%.lib: $(C2_BUILD_DIR)/%.lib $(install-file) -$(EXPORT_JRE_BIN_DIR)/%.diz: $(C2_BUILD_DIR)/%.diz +$(EXPORT_BIN_DIR)/%.diz: $(C2_BUILD_DIR)/%.diz $(install-file) -$(EXPORT_JRE_BIN_DIR)/%.dll: $(C2_BUILD_DIR)/%.dll +$(EXPORT_BIN_DIR)/%.dll: $(C2_BUILD_DIR)/%.dll $(install-file) -$(EXPORT_JRE_BIN_DIR)/%.pdb: $(C2_BUILD_DIR)/%.pdb +$(EXPORT_BIN_DIR)/%.pdb: $(C2_BUILD_DIR)/%.pdb $(install-file) -$(EXPORT_JRE_BIN_DIR)/%.map: $(C2_BUILD_DIR)/%.map +$(EXPORT_BIN_DIR)/%.map: $(C2_BUILD_DIR)/%.map $(install-file) # Unix -$(EXPORT_JRE_LIB_ARCH_DIR)/%.$(LIBRARY_SUFFIX): $(C2_BUILD_DIR)/%.$(LIBRARY_SUFFIX) +$(EXPORT_LIB_ARCH_DIR)/%.$(LIBRARY_SUFFIX): $(C2_BUILD_DIR)/%.$(LIBRARY_SUFFIX) $(install-file) $(EXPORT_SERVER_DIR)/%.$(LIBRARY_SUFFIX): $(C2_BUILD_DIR)/%.$(LIBRARY_SUFFIX) $(install-file) $(EXPORT_SERVER_DIR)/64/%.$(LIBRARY_SUFFIX): $(C2_BUILD_DIR)/%.$(LIBRARY_SUFFIX) $(install-file) -$(EXPORT_JRE_LIB_ARCH_DIR)/%.debuginfo: $(C2_BUILD_DIR)/%.debuginfo +$(EXPORT_LIB_ARCH_DIR)/%.debuginfo: $(C2_BUILD_DIR)/%.debuginfo $(install-file) $(EXPORT_SERVER_DIR)/%.debuginfo: $(C2_BUILD_DIR)/%.debuginfo $(install-file) $(EXPORT_SERVER_DIR)/64/%.debuginfo: $(C2_BUILD_DIR)/%.debuginfo $(install-file) -$(EXPORT_JRE_LIB_ARCH_DIR)/%.diz: $(C2_BUILD_DIR)/%.diz +$(EXPORT_LIB_ARCH_DIR)/%.diz: $(C2_BUILD_DIR)/%.diz $(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 +$(EXPORT_LIB_ARCH_DIR)/%.dSYM: $(C2_BUILD_DIR)/%.dSYM $(install-dir) $(EXPORT_SERVER_DIR)/%.dSYM: $(C2_BUILD_DIR)/%.dSYM $(install-dir) @@ -423,33 +423,33 @@ $(install-file) $(EXPORT_LIB_DIR)/%.lib: $(C1_BUILD_DIR)/%.lib $(install-file) -$(EXPORT_JRE_BIN_DIR)/%.diz: $(C1_BUILD_DIR)/%.diz +$(EXPORT_BIN_DIR)/%.diz: $(C1_BUILD_DIR)/%.diz $(install-file) -$(EXPORT_JRE_BIN_DIR)/%.dll: $(C1_BUILD_DIR)/%.dll +$(EXPORT_BIN_DIR)/%.dll: $(C1_BUILD_DIR)/%.dll $(install-file) -$(EXPORT_JRE_BIN_DIR)/%.pdb: $(C1_BUILD_DIR)/%.pdb +$(EXPORT_BIN_DIR)/%.pdb: $(C1_BUILD_DIR)/%.pdb $(install-file) -$(EXPORT_JRE_BIN_DIR)/%.map: $(C1_BUILD_DIR)/%.map +$(EXPORT_BIN_DIR)/%.map: $(C1_BUILD_DIR)/%.map $(install-file) # Unix -$(EXPORT_JRE_LIB_ARCH_DIR)/%.$(LIBRARY_SUFFIX): $(C1_BUILD_DIR)/%.$(LIBRARY_SUFFIX) +$(EXPORT_LIB_ARCH_DIR)/%.$(LIBRARY_SUFFIX): $(C1_BUILD_DIR)/%.$(LIBRARY_SUFFIX) $(install-file) $(EXPORT_CLIENT_DIR)/%.$(LIBRARY_SUFFIX): $(C1_BUILD_DIR)/%.$(LIBRARY_SUFFIX) $(install-file) $(EXPORT_CLIENT_DIR)/64/%.$(LIBRARY_SUFFIX): $(C1_BUILD_DIR)/%.$(LIBRARY_SUFFIX) $(install-file) -$(EXPORT_JRE_LIB_ARCH_DIR)/%.debuginfo: $(C1_BUILD_DIR)/%.debuginfo +$(EXPORT_LIB_ARCH_DIR)/%.debuginfo: $(C1_BUILD_DIR)/%.debuginfo $(install-file) $(EXPORT_CLIENT_DIR)/%.debuginfo: $(C1_BUILD_DIR)/%.debuginfo $(install-file) $(EXPORT_CLIENT_DIR)/64/%.debuginfo: $(C1_BUILD_DIR)/%.debuginfo $(install-file) -$(EXPORT_JRE_LIB_ARCH_DIR)/%.diz: $(C1_BUILD_DIR)/%.diz +$(EXPORT_LIB_ARCH_DIR)/%.diz: $(C1_BUILD_DIR)/%.diz $(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 +$(EXPORT_LIB_ARCH_DIR)/%.dSYM: $(C1_BUILD_DIR)/%.dSYM $(install-dir) $(EXPORT_CLIENT_DIR)/%.dSYM: $(C1_BUILD_DIR)/%.dSYM $(install-dir) @@ -473,28 +473,28 @@ $(install-file) $(EXPORT_LIB_DIR)/%.lib: $(MINIMAL1_BUILD_DIR)/%.lib $(install-file) -$(EXPORT_JRE_BIN_DIR)/%.diz: $(MINIMAL1_BUILD_DIR)/%.diz +$(EXPORT_BIN_DIR)/%.diz: $(MINIMAL1_BUILD_DIR)/%.diz $(install-file) -$(EXPORT_JRE_BIN_DIR)/%.dll: $(MINIMAL1_BUILD_DIR)/%.dll +$(EXPORT_BIN_DIR)/%.dll: $(MINIMAL1_BUILD_DIR)/%.dll $(install-file) -$(EXPORT_JRE_BIN_DIR)/%.pdb: $(MINIMAL1_BUILD_DIR)/%.pdb +$(EXPORT_BIN_DIR)/%.pdb: $(MINIMAL1_BUILD_DIR)/%.pdb $(install-file) -$(EXPORT_JRE_BIN_DIR)/%.map: $(MINIMAL1_BUILD_DIR)/%.map +$(EXPORT_BIN_DIR)/%.map: $(MINIMAL1_BUILD_DIR)/%.map $(install-file) # Unix -$(EXPORT_JRE_LIB_ARCH_DIR)/%.$(LIBRARY_SUFFIX): $(MINIMAL1_BUILD_DIR)/%.$(LIBRARY_SUFFIX) +$(EXPORT_LIB_ARCH_DIR)/%.$(LIBRARY_SUFFIX): $(MINIMAL1_BUILD_DIR)/%.$(LIBRARY_SUFFIX) $(install-file) $(EXPORT_MINIMAL_DIR)/%.$(LIBRARY_SUFFIX): $(MINIMAL1_BUILD_DIR)/%.$(LIBRARY_SUFFIX) $(install-file) $(EXPORT_MINIMAL_DIR)/64/%.$(LIBRARY_SUFFIX): $(MINIMAL1_BUILD_DIR)/%.$(LIBRARY_SUFFIX) $(install-file) -$(EXPORT_JRE_LIB_ARCH_DIR)/%.debuginfo: $(MINIMAL1_BUILD_DIR)/%.debuginfo +$(EXPORT_LIB_ARCH_DIR)/%.debuginfo: $(MINIMAL1_BUILD_DIR)/%.debuginfo $(install-file) $(EXPORT_MINIMAL_DIR)/%.debuginfo: $(MINIMAL1_BUILD_DIR)/%.debuginfo $(install-file) $(EXPORT_MINIMAL_DIR)/64/%.debuginfo: $(MINIMAL1_BUILD_DIR)/%.debuginfo $(install-file) -$(EXPORT_JRE_LIB_ARCH_DIR)/%.diz: $(MINIMAL1_BUILD_DIR)/%.diz +$(EXPORT_LIB_ARCH_DIR)/%.diz: $(MINIMAL1_BUILD_DIR)/%.diz $(install-file) $(EXPORT_MINIMAL_DIR)/64/%.diz: $(MINIMAL1_BUILD_DIR)/%.diz $(install-file) @@ -509,11 +509,11 @@ $(EXPORT_INCLUDE_DIR)/%: $(ZERO_BUILD_DIR)/../generated/jvmtifiles/% $(install-file) # Unix -$(EXPORT_JRE_LIB_ARCH_DIR)/%.$(LIBRARY_SUFFIX): $(ZERO_BUILD_DIR)/%.$(LIBRARY_SUFFIX) +$(EXPORT_LIB_ARCH_DIR)/%.$(LIBRARY_SUFFIX): $(ZERO_BUILD_DIR)/%.$(LIBRARY_SUFFIX) $(install-file) -$(EXPORT_JRE_LIB_ARCH_DIR)/%.debuginfo: $(ZERO_BUILD_DIR)/%.debuginfo +$(EXPORT_LIB_ARCH_DIR)/%.debuginfo: $(ZERO_BUILD_DIR)/%.debuginfo $(install-file) -$(EXPORT_JRE_LIB_ARCH_DIR)/%.diz: $(ZERO_BUILD_DIR)/%.diz +$(EXPORT_LIB_ARCH_DIR)/%.diz: $(ZERO_BUILD_DIR)/%.diz $(install-file) $(EXPORT_SERVER_DIR)/%.$(LIBRARY_SUFFIX): $(ZERO_BUILD_DIR)/%.$(LIBRARY_SUFFIX) $(install-file) @@ -522,7 +522,7 @@ $(EXPORT_SERVER_DIR)/%.diz: $(ZERO_BUILD_DIR)/%.diz $(install-file) # MacOS X -$(EXPORT_JRE_LIB_ARCH_DIR)/%.dSYM: $(ZERO_BUILD_DIR)/%.dSYM +$(EXPORT_LIB_ARCH_DIR)/%.dSYM: $(ZERO_BUILD_DIR)/%.dSYM $(install-dir) $(EXPORT_SERVER_DIR)/%.dSYM: $(ZERO_BUILD_DIR)/%.dSYM $(install-dir) @@ -536,11 +536,11 @@ $(EXPORT_INCLUDE_DIR)/%: $(CORE_BUILD_DIR)/../generated/jvmtifiles/% $(install-file) # Unix -$(EXPORT_JRE_LIB_ARCH_DIR)/%.$(LIBRARY_SUFFIX): $(CORE_BUILD_DIR)/%.$(LIBRARY_SUFFIX) +$(EXPORT_LIB_ARCH_DIR)/%.$(LIBRARY_SUFFIX): $(CORE_BUILD_DIR)/%.$(LIBRARY_SUFFIX) $(install-file) -$(EXPORT_JRE_LIB_ARCH_DIR)/%.debuginfo: $(CORE_BUILD_DIR)/%.debuginfo +$(EXPORT_LIB_ARCH_DIR)/%.debuginfo: $(CORE_BUILD_DIR)/%.debuginfo $(install-file) -$(EXPORT_JRE_LIB_ARCH_DIR)/%.diz: $(CORE_BUILD_DIR)/%.diz +$(EXPORT_LIB_ARCH_DIR)/%.diz: $(CORE_BUILD_DIR)/%.diz $(install-file) $(EXPORT_SERVER_DIR)/%.$(LIBRARY_SUFFIX): $(CORE_BUILD_DIR)/%.$(LIBRARY_SUFFIX) $(install-file) @@ -558,11 +558,11 @@ $(EXPORT_INCLUDE_DIR)/%: $(SHARK_BUILD_DIR)/../generated/jvmtifiles/% $(install-file) # Unix -$(EXPORT_JRE_LIB_ARCH_DIR)/%.$(LIBRARY_SUFFIX): $(SHARK_BUILD_DIR)/%.$(LIBRARY_SUFFIX) +$(EXPORT_LIB_ARCH_DIR)/%.$(LIBRARY_SUFFIX): $(SHARK_BUILD_DIR)/%.$(LIBRARY_SUFFIX) $(install-file) -$(EXPORT_JRE_LIB_ARCH_DIR)/%.debuginfo): $(SHARK_BUILD_DIR)/%.debuginfo +$(EXPORT_LIB_ARCH_DIR)/%.debuginfo): $(SHARK_BUILD_DIR)/%.debuginfo $(install-file) -$(EXPORT_JRE_LIB_ARCH_DIR)/%.diz: $(SHARK_BUILD_DIR)/%.diz +$(EXPORT_LIB_ARCH_DIR)/%.diz: $(SHARK_BUILD_DIR)/%.diz $(install-file) $(EXPORT_SERVER_DIR)/%.$(LIBRARY_SUFFIX): $(SHARK_BUILD_DIR)/%.$(LIBRARY_SUFFIX) $(install-file) @@ -571,7 +571,7 @@ $(EXPORT_SERVER_DIR)/%.diz: $(SHARK_BUILD_DIR)/%.diz $(install-file) # MacOS X -$(EXPORT_JRE_LIB_ARCH_DIR)/%.dSYM: $(SHARK_BUILD_DIR)/%.dSYM +$(EXPORT_LIB_ARCH_DIR)/%.dSYM: $(SHARK_BUILD_DIR)/%.dSYM $(install-dir) $(EXPORT_SERVER_DIR)/%.dSYM: $(SHARK_BUILD_DIR)/%.dSYM $(install-dir) diff -r a4b1c7d6317a -r febd2373771c hotspot/make/aix/makefiles/adlc.make --- a/hotspot/make/aix/makefiles/adlc.make Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/aix/makefiles/adlc.make Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -140,13 +140,7 @@ # Note "+="; it is a hook so flags.make can add more flags, like -g or -DFOO. ADLCFLAGS += -q -T -# Normally, debugging is done directly on the ad_*.cpp files. -# But -g will put #line directives in those files pointing back to .ad. -# Some builds of gcc 3.2 have a bug that gets tickled by the extra #line directives -# so skip it for 3.2 and ealier. -ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 3 \) \| \( \( $(CC_VER_MAJOR) = 3 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" ADLCFLAGS += -g -endif ifdef LP64 ADLCFLAGS += -D_LP64 diff -r a4b1c7d6317a -r febd2373771c hotspot/make/aix/makefiles/defs.make --- a/hotspot/make/aix/makefiles/defs.make Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/aix/makefiles/defs.make Thu May 07 20:51:12 2015 -0700 @@ -184,17 +184,17 @@ EXPORT_LIST += $(EXPORT_DOCS_DIR)/platform/jvmti/jvmti.html # client and server subdirectories have symbolic links to ../libjsig.so -EXPORT_LIST += $(EXPORT_JRE_LIB_ARCH_DIR)/libjsig.$(LIBRARY_SUFFIX) +EXPORT_LIST += $(EXPORT_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 +# EXPORT_LIST += $(EXPORT_LIB_ARCH_DIR)/libjsig.diz # else -# EXPORT_LIST += $(EXPORT_JRE_LIB_ARCH_DIR)/libjsig.debuginfo +# EXPORT_LIST += $(EXPORT_LIB_ARCH_DIR)/libjsig.debuginfo # 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 +EXPORT_SERVER_DIR = $(EXPORT_LIB_ARCH_DIR)/server +EXPORT_CLIENT_DIR = $(EXPORT_LIB_ARCH_DIR)/client +EXPORT_MINIMAL_DIR = $(EXPORT_LIB_ARCH_DIR)/minimal ifeq ($(findstring true, $(JVM_VARIANT_SERVER) $(JVM_VARIANT_ZERO) $(JVM_VARIANT_ZEROSHARK) $(JVM_VARIANT_CORE)), true) EXPORT_LIST += $(EXPORT_SERVER_DIR)/Xusage.txt diff -r a4b1c7d6317a -r febd2373771c hotspot/make/aix/makefiles/mapfile-vers-debug --- a/hotspot/make/aix/makefiles/mapfile-vers-debug Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/aix/makefiles/mapfile-vers-debug Thu May 07 20:51:12 2015 -0700 @@ -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. -# +# # # Define public interface. @@ -107,6 +107,7 @@ JVM_GetClassTypeAnnotations; JVM_GetDeclaredClasses; JVM_GetDeclaringClass; + JVM_GetSimpleBinaryName; JVM_GetEnclosingMethodInfo; JVM_GetFieldIxModifiers; JVM_GetFieldTypeAnnotations; diff -r a4b1c7d6317a -r febd2373771c hotspot/make/aix/makefiles/mapfile-vers-product --- a/hotspot/make/aix/makefiles/mapfile-vers-product Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/aix/makefiles/mapfile-vers-product Thu May 07 20:51:12 2015 -0700 @@ -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. -# +# # # Define public interface. @@ -107,6 +107,7 @@ JVM_GetClassTypeAnnotations; JVM_GetDeclaredClasses; JVM_GetDeclaringClass; + JVM_GetSimpleBinaryName; JVM_GetEnclosingMethodInfo; JVM_GetFieldIxModifiers; JVM_GetInheritedAccessControlContext; diff -r a4b1c7d6317a -r febd2373771c hotspot/make/aix/makefiles/ppc64.make --- a/hotspot/make/aix/makefiles/ppc64.make Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/aix/makefiles/ppc64.make Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ # -# Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. -# Copyright 2012, 2013 SAP AG. All rights reserved. +# Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright 2012, 2015 SAP AG. 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 @@ -71,9 +71,6 @@ OPT_CFLAGS/sharedRuntimeTrig.o = $(OPT_CFLAGS/NOOPT) OPT_CFLAGS/sharedRuntimeTrans.o = $(OPT_CFLAGS/NOOPT) -# xlc 10.01 parameters for ipa compile. -QIPA_COMPILE=$(if $(CXX_IS_V10),-qipa) - # Xlc 10.1 parameters for aggressive optimization: # - qhot=level=1: Most aggressive loop optimizations. # - qignerrno: Assume errno is not modified by system calls. @@ -88,7 +85,7 @@ OPT_CFLAGS/synchronizer.o = $(OPT_CFLAGS) -qnoinline # Set all the xlC V10.1 options here. -OPT_CFLAGS += $(QIPA_COMPILE) $(QV10_OPT) $(QV10_OPT_AGGRESSIVE) +OPT_CFLAGS += $(QV10_OPT) $(QV10_OPT_AGGRESSIVE) export OBJECT_MODE=64 diff -r a4b1c7d6317a -r febd2373771c hotspot/make/aix/makefiles/vm.make --- a/hotspot/make/aix/makefiles/vm.make Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/aix/makefiles/vm.make Thu May 07 20:51:12 2015 -0700 @@ -122,7 +122,7 @@ # By default, link the *.o into the library, not the executable. LINK_INTO$(LINK_INTO) = LIBJVM -JDK_LIBDIR = $(JAVA_HOME)/jre/lib/$(LIBARCH) +JDK_LIBDIR = $(JAVA_HOME)/lib/$(LIBARCH) #---------------------------------------------------------------------- # jvm_db & dtrace diff -r a4b1c7d6317a -r febd2373771c hotspot/make/aix/makefiles/xlc.make --- a/hotspot/make/aix/makefiles/xlc.make Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/aix/makefiles/xlc.make Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ # -# Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. -# Copyright (c) 2012, 2013 SAP. All rights reserved. +# Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2015 SAP. 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 @@ -34,13 +34,17 @@ AS = $(CC) -c -# get xlc version -CXX_VERSION := $(shell $(CXX) -qversion 2>&1 | sed -n 's/.*Version: \([0-9.]*\)/\1/p') +# get xlc version which comes as VV.RR.MMMM.LLLL where 'VV' is the version, +# 'RR' is the release, 'MMMM' is the modification and 'LLLL' is the level. +# We only use 'VV.RR.LLLL' to avoid integer overflows in bash when comparing +# the version numbers (some shells only support 32-bit integer compares!). +CXX_VERSION := $(shell $(CXX) -qversion 2>&1 | \ + sed -n 's/.*Version: \([0-9]\{2\}\).\([0-9]\{2\}\).[0-9]\{4\}.\([0-9]\{4\}\)/\1\2\3/p') # xlc 08.00.0000.0023 and higher supports -qtune=balanced -CXX_SUPPORTS_BALANCED_TUNING=$(shell if [ $(subst .,,$(CXX_VERSION)) -ge 080000000023 ] ; then echo "true" ; fi) +CXX_SUPPORTS_BALANCED_TUNING := $(shell if [ $(CXX_VERSION) -ge 08000023 ] ; then echo "true" ; fi) # xlc 10.01 is used with aggressive optimizations to boost performance -CXX_IS_V10=$(shell if [ $(subst .,,$(CXX_VERSION)) -ge 100100000000 ] ; then echo "true" ; fi) +CXX_IS_V10 := $(shell if [ $(CXX_VERSION) -ge 10010000 ] ; then echo "true" ; fi) # check for precompiled headers support diff -r a4b1c7d6317a -r febd2373771c hotspot/make/bsd/makefiles/defs.make --- a/hotspot/make/bsd/makefiles/defs.make Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/bsd/makefiles/defs.make Thu May 07 20:51:12 2015 -0700 @@ -265,23 +265,23 @@ EXPORT_LIST += $(EXPORT_DOCS_DIR)/platform/jvmti/jvmti.html # client and server subdirectories have symbolic links to ../libjsig.so -EXPORT_LIST += $(EXPORT_JRE_LIB_ARCH_DIR)/libjsig.$(LIBRARY_SUFFIX) +EXPORT_LIST += $(EXPORT_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 + EXPORT_LIST += $(EXPORT_LIB_ARCH_DIR)/libjsig.diz else ifeq ($(OS_VENDOR), Darwin) - EXPORT_LIST += $(EXPORT_JRE_LIB_ARCH_DIR)/libjsig.$(LIBRARY_SUFFIX).dSYM + EXPORT_LIST += $(EXPORT_LIB_ARCH_DIR)/libjsig.$(LIBRARY_SUFFIX).dSYM else - EXPORT_LIST += $(EXPORT_JRE_LIB_ARCH_DIR)/libjsig.debuginfo + EXPORT_LIST += $(EXPORT_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 +EXPORT_SERVER_DIR = $(EXPORT_LIB_ARCH_DIR)/server +EXPORT_CLIENT_DIR = $(EXPORT_LIB_ARCH_DIR)/client +EXPORT_MINIMAL_DIR = $(EXPORT_LIB_ARCH_DIR)/minimal ifeq ($(findstring true, $(JVM_VARIANT_SERVER) $(JVM_VARIANT_ZERO) $(JVM_VARIANT_ZEROSHARK)), true) EXPORT_LIST += $(EXPORT_SERVER_DIR)/Xusage.txt @@ -324,34 +324,34 @@ # Serviceability Binaries # No SA Support for PPC, IA64, ARM or zero -ADD_SA_BINARIES/x86 = $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.$(LIBRARY_SUFFIX) \ +ADD_SA_BINARIES/x86 = $(EXPORT_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 + ADD_SA_BINARIES/x86 += $(EXPORT_LIB_ARCH_DIR)/libsaproc.diz else ifeq ($(OS_VENDOR), Darwin) - ADD_SA_BINARIES/x86 += $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.$(LIBRARY_SUFFIX).dSYM + ADD_SA_BINARIES/x86 += $(EXPORT_LIB_ARCH_DIR)/libsaproc.$(LIBRARY_SUFFIX).dSYM else - ADD_SA_BINARIES/x86 += $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.debuginfo + ADD_SA_BINARIES/x86 += $(EXPORT_LIB_ARCH_DIR)/libsaproc.debuginfo endif endif endif -ADD_SA_BINARIES/sparc = $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.$(LIBRARY_SUFFIX) \ +ADD_SA_BINARIES/sparc = $(EXPORT_LIB_ARCH_DIR)/libsaproc.$(LIBRARY_SUFFIX) \ $(EXPORT_LIB_DIR)/sa-jdi.jar -ADD_SA_BINARIES/universal = $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.$(LIBRARY_SUFFIX) \ +ADD_SA_BINARIES/universal = $(EXPORT_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 + ADD_SA_BINARIES/universal += $(EXPORT_LIB_ARCH_DIR)/libsaproc.diz else ifeq ($(OS_VENDOR), Darwin) - ADD_SA_BINARIES/universal += $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.$(LIBRARY_SUFFIX).dSYM + ADD_SA_BINARIES/universal += $(EXPORT_LIB_ARCH_DIR)/libsaproc.$(LIBRARY_SUFFIX).dSYM else - ADD_SA_BINARIES/universal += $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.debuginfo + ADD_SA_BINARIES/universal += $(EXPORT_LIB_ARCH_DIR)/libsaproc.debuginfo endif endif endif @@ -388,25 +388,25 @@ endif # Binaries to 'universalize' if built - UNIVERSAL_LIPO_LIST += $(EXPORT_JRE_LIB_DIR)/libjsig.$(LIBRARY_SUFFIX) - UNIVERSAL_LIPO_LIST += $(EXPORT_JRE_LIB_DIR)/libsaproc.$(LIBRARY_SUFFIX) - UNIVERSAL_LIPO_LIST += $(EXPORT_JRE_LIB_DIR)/server/libjvm.$(LIBRARY_SUFFIX) - UNIVERSAL_LIPO_LIST += $(EXPORT_JRE_LIB_DIR)/client/libjvm.$(LIBRARY_SUFFIX) + UNIVERSAL_LIPO_LIST += $(EXPORT_LIB_DIR)/libjsig.$(LIBRARY_SUFFIX) + UNIVERSAL_LIPO_LIST += $(EXPORT_LIB_DIR)/libsaproc.$(LIBRARY_SUFFIX) + UNIVERSAL_LIPO_LIST += $(EXPORT_LIB_DIR)/server/libjvm.$(LIBRARY_SUFFIX) + UNIVERSAL_LIPO_LIST += $(EXPORT_LIB_DIR)/client/libjvm.$(LIBRARY_SUFFIX) # 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 + UNIVERSAL_COPY_LIST += $(EXPORT_LIB_DIR)/server/Xusage.txt + UNIVERSAL_COPY_LIST += $(EXPORT_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 + UNIVERSAL_COPY_LIST += $(EXPORT_LIB_DIR)/server/libjvm.diz + UNIVERSAL_COPY_LIST += $(EXPORT_LIB_DIR)/client/libjvm.diz + UNIVERSAL_COPY_LIST += $(EXPORT_LIB_DIR)/libjsig.diz + UNIVERSAL_COPY_LIST += $(EXPORT_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 + UNIVERSAL_COPY_LIST += $(EXPORT_LIB_DIR)/server/libjvm.$(LIBRARY_SUFFIX).dSYM + UNIVERSAL_COPY_LIST += $(EXPORT_LIB_DIR)/client/libjvm.$(LIBRARY_SUFFIX).dSYM + UNIVERSAL_COPY_LIST += $(EXPORT_LIB_DIR)/libjsig.$(LIBRARY_SUFFIX).dSYM + UNIVERSAL_COPY_LIST += $(EXPORT_LIB_DIR)/libsaproc.$(LIBRARY_SUFFIX).dSYM endif endif diff -r a4b1c7d6317a -r febd2373771c hotspot/make/bsd/makefiles/gcc.make --- a/hotspot/make/bsd/makefiles/gcc.make Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/bsd/makefiles/gcc.make Thu May 07 20:51:12 2015 -0700 @@ -313,22 +313,13 @@ # Work around some compiler bugs. ifeq ($(USE_CLANG), true) - # Clang 4.2 - ifeq ($(shell expr $(CC_VER_MAJOR) = 4 \& $(CC_VER_MINOR) = 2), 1) - OPT_CFLAGS/loopTransform.o += $(OPT_CFLAGS/NOOPT) - OPT_CFLAGS/unsafe.o += -O1 - # Clang 5.0 - else ifeq ($(shell expr $(CC_VER_MAJOR) = 5 \& $(CC_VER_MINOR) = 0), 1) + # Clang <= 6.1 + ifeq ($(shell expr \ + $(CC_VER_MAJOR) \< 6 \| \ + \( $(CC_VER_MAJOR) = 6 \& $(CC_VER_MINOR) \<= 1 \) \ + ), 1) OPT_CFLAGS/loopTransform.o += $(OPT_CFLAGS/NOOPT) OPT_CFLAGS/unsafe.o += -O1 - # Clang 5.1 - else ifeq ($(shell expr $(CC_VER_MAJOR) = 5 \& $(CC_VER_MINOR) = 1), 1) - OPT_CFLAGS/loopTransform.o += $(OPT_CFLAGS/NOOPT) - OPT_CFLAGS/unsafe.o += -O1 - # Clang 6.0 - else ifeq ($(shell expr $(CC_VER_MAJOR) = 6 \& $(CC_VER_MINOR) = 0), 1) - OPT_CFLAGS/loopTransform.o += $(OPT_CFLAGS/NOOPT) - OPT_CFLAGS/unsafe.o += -O1 else $(error "Update compiler workarounds for Clang $(CC_VER_MAJOR).$(CC_VER_MINOR)") endif @@ -336,7 +327,7 @@ # 6835796. Problem in GCC 4.3.0 with mulnode.o optimized compilation. ifeq ($(shell expr $(CC_VER_MAJOR) = 4 \& $(CC_VER_MINOR) = 3), 1) OPT_CFLAGS/mulnode.o += $(OPT_CFLAGS/NOOPT) - endif + endif endif # Flags for generating make dependency flags. diff -r a4b1c7d6317a -r febd2373771c hotspot/make/bsd/makefiles/mapfile-vers-darwin-debug --- a/hotspot/make/bsd/makefiles/mapfile-vers-darwin-debug Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/bsd/makefiles/mapfile-vers-darwin-debug Thu May 07 20:51:12 2015 -0700 @@ -105,6 +105,7 @@ _JVM_GetClassTypeAnnotations _JVM_GetDeclaredClasses _JVM_GetDeclaringClass + _JVM_GetSimpleBinaryName _JVM_GetEnclosingMethodInfo _JVM_GetFieldIxModifiers _JVM_GetFieldTypeAnnotations diff -r a4b1c7d6317a -r febd2373771c hotspot/make/bsd/makefiles/mapfile-vers-darwin-product --- a/hotspot/make/bsd/makefiles/mapfile-vers-darwin-product Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/bsd/makefiles/mapfile-vers-darwin-product Thu May 07 20:51:12 2015 -0700 @@ -105,6 +105,7 @@ _JVM_GetClassTypeAnnotations _JVM_GetDeclaredClasses _JVM_GetDeclaringClass + _JVM_GetSimpleBinaryName _JVM_GetEnclosingMethodInfo _JVM_GetFieldIxModifiers _JVM_GetFieldTypeAnnotations diff -r a4b1c7d6317a -r febd2373771c hotspot/make/bsd/makefiles/mapfile-vers-debug --- a/hotspot/make/bsd/makefiles/mapfile-vers-debug Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/bsd/makefiles/mapfile-vers-debug Thu May 07 20:51:12 2015 -0700 @@ -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. -# +# # # Define public interface. @@ -107,6 +107,7 @@ JVM_GetClassTypeAnnotations; JVM_GetDeclaredClasses; JVM_GetDeclaringClass; + JVM_GetSimpleBinaryName; JVM_GetEnclosingMethodInfo; JVM_GetFieldIxModifiers; JVM_GetFieldTypeAnnotations; diff -r a4b1c7d6317a -r febd2373771c hotspot/make/bsd/makefiles/mapfile-vers-product --- a/hotspot/make/bsd/makefiles/mapfile-vers-product Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/bsd/makefiles/mapfile-vers-product Thu May 07 20:51:12 2015 -0700 @@ -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. -# +# # # Define public interface. @@ -107,6 +107,7 @@ JVM_GetClassTypeAnnotations; JVM_GetDeclaredClasses; JVM_GetDeclaringClass; + JVM_GetSimpleBinaryName; JVM_GetEnclosingMethodInfo; JVM_GetFieldIxModifiers; JVM_GetFieldTypeAnnotations; diff -r a4b1c7d6317a -r febd2373771c hotspot/make/bsd/makefiles/universal.gmk --- a/hotspot/make/bsd/makefiles/universal.gmk Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/bsd/makefiles/universal.gmk Thu May 07 20:51:12 2015 -0700 @@ -54,12 +54,12 @@ # Consolidate architecture builds into a single Universal binary universalize: $(UNIVERSAL_LIPO_LIST) $(UNIVERSAL_COPY_LIST) - $(RM) -r $(EXPORT_PATH)/jre/lib/{i386,amd64} + $(RM) -r $(EXPORT_PATH)/lib/{i386,amd64} # Package built libraries in a universal binary $(UNIVERSAL_LIPO_LIST): - BUILT_LIPO_FILES="`find $(EXPORT_JRE_LIB_DIR)/{i386,amd64}/$(subst $(EXPORT_JRE_LIB_DIR)/,,$@) 2>/dev/null`" || test $$? = "1"; \ + BUILT_LIPO_FILES="`find $(EXPORT_LIB_DIR)/{i386,amd64}/$(subst $(EXPORT_LIB_DIR)/,,$@) 2>/dev/null`" || test $$? = "1"; \ if [ -n "$${BUILT_LIPO_FILES}" ]; then \ $(MKDIR) -p $(shell dirname $@); \ lipo -create -output $@ $${BUILT_LIPO_FILES}; \ @@ -70,7 +70,7 @@ # - 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)/,,$@) -prune 2>/dev/null`" || test $$? = "1"; \ + BUILT_COPY_FILES="`find $(EXPORT_LIB_DIR)/{i386,amd64}/$(subst $(EXPORT_LIB_DIR)/,,$@) -prune 2>/dev/null`" || test $$? = "1"; \ if [ -n "$${BUILT_COPY_FILES}" ]; then \ for i in $${BUILT_COPY_FILES}; do \ $(MKDIR) -p $(shell dirname $@); \ @@ -80,21 +80,21 @@ # Replace arch specific binaries with universal binaries -# Do not touch jre/lib/{client,server}/libjsig.$(LIBRARY_SUFFIX) +# Do not touch lib/{client,server}/libjsig.$(LIBRARY_SUFFIX) # That symbolic link belongs to the 'jdk' build. export_universal: - $(RM) -r $(EXPORT_PATH)/jre/lib/{i386,amd64} - $(RM) -r $(JDK_IMAGE_DIR)/jre/lib/{i386,amd64} + $(RM) -r $(EXPORT_PATH)/lib/{i386,amd64} + $(RM) -r $(JDK_IMAGE_DIR)/lib/{i386,amd64} ($(CD) $(EXPORT_PATH) && \ $(TAR) -cf - *) | \ ($(CD) $(JDK_IMAGE_DIR) && $(TAR) -xpf -) # Overlay universal binaries -# Do not touch jre/lib/{client,server}/libjsig.$(LIBRARY_SUFFIX) +# Do not touch lib/{client,server}/libjsig.$(LIBRARY_SUFFIX) # That symbolic link belongs to the 'jdk' build. copy_universal: - $(RM) -r $(JDK_IMAGE_DIR)$(COPY_SUBDIR)/jre/lib/{i386,amd64} + $(RM) -r $(JDK_IMAGE_DIR)$(COPY_SUBDIR)/lib/{i386,amd64} ($(CD) $(EXPORT_PATH)$(COPY_SUBDIR) && \ $(TAR) -cf - *) | \ ($(CD) $(JDK_IMAGE_DIR)$(COPY_SUBDIR) && $(TAR) -xpf -) diff -r a4b1c7d6317a -r febd2373771c hotspot/make/build.sh --- a/hotspot/make/build.sh Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/build.sh Thu May 07 20:51:12 2015 -0700 @@ -40,7 +40,7 @@ exit 1 fi -if [ "${JAVA_HOME-}" = "" -o ! -d "${JAVA_HOME-}" -o ! -d ${JAVA_HOME-}/jre/lib/ ]; then +if [ "${JAVA_HOME-}" = "" -o ! -d "${JAVA_HOME-}" ]; then echo "JAVA_HOME needs to be set to a valid JDK path" echo "JAVA_HOME: ${JAVA_HOME-}" exit 1 diff -r a4b1c7d6317a -r febd2373771c hotspot/make/defs.make --- a/hotspot/make/defs.make Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/defs.make Thu May 07 20:51:12 2015 -0700 @@ -350,15 +350,13 @@ EXPORT_INCLUDE_DIR = $(EXPORT_PATH)/include EXPORT_DOCS_DIR = $(EXPORT_PATH)/docs EXPORT_LIB_DIR = $(EXPORT_PATH)/lib -EXPORT_JRE_DIR = $(EXPORT_PATH)/jre -EXPORT_JRE_BIN_DIR = $(EXPORT_JRE_DIR)/bin -EXPORT_JRE_LIB_DIR = $(EXPORT_JRE_DIR)/lib -EXPORT_JRE_LIB_ARCH_DIR = $(EXPORT_JRE_LIB_DIR)/$(LIBARCH) +EXPORT_BIN_DIR = $(EXPORT_PATH)/bin +EXPORT_LIB_ARCH_DIR = $(EXPORT_LIB_DIR)/$(LIBARCH) # non-universal macosx builds need to appear universal ifeq ($(OS_VENDOR), Darwin) ifneq ($(MACOSX_UNIVERSAL), true) - EXPORT_JRE_LIB_ARCH_DIR = $(EXPORT_JRE_LIB_DIR) + EXPORT_LIB_ARCH_DIR = $(EXPORT_LIB_DIR) endif endif @@ -370,4 +368,3 @@ EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jmm.h .PHONY: $(HS_ALT_MAKE)/defs.make - diff -r a4b1c7d6317a -r febd2373771c hotspot/make/linux/makefiles/defs.make --- a/hotspot/make/linux/makefiles/defs.make Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/linux/makefiles/defs.make Thu May 07 20:51:12 2015 -0700 @@ -244,17 +244,17 @@ EXPORT_LIST += $(EXPORT_DOCS_DIR)/platform/jvmti/jvmti.html # client and server subdirectories have symbolic links to ../libjsig.so -EXPORT_LIST += $(EXPORT_JRE_LIB_ARCH_DIR)/libjsig.$(LIBRARY_SUFFIX) +EXPORT_LIST += $(EXPORT_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 + EXPORT_LIST += $(EXPORT_LIB_ARCH_DIR)/libjsig.diz else - EXPORT_LIST += $(EXPORT_JRE_LIB_ARCH_DIR)/libjsig.debuginfo + EXPORT_LIST += $(EXPORT_LIB_ARCH_DIR)/libjsig.debuginfo 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 +EXPORT_SERVER_DIR = $(EXPORT_LIB_ARCH_DIR)/server +EXPORT_CLIENT_DIR = $(EXPORT_LIB_ARCH_DIR)/client +EXPORT_MINIMAL_DIR = $(EXPORT_LIB_ARCH_DIR)/minimal ifeq ($(findstring true, $(JVM_VARIANT_SERVER) $(JVM_VARIANT_ZERO) $(JVM_VARIANT_ZEROSHARK) $(JVM_VARIANT_CORE)), true) EXPORT_LIST += $(EXPORT_SERVER_DIR)/Xusage.txt @@ -295,14 +295,14 @@ # Serviceability Binaries -ADD_SA_BINARIES/DEFAULT = $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.$(LIBRARY_SUFFIX) \ +ADD_SA_BINARIES/DEFAULT = $(EXPORT_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/DEFAULT += $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.diz + ADD_SA_BINARIES/DEFAULT += $(EXPORT_LIB_ARCH_DIR)/libsaproc.diz else - ADD_SA_BINARIES/DEFAULT += $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.debuginfo + ADD_SA_BINARIES/DEFAULT += $(EXPORT_LIB_ARCH_DIR)/libsaproc.debuginfo endif endif diff -r a4b1c7d6317a -r febd2373771c hotspot/make/linux/makefiles/mapfile-vers-debug --- a/hotspot/make/linux/makefiles/mapfile-vers-debug Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/linux/makefiles/mapfile-vers-debug Thu May 07 20:51:12 2015 -0700 @@ -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. -# +# # # Define public interface. @@ -107,6 +107,7 @@ JVM_GetClassTypeAnnotations; JVM_GetDeclaredClasses; JVM_GetDeclaringClass; + JVM_GetSimpleBinaryName; JVM_GetEnclosingMethodInfo; JVM_GetFieldIxModifiers; JVM_GetFieldTypeAnnotations; diff -r a4b1c7d6317a -r febd2373771c hotspot/make/linux/makefiles/mapfile-vers-product --- a/hotspot/make/linux/makefiles/mapfile-vers-product Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/linux/makefiles/mapfile-vers-product Thu May 07 20:51:12 2015 -0700 @@ -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. -# +# # # Define public interface. @@ -107,6 +107,7 @@ JVM_GetClassTypeAnnotations; JVM_GetDeclaredClasses; JVM_GetDeclaringClass; + JVM_GetSimpleBinaryName; JVM_GetEnclosingMethodInfo; JVM_GetFieldIxModifiers; JVM_GetFieldTypeAnnotations; diff -r a4b1c7d6317a -r febd2373771c hotspot/make/linux/makefiles/vm.make --- a/hotspot/make/linux/makefiles/vm.make Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/linux/makefiles/vm.make Thu May 07 20:51:12 2015 -0700 @@ -127,7 +127,7 @@ # By default, link the *.o into the library, not the executable. LINK_INTO$(LINK_INTO) = LIBJVM -JDK_LIBDIR = $(JAVA_HOME)/jre/lib/$(LIBARCH) +JDK_LIBDIR = $(JAVA_HOME)/lib/$(LIBARCH) #---------------------------------------------------------------------- # jvm_db & dtrace diff -r a4b1c7d6317a -r febd2373771c hotspot/make/solaris/makefiles/defs.make --- a/hotspot/make/solaris/makefiles/defs.make Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/solaris/makefiles/defs.make Thu May 07 20:51:12 2015 -0700 @@ -224,17 +224,17 @@ EXPORT_LIST += $(EXPORT_DOCS_DIR)/platform/jvmti/jvmti.html # client and server subdirectories have symbolic links to ../libjsig.$(LIBRARY_SUFFIX) -EXPORT_LIST += $(EXPORT_JRE_LIB_ARCH_DIR)/libjsig.$(LIBRARY_SUFFIX) +EXPORT_LIST += $(EXPORT_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 + EXPORT_LIST += $(EXPORT_LIB_ARCH_DIR)/libjsig.diz else - EXPORT_LIST += $(EXPORT_JRE_LIB_ARCH_DIR)/libjsig.debuginfo + EXPORT_LIST += $(EXPORT_LIB_ARCH_DIR)/libjsig.debuginfo endif endif -EXPORT_SERVER_DIR = $(EXPORT_JRE_LIB_ARCH_DIR)/server -EXPORT_CLIENT_DIR = $(EXPORT_JRE_LIB_ARCH_DIR)/client +EXPORT_SERVER_DIR = $(EXPORT_LIB_ARCH_DIR)/server +EXPORT_CLIENT_DIR = $(EXPORT_LIB_ARCH_DIR)/client ifeq ($(JVM_VARIANT_SERVER),true) EXPORT_LIST += $(EXPORT_SERVER_DIR)/Xusage.txt @@ -295,12 +295,12 @@ endif endif -EXPORT_LIST += $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.$(LIBRARY_SUFFIX) +EXPORT_LIST += $(EXPORT_LIB_ARCH_DIR)/libsaproc.$(LIBRARY_SUFFIX) ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) ifeq ($(ZIP_DEBUGINFO_FILES),1) - EXPORT_LIST += $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.diz + EXPORT_LIST += $(EXPORT_LIB_ARCH_DIR)/libsaproc.diz else - EXPORT_LIST += $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.debuginfo + EXPORT_LIST += $(EXPORT_LIB_ARCH_DIR)/libsaproc.debuginfo endif endif EXPORT_LIST += $(EXPORT_LIB_DIR)/sa-jdi.jar diff -r a4b1c7d6317a -r febd2373771c hotspot/make/solaris/makefiles/dtrace.make --- a/hotspot/make/solaris/makefiles/dtrace.make Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/solaris/makefiles/dtrace.make Thu May 07 20:51:12 2015 -0700 @@ -130,8 +130,9 @@ $(XLIBJVM_DTRACE): $(DTRACE_SRCDIR)/$(JVM_DTRACE).c $(DTRACE_SRCDIR)/$(JVM_DTRACE).h $(LIBJVM_DTRACE_MAPFILE) @echo $(LOG_INFO) Making $@ $(QUIETLY) mkdir -p $(XLIBJVM_DIR) ; \ - $(CC) $(SYMFLAG) $(ARCHFLAG/$(ISA)) -D$(TYPE) -I. \ - $(SHARED_FLAG) $(LFLAGS_JVM_DTRACE) -o $@ $(DTRACE_SRCDIR)/$(JVM_DTRACE).c -lc -lthread -ldoor + $(CC) $(SYMFLAG) $(ARCHFLAG/$(ISA)) -D$(TYPE) -I. $(EXTRA_CFLAGS) \ + $(SHARED_FLAG) $(LFLAGS_JVM_DTRACE) -o $@ $(DTRACE_SRCDIR)/$(JVM_DTRACE).c \ + $(EXTRA_LDFLAGS) -lc -lthread -ldoor ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(XLIBJVM_DTRACE_DEBUGINFO) # Do this part in the $(XLIBJVM_DIR) subdir so $(XLIBJVM_DIR) is not @@ -216,8 +217,9 @@ $(LIBJVM_DTRACE): $(DTRACE_SRCDIR)/$(JVM_DTRACE).c $(XLIBJVM_DTRACE) $(DTRACE_SRCDIR)/$(JVM_DTRACE).h $(LIBJVM_DTRACE_MAPFILE) @echo $(LOG_INFO) Making $@ - $(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) -D$(TYPE) -I. \ - $(SHARED_FLAG) $(LFLAGS_JVM_DTRACE) -o $@ $(DTRACE_SRCDIR)/$(JVM_DTRACE).c -lc -lthread -ldoor + $(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) -D$(TYPE) -I. $(EXTRA_CFLAGS) \ + $(SHARED_FLAG) $(LFLAGS_JVM_DTRACE) -o $@ $(DTRACE_SRCDIR)/$(JVM_DTRACE).c \ + $(EXTRA_LDFLAGS) -lc -lthread -ldoor ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBJVM_DTRACE_DEBUGINFO) $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DTRACE_DEBUGINFO) $@ diff -r a4b1c7d6317a -r febd2373771c hotspot/make/solaris/makefiles/jsig.make --- a/hotspot/make/solaris/makefiles/jsig.make Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/solaris/makefiles/jsig.make Thu May 07 20:51:12 2015 -0700 @@ -50,7 +50,9 @@ $(LIBJSIG): $(JSIGSRCDIR)/jsig.c $(LIBJSIG_MAPFILE) @echo $(LOG_INFO) Making signal interposition lib... $(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) $(SHARED_FLAG) $(PICFLAG) \ - $(LFLAGS_JSIG) -o $@ $(JSIGSRCDIR)/jsig.c -ldl + $(EXTRA_CFLAGS) \ + $(LFLAGS_JSIG) $(EXTRA_LDFLAGS) \ + -o $@ $(JSIGSRCDIR)/jsig.c -ldl ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBJSIG_DEBUGINFO) $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBJSIG_DEBUGINFO) $@ diff -r a4b1c7d6317a -r febd2373771c hotspot/make/solaris/makefiles/mapfile-vers --- a/hotspot/make/solaris/makefiles/mapfile-vers Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/solaris/makefiles/mapfile-vers Thu May 07 20:51:12 2015 -0700 @@ -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. -# +# # # Define public interface. @@ -30,7 +30,7 @@ JNI_CreateJavaVM; JNI_GetCreatedJavaVMs; JNI_GetDefaultJavaVMInitArgs; - + # JVM JVM_ActiveProcessorCount; JVM_ArrayCopy; @@ -107,6 +107,7 @@ JVM_GetClassTypeAnnotations; JVM_GetDeclaredClasses; JVM_GetDeclaringClass; + JVM_GetSimpleBinaryName; JVM_GetEnclosingMethodInfo; JVM_GetFieldIxModifiers; JVM_GetFieldTypeAnnotations; diff -r a4b1c7d6317a -r febd2373771c hotspot/make/solaris/makefiles/product.make --- a/hotspot/make/solaris/makefiles/product.make Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/solaris/makefiles/product.make Thu May 07 20:51:12 2015 -0700 @@ -37,6 +37,11 @@ OPT_CFLAGS/ciEnv.o = $(OPT_CFLAGS) -xinline=no%__1cFciEnvbFpost_compiled_method_load_event6MpnHnmethod__v_ endif +# Need extra inlining to get oop_ps_push_contents functions to perform well enough. +ifndef USE_GCC +OPT_CFLAGS/psPromotionManager.o = $(OPT_CFLAGS) -W2,-Ainline:inc=1000 +endif + # (OPT_CFLAGS/SLOWER is also available, to alter compilation of buggy files) ifeq ("${Platform_compiler}", "sparcWorks") diff -r a4b1c7d6317a -r febd2373771c hotspot/make/solaris/makefiles/saproc.make --- a/hotspot/make/solaris/makefiles/saproc.make Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/solaris/makefiles/saproc.make Thu May 07 20:51:12 2015 -0700 @@ -89,6 +89,17 @@ # when actually building on Nevada-B158 or earlier: #SOLARIS_11_B159_OR_LATER=-DSOLARIS_11_B159_OR_LATER +$(SADISOBJ): $(SADISSRCFILES) + $(QUIETLY) $(CC) \ + $(SYMFLAG) $(ARCHFLAG) $(SHARED_FLAG) $(PICFLAG) \ + -I$(SASRCDIR) \ + -I$(GENERATED) \ + -I$(BOOT_JAVA_HOME)/include \ + -I$(BOOT_JAVA_HOME)/include/$(Platform_os_family) \ + $(SOLARIS_11_B159_OR_LATER) \ + $(EXTRA_CFLAGS) \ + $(SADISSRCFILES) \ + -c -o $(SADISOBJ) $(LIBSAPROC): $(SASRCFILES) $(SADISOBJ) $(SAMAPFILE) $(QUIETLY) if [ "$(BOOT_JAVA_HOME)" = "" ]; then \ @@ -103,23 +114,13 @@ -I$(BOOT_JAVA_HOME)/include \ -I$(BOOT_JAVA_HOME)/include/$(Platform_os_family) \ $(SOLARIS_11_B159_OR_LATER) \ + $(EXTRA_CXXFLAGS) $(EXTRA_LDFLAGS) \ + $(SADISOBJ) \ $(SASRCFILES) \ - $(SADISOBJ) \ $(SA_LFLAGS) \ -o $@ \ -ldl -ldemangle -lthread -lc -$(SADISOBJ): $(SADISSRCFILES) - $(QUIETLY) $(CC) \ - $(SYMFLAG) $(ARCHFLAG) $(SHARED_FLAG) $(PICFLAG) \ - -I$(SASRCDIR) \ - -I$(GENERATED) \ - -I$(BOOT_JAVA_HOME)/include \ - -I$(BOOT_JAVA_HOME)/include/$(Platform_os_family) \ - $(SOLARIS_11_B159_OR_LATER) \ - $(SADISSRCFILES) \ - -c -o $(SADISOBJ) - ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBSAPROC_DEBUGINFO) $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBSAPROC_DEBUGINFO) $@ diff -r a4b1c7d6317a -r febd2373771c hotspot/make/solaris/makefiles/vm.make --- a/hotspot/make/solaris/makefiles/vm.make Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/solaris/makefiles/vm.make Thu May 07 20:51:12 2015 -0700 @@ -148,7 +148,7 @@ # By default, link the *.o into the library, not the executable. LINK_INTO$(LINK_INTO) = LIBJVM -JDK_LIBDIR = $(JAVA_HOME)/jre/lib/$(LIBARCH) +JDK_LIBDIR = $(JAVA_HOME)/lib/$(LIBARCH) #---------------------------------------------------------------------- # jvm_db & dtrace @@ -288,6 +288,8 @@ endif endif +LFLAGS_VM += $(EXTRA_LDFLAGS) + ifdef USE_GCC LINK_VM = $(LINK_LIB.CC) else diff -r a4b1c7d6317a -r febd2373771c hotspot/make/windows/makefiles/defs.make --- a/hotspot/make/windows/makefiles/defs.make Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/windows/makefiles/defs.make Thu May 07 20:51:12 2015 -0700 @@ -249,8 +249,8 @@ endif endif -EXPORT_SERVER_DIR = $(EXPORT_JRE_BIN_DIR)/server -EXPORT_CLIENT_DIR = $(EXPORT_JRE_BIN_DIR)/client +EXPORT_SERVER_DIR = $(EXPORT_BIN_DIR)/server +EXPORT_CLIENT_DIR = $(EXPORT_BIN_DIR)/client ifeq ($(JVM_VARIANT_SERVER),true) EXPORT_LIST += $(EXPORT_SERVER_DIR)/Xusage.txt @@ -280,13 +280,13 @@ EXPORT_LIST += $(EXPORT_LIB_DIR)/jvm.lib ifeq ($(BUILD_WIN_SA), 1) - EXPORT_LIST += $(EXPORT_JRE_BIN_DIR)/sawindbg.$(LIBRARY_SUFFIX) + EXPORT_LIST += $(EXPORT_BIN_DIR)/sawindbg.$(LIBRARY_SUFFIX) ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) ifeq ($(ZIP_DEBUGINFO_FILES),1) - EXPORT_LIST += $(EXPORT_JRE_BIN_DIR)/sawindbg.diz + EXPORT_LIST += $(EXPORT_BIN_DIR)/sawindbg.diz else - EXPORT_LIST += $(EXPORT_JRE_BIN_DIR)/sawindbg.pdb - EXPORT_LIST += $(EXPORT_JRE_BIN_DIR)/sawindbg.map + EXPORT_LIST += $(EXPORT_BIN_DIR)/sawindbg.pdb + EXPORT_LIST += $(EXPORT_BIN_DIR)/sawindbg.map endif endif EXPORT_LIST += $(EXPORT_LIB_DIR)/sa-jdi.jar diff -r a4b1c7d6317a -r febd2373771c hotspot/make/windows/makefiles/sa.make --- a/hotspot/make/windows/makefiles/sa.make Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/make/windows/makefiles/sa.make Thu May 07 20:51:12 2015 -0700 @@ -91,6 +91,9 @@ SAWINDBG=sawindbg.dll +# Resource file containing VERSIONINFO +SA_Res_Files=.\version.sares + checkAndBuildSA:: $(SAWINDBG) # These do not need to be optimized (don't run a lot of code) and it @@ -126,10 +129,13 @@ # Note that we do not keep sawindbj.obj around as it would then # get included in the dumpbin command in build_vm_def.sh +# Force resources to be rebuilt every time +$(SA_Res_Files): FORCE + # In VS2005 or VS2008 the link command creates a .manifest file that we want # to insert into the linked artifact so we do not need to track it separately. # Use ";#2" for .dll and ";#1" for .exe in the MT command below: -$(SAWINDBG): $(SASRCFILES) +$(SAWINDBG): $(SASRCFILES) $(SA_Res_Files) set INCLUDE=$(SA_INCLUDE)$(INCLUDE) $(CXX) @<< -I"$(BootStrapDir)/include" -I"$(BootStrapDir)/include/win32" @@ -138,7 +144,7 @@ -out:$*.obj << set LIB=$(SA_LIB)$(LIB) - $(LD) -out:$@ -DLL sawindbg.obj sadis.obj dbgeng.lib $(SA_LFLAGS) + $(LD) -out:$@ -DLL sawindbg.obj sadis.obj dbgeng.lib $(SA_LFLAGS) $(SA_Res_Files) !if "$(MT)" != "" $(MT) -manifest $(@F).manifest -outputresource:$(@F);#2 !endif @@ -150,6 +156,9 @@ !endif -@rm -f $*.obj +{$(COMMONSRC)\os\windows\vm}.rc.sares: + @$(RC) $(RC_FLAGS) /D "HS_FNAME=$(SAWINDBG)" /fo"$@" $< + cleanall : rm -rf $(GENERATED)/saclasses rm -rf $(GENERATED)/sa-jdi.jar diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/aarch64/vm/aarch64.ad --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad Thu May 07 20:51:12 2015 -0700 @@ -2614,6 +2614,8 @@ case INDINDEXSCALEDI2L: case INDINDEXSCALEDOFFSETI2LN: case INDINDEXSCALEDI2LN: + case INDINDEXOFFSETI2L: + case INDINDEXOFFSETI2LN: scale = Address::sxtw(size); break; default: @@ -5060,6 +5062,20 @@ %} %} +operand indIndexOffsetI2L(iRegP reg, iRegI ireg, immLU12 off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (AddP reg (ConvI2L ireg)) off); + op_cost(INSN_COST); + format %{ "$reg, $ireg, $off I2L" %} + interface(MEMORY_INTER) %{ + base($reg); + index($ireg); + scale(0x0); + disp($off); + %} +%} + operand indIndexScaledOffsetI2L(iRegP reg, iRegI ireg, immIScale scale, immLU12 off) %{ constraint(ALLOC_IN_RC(ptr_reg)); @@ -5120,7 +5136,7 @@ %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg off); - op_cost(INSN_COST); + op_cost(0); format %{ "[$reg, $off]" %} interface(MEMORY_INTER) %{ base($reg); @@ -5190,6 +5206,21 @@ %} %} +operand indIndexOffsetI2LN(iRegN reg, iRegI ireg, immLU12 off) +%{ + predicate(Universe::narrow_oop_shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (AddP (DecodeN reg) (ConvI2L ireg)) off); + op_cost(INSN_COST); + format %{ "$reg, $ireg, $off I2L\t# narrow" %} + interface(MEMORY_INTER) %{ + base($reg); + index($ireg); + scale(0x0); + disp($off); + %} +%} + operand indIndexScaledOffsetI2LN(iRegN reg, iRegI ireg, immIScale scale, immLU12 off) %{ predicate(Universe::narrow_oop_shift() == 0); @@ -5452,8 +5483,8 @@ // memory is used to define read/write location for load/store // instruction defs. we can turn a memory op into an Address -opclass memory(indirect, indIndexScaledOffsetI, indIndexScaledOffsetL, indIndexScaledOffsetI2L, indIndexScaled, indIndexScaledI2L, indIndex, indOffI, indOffL, - indirectN, indIndexScaledOffsetIN, indIndexScaledOffsetLN, indIndexScaledOffsetI2LN, indIndexScaledN, indIndexScaledI2LN, indIndexN, indOffIN, indOffLN); +opclass memory(indirect, indIndexScaledOffsetI, indIndexScaledOffsetL, indIndexOffsetI2L, indIndexScaledOffsetI2L, indIndexScaled, indIndexScaledI2L, indIndex, indOffI, indOffL, + indirectN, indIndexScaledOffsetIN, indIndexScaledOffsetLN, indIndexOffsetI2LN, indIndexScaledOffsetI2LN, indIndexScaledN, indIndexScaledI2LN, indIndexN, indOffIN, indOffLN); // iRegIorL2I is used for src inputs in rules for 32 bit int (I) @@ -8346,7 +8377,7 @@ instruct addP_reg_reg_ext(iRegPNoSp dst, iRegP src1, iRegIorL2I src2) %{ match(Set dst (AddP src1 (ConvI2L src2))); - ins_cost(INSN_COST); + ins_cost(1.9 * INSN_COST); format %{ "add $dst, $src1, $src2, sxtw\t# ptr" %} ins_encode %{ diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp --- a/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2014, 2015, Red Hat Inc. 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 @@ -1469,7 +1469,7 @@ f(op, 31, 29); f(0b11010000, 28, 21); f(0b000000, 15, 10); - rf(Rm, 16), rf(Rn, 5), rf(Rd, 0); + zrf(Rm, 16), zrf(Rn, 5), zrf(Rd, 0); } #define INSN(NAME, op) \ diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp --- a/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp Thu May 07 20:51:12 2015 -0700 @@ -68,6 +68,8 @@ define_pd_global(bool, UseMembar, true); +define_pd_global(bool, PreserveFramePointer, false); + // GC Ergo Flags define_pd_global(uintx, CMSYoungGenPerWorker, 64*M); // default max size of CMS young gen, per GC worker thread diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.hpp --- a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2014, 2015, Red Hat Inc. 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 @@ -42,6 +42,8 @@ using MacroAssembler::call_VM_leaf_base; // Interpreter specific version of call_VM_base + using MacroAssembler::call_VM_leaf_base; + virtual void call_VM_leaf_base(address entry_point, int number_of_arguments); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Red Hat Inc. 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 @@ -2238,6 +2238,341 @@ } /** + * Helpers for multiply_to_len(). + */ +void MacroAssembler::add2_with_carry(Register final_dest_hi, Register dest_hi, Register dest_lo, + Register src1, Register src2) { + adds(dest_lo, dest_lo, src1); + adc(dest_hi, dest_hi, zr); + adds(dest_lo, dest_lo, src2); + adc(final_dest_hi, dest_hi, zr); +} + +// Generate an address from (r + r1 extend offset). "size" is the +// size of the operand. The result may be in rscratch2. +Address MacroAssembler::offsetted_address(Register r, Register r1, + Address::extend ext, int offset, int size) { + if (offset || (ext.shift() % size != 0)) { + lea(rscratch2, Address(r, r1, ext)); + return Address(rscratch2, offset); + } else { + return Address(r, r1, ext); + } +} + +/** + * Multiply 64 bit by 64 bit first loop. + */ +void MacroAssembler::multiply_64_x_64_loop(Register x, Register xstart, Register x_xstart, + Register y, Register y_idx, Register z, + Register carry, Register product, + Register idx, Register kdx) { + // + // jlong carry, x[], y[], z[]; + // for (int idx=ystart, kdx=ystart+1+xstart; idx >= 0; idx-, kdx--) { + // huge_128 product = y[idx] * x[xstart] + carry; + // z[kdx] = (jlong)product; + // carry = (jlong)(product >>> 64); + // } + // z[xstart] = carry; + // + + Label L_first_loop, L_first_loop_exit; + Label L_one_x, L_one_y, L_multiply; + + subsw(xstart, xstart, 1); + br(Assembler::MI, L_one_x); + + lea(rscratch1, Address(x, xstart, Address::lsl(LogBytesPerInt))); + ldr(x_xstart, Address(rscratch1)); + ror(x_xstart, x_xstart, 32); // convert big-endian to little-endian + + bind(L_first_loop); + subsw(idx, idx, 1); + br(Assembler::MI, L_first_loop_exit); + subsw(idx, idx, 1); + br(Assembler::MI, L_one_y); + lea(rscratch1, Address(y, idx, Address::uxtw(LogBytesPerInt))); + ldr(y_idx, Address(rscratch1)); + ror(y_idx, y_idx, 32); // convert big-endian to little-endian + bind(L_multiply); + + // AArch64 has a multiply-accumulate instruction that we can't use + // here because it has no way to process carries, so we have to use + // separate add and adc instructions. Bah. + umulh(rscratch1, x_xstart, y_idx); // x_xstart * y_idx -> rscratch1:product + mul(product, x_xstart, y_idx); + adds(product, product, carry); + adc(carry, rscratch1, zr); // x_xstart * y_idx + carry -> carry:product + + subw(kdx, kdx, 2); + ror(product, product, 32); // back to big-endian + str(product, offsetted_address(z, kdx, Address::uxtw(LogBytesPerInt), 0, BytesPerLong)); + + b(L_first_loop); + + bind(L_one_y); + ldrw(y_idx, Address(y, 0)); + b(L_multiply); + + bind(L_one_x); + ldrw(x_xstart, Address(x, 0)); + b(L_first_loop); + + bind(L_first_loop_exit); +} + +/** + * Multiply 128 bit by 128. Unrolled inner loop. + * + */ +void MacroAssembler::multiply_128_x_128_loop(Register y, Register z, + Register carry, Register carry2, + Register idx, Register jdx, + Register yz_idx1, Register yz_idx2, + Register tmp, Register tmp3, Register tmp4, + Register tmp6, Register product_hi) { + + // jlong carry, x[], y[], z[]; + // int kdx = ystart+1; + // for (int idx=ystart-2; idx >= 0; idx -= 2) { // Third loop + // huge_128 tmp3 = (y[idx+1] * product_hi) + z[kdx+idx+1] + carry; + // jlong carry2 = (jlong)(tmp3 >>> 64); + // huge_128 tmp4 = (y[idx] * product_hi) + z[kdx+idx] + carry2; + // carry = (jlong)(tmp4 >>> 64); + // z[kdx+idx+1] = (jlong)tmp3; + // z[kdx+idx] = (jlong)tmp4; + // } + // idx += 2; + // if (idx > 0) { + // yz_idx1 = (y[idx] * product_hi) + z[kdx+idx] + carry; + // z[kdx+idx] = (jlong)yz_idx1; + // carry = (jlong)(yz_idx1 >>> 64); + // } + // + + Label L_third_loop, L_third_loop_exit, L_post_third_loop_done; + + lsrw(jdx, idx, 2); + + bind(L_third_loop); + + subsw(jdx, jdx, 1); + br(Assembler::MI, L_third_loop_exit); + subw(idx, idx, 4); + + lea(rscratch1, Address(y, idx, Address::uxtw(LogBytesPerInt))); + + ldp(yz_idx2, yz_idx1, Address(rscratch1, 0)); + + lea(tmp6, Address(z, idx, Address::uxtw(LogBytesPerInt))); + + ror(yz_idx1, yz_idx1, 32); // convert big-endian to little-endian + ror(yz_idx2, yz_idx2, 32); + + ldp(rscratch2, rscratch1, Address(tmp6, 0)); + + mul(tmp3, product_hi, yz_idx1); // yz_idx1 * product_hi -> tmp4:tmp3 + umulh(tmp4, product_hi, yz_idx1); + + ror(rscratch1, rscratch1, 32); // convert big-endian to little-endian + ror(rscratch2, rscratch2, 32); + + mul(tmp, product_hi, yz_idx2); // yz_idx2 * product_hi -> carry2:tmp + umulh(carry2, product_hi, yz_idx2); + + // propagate sum of both multiplications into carry:tmp4:tmp3 + adds(tmp3, tmp3, carry); + adc(tmp4, tmp4, zr); + adds(tmp3, tmp3, rscratch1); + adcs(tmp4, tmp4, tmp); + adc(carry, carry2, zr); + adds(tmp4, tmp4, rscratch2); + adc(carry, carry, zr); + + ror(tmp3, tmp3, 32); // convert little-endian to big-endian + ror(tmp4, tmp4, 32); + stp(tmp4, tmp3, Address(tmp6, 0)); + + b(L_third_loop); + bind (L_third_loop_exit); + + andw (idx, idx, 0x3); + cbz(idx, L_post_third_loop_done); + + Label L_check_1; + subsw(idx, idx, 2); + br(Assembler::MI, L_check_1); + + lea(rscratch1, Address(y, idx, Address::uxtw(LogBytesPerInt))); + ldr(yz_idx1, Address(rscratch1, 0)); + ror(yz_idx1, yz_idx1, 32); + mul(tmp3, product_hi, yz_idx1); // yz_idx1 * product_hi -> tmp4:tmp3 + umulh(tmp4, product_hi, yz_idx1); + lea(rscratch1, Address(z, idx, Address::uxtw(LogBytesPerInt))); + ldr(yz_idx2, Address(rscratch1, 0)); + ror(yz_idx2, yz_idx2, 32); + + add2_with_carry(carry, tmp4, tmp3, carry, yz_idx2); + + ror(tmp3, tmp3, 32); + str(tmp3, Address(rscratch1, 0)); + + bind (L_check_1); + + andw (idx, idx, 0x1); + subsw(idx, idx, 1); + br(Assembler::MI, L_post_third_loop_done); + ldrw(tmp4, Address(y, idx, Address::uxtw(LogBytesPerInt))); + mul(tmp3, tmp4, product_hi); // tmp4 * product_hi -> carry2:tmp3 + umulh(carry2, tmp4, product_hi); + ldrw(tmp4, Address(z, idx, Address::uxtw(LogBytesPerInt))); + + add2_with_carry(carry2, tmp3, tmp4, carry); + + strw(tmp3, Address(z, idx, Address::uxtw(LogBytesPerInt))); + extr(carry, carry2, tmp3, 32); + + bind(L_post_third_loop_done); +} + +/** + * Code for BigInteger::multiplyToLen() instrinsic. + * + * r0: x + * r1: xlen + * r2: y + * r3: ylen + * r4: z + * r5: zlen + * r10: tmp1 + * r11: tmp2 + * r12: tmp3 + * r13: tmp4 + * r14: tmp5 + * r15: tmp6 + * r16: tmp7 + * + */ +void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Register ylen, + Register z, Register zlen, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, + Register tmp5, Register tmp6, Register product_hi) { + + assert_different_registers(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6); + + const Register idx = tmp1; + const Register kdx = tmp2; + const Register xstart = tmp3; + + const Register y_idx = tmp4; + const Register carry = tmp5; + const Register product = xlen; + const Register x_xstart = zlen; // reuse register + + // First Loop. + // + // final static long LONG_MASK = 0xffffffffL; + // int xstart = xlen - 1; + // int ystart = ylen - 1; + // long carry = 0; + // for (int idx=ystart, kdx=ystart+1+xstart; idx >= 0; idx-, kdx--) { + // long product = (y[idx] & LONG_MASK) * (x[xstart] & LONG_MASK) + carry; + // z[kdx] = (int)product; + // carry = product >>> 32; + // } + // z[xstart] = (int)carry; + // + + movw(idx, ylen); // idx = ylen; + movw(kdx, zlen); // kdx = xlen+ylen; + mov(carry, zr); // carry = 0; + + Label L_done; + + movw(xstart, xlen); + subsw(xstart, xstart, 1); + br(Assembler::MI, L_done); + + multiply_64_x_64_loop(x, xstart, x_xstart, y, y_idx, z, carry, product, idx, kdx); + + Label L_second_loop; + cbzw(kdx, L_second_loop); + + Label L_carry; + subw(kdx, kdx, 1); + cbzw(kdx, L_carry); + + strw(carry, Address(z, kdx, Address::uxtw(LogBytesPerInt))); + lsr(carry, carry, 32); + subw(kdx, kdx, 1); + + bind(L_carry); + strw(carry, Address(z, kdx, Address::uxtw(LogBytesPerInt))); + + // Second and third (nested) loops. + // + // for (int i = xstart-1; i >= 0; i--) { // Second loop + // carry = 0; + // for (int jdx=ystart, k=ystart+1+i; jdx >= 0; jdx--, k--) { // Third loop + // long product = (y[jdx] & LONG_MASK) * (x[i] & LONG_MASK) + + // (z[k] & LONG_MASK) + carry; + // z[k] = (int)product; + // carry = product >>> 32; + // } + // z[i] = (int)carry; + // } + // + // i = xlen, j = tmp1, k = tmp2, carry = tmp5, x[i] = product_hi + + const Register jdx = tmp1; + + bind(L_second_loop); + mov(carry, zr); // carry = 0; + movw(jdx, ylen); // j = ystart+1 + + subsw(xstart, xstart, 1); // i = xstart-1; + br(Assembler::MI, L_done); + + str(z, Address(pre(sp, -4 * wordSize))); + + Label L_last_x; + lea(z, offsetted_address(z, xstart, Address::uxtw(LogBytesPerInt), 4, BytesPerInt)); // z = z + k - j + subsw(xstart, xstart, 1); // i = xstart-1; + br(Assembler::MI, L_last_x); + + lea(rscratch1, Address(x, xstart, Address::uxtw(LogBytesPerInt))); + ldr(product_hi, Address(rscratch1)); + ror(product_hi, product_hi, 32); // convert big-endian to little-endian + + Label L_third_loop_prologue; + bind(L_third_loop_prologue); + + str(ylen, Address(sp, wordSize)); + stp(x, xstart, Address(sp, 2 * wordSize)); + multiply_128_x_128_loop(y, z, carry, x, jdx, ylen, product, + tmp2, x_xstart, tmp3, tmp4, tmp6, product_hi); + ldp(z, ylen, Address(post(sp, 2 * wordSize))); + ldp(x, xlen, Address(post(sp, 2 * wordSize))); // copy old xstart -> xlen + + addw(tmp3, xlen, 1); + strw(carry, Address(z, tmp3, Address::uxtw(LogBytesPerInt))); + subsw(tmp3, tmp3, 1); + br(Assembler::MI, L_done); + + lsr(carry, carry, 32); + strw(carry, Address(z, tmp3, Address::uxtw(LogBytesPerInt))); + b(L_second_loop); + + // Next infrequent code is moved outside loops. + bind(L_last_x); + ldrw(product_hi, Address(x, 0)); + b(L_third_loop_prologue); + + bind(L_done); +} + +/** * Emits code to update CRC-32 with a byte value according to constants in table * * @param [in,out]crc Register containing the crc. diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2014, 2015, Red Hat Inc. 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 @@ -167,9 +167,8 @@ // aliases defined in AARCH64 spec - template - inline void cmpw(Register Rd, T imm) { subsw(zr, Rd, imm); } + inline void cmpw(Register Rd, T imm) { subsw(zr, Rd, imm); } inline void cmp(Register Rd, unsigned imm) { subs(zr, Rd, imm); } inline void cmnw(Register Rd, unsigned imm) { addsw(zr, Rd, imm); } @@ -1121,9 +1120,34 @@ Register tmp1, Register tmp2, Register tmp3, Register tmp4, int int_cnt1, Register result); - +private: + void add2_with_carry(Register final_dest_hi, Register dest_hi, Register dest_lo, + Register src1, Register src2); + void add2_with_carry(Register dest_hi, Register dest_lo, Register src1, Register src2) { + add2_with_carry(dest_hi, dest_hi, dest_lo, src1, src2); + } + void multiply_64_x_64_loop(Register x, Register xstart, Register x_xstart, + Register y, Register y_idx, Register z, + Register carry, Register product, + Register idx, Register kdx); + void multiply_128_x_128_loop(Register y, Register z, + Register carry, Register carry2, + Register idx, Register jdx, + Register yz_idx1, Register yz_idx2, + Register tmp, Register tmp3, Register tmp4, + Register tmp7, Register product_hi); +public: + void multiply_to_len(Register x, Register xlen, Register y, Register ylen, Register z, + Register zlen, Register tmp1, Register tmp2, Register tmp3, + Register tmp4, Register tmp5, Register tmp6, Register tmp7); // ISB may be needed because of a safepoint void maybe_isb() { isb(); } + +private: + // Return the effective address r + (r1 << ext) + offset. + // Uses rscratch2. + Address offsetted_address(Register r, Register r1, Address::extend ext, + int offset, int size); }; // Used by aarch64.ad to control code generation diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2014, 2015, Red Hat Inc. 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 @@ -2356,8 +2356,45 @@ return start; } -#undef __ -#define __ masm-> + /** + * Arguments: + * + * Input: + * c_rarg0 - x address + * c_rarg1 - x length + * c_rarg2 - y address + * c_rarg3 - y lenth + * c_rarg4 - z address + * c_rarg5 - z length + */ + address generate_multiplyToLen() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "multiplyToLen"); + + address start = __ pc(); + const Register x = r0; + const Register xlen = r1; + const Register y = r2; + const Register ylen = r3; + const Register z = r4; + const Register zlen = r5; + + const Register tmp1 = r10; + const Register tmp2 = r11; + const Register tmp3 = r12; + const Register tmp4 = r13; + const Register tmp5 = r14; + const Register tmp6 = r15; + const Register tmp7 = r16; + + BLOCK_COMMENT("Entry:"); + __ enter(); // required for proper stackwalking of RuntimeStub frame + __ multiply_to_len(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7); + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(lr); + + return start; + } // Continuation point for throwing of implicit exceptions that are // not handled in the current activation. Fabricates an exception @@ -2375,6 +2412,9 @@ // otherwise assume that stack unwinding will be initiated, so // caller saved registers were assumed volatile in the compiler. +#undef __ +#define __ masm-> + address generate_throw_exception(const char* name, address runtime_entry, Register arg1 = noreg, @@ -2518,6 +2558,10 @@ // arraycopy stubs used by compilers generate_arraycopy_stubs(); + if (UseMultiplyToLenIntrinsic) { + StubRoutines::_multiplyToLen = generate_multiplyToLen(); + } + #ifndef BUILTIN_SIM if (UseAESIntrinsics) { StubRoutines::_aescrypt_encryptBlock = generate_aescrypt_encryptBlock(); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/aarch64/vm/templateTable_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/templateTable_aarch64.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/templateTable_aarch64.cpp Thu May 07 20:51:12 2015 -0700 @@ -502,10 +502,17 @@ __ neg(reg, reg); } -void TemplateTable::iload() -{ +void TemplateTable::iload() { + iload_internal(); +} + +void TemplateTable::nofast_iload() { + iload_internal(may_not_rewrite); +} + +void TemplateTable::iload_internal(RewriteControl rc) { transition(vtos, itos); - if (RewriteFrequentPairs) { + if (RewriteFrequentPairs && rc == may_rewrite) { // TODO : check x86 code for what to do here __ call_Unimplemented(); } else { @@ -759,8 +766,15 @@ __ ldr(r0, iaddress(n)); } -void TemplateTable::aload_0() -{ +void TemplateTable::aload_0() { + aload_0_internal(); +} + +void TemplateTable::nofast_aload_0() { + aload_0_internal(may_not_rewrite); +} + +void TemplateTable::aload_0_internal(RewriteControl rc) { // According to bytecode histograms, the pairs: // // _aload_0, _fast_igetfield @@ -782,7 +796,7 @@ // aload_0, iload_1 // These bytecodes with a small amount of code are most profitable // to rewrite - if (RewriteFrequentPairs) { + if (RewriteFrequentPairs && rc == may_rewrite) { __ call_Unimplemented(); } else { aload(0); @@ -2132,37 +2146,21 @@ assert_different_registers(Rcache, index, temp); Label resolved; + + Bytecodes::Code code = bytecode(); + switch (code) { + case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break; + case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break; + } + assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); __ get_cache_and_index_and_bytecode_at_bcp(Rcache, index, temp, byte_no, 1, index_size); - __ cmp(temp, (int) bytecode()); // have we resolved this bytecode? + __ cmp(temp, (int) code); // have we resolved this bytecode? __ br(Assembler::EQ, resolved); // resolve first time through - address entry; - switch (bytecode()) { - case Bytecodes::_getstatic: - case Bytecodes::_putstatic: - case Bytecodes::_getfield: - case Bytecodes::_putfield: - entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_get_put); - break; - case Bytecodes::_invokevirtual: - case Bytecodes::_invokespecial: - case Bytecodes::_invokestatic: - case Bytecodes::_invokeinterface: - entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invoke); - break; - case Bytecodes::_invokehandle: - entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokehandle); - break; - case Bytecodes::_invokedynamic: - entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokedynamic); - break; - default: - fatal(err_msg("unexpected bytecode: %s", Bytecodes::name(bytecode()))); - break; - } - __ mov(temp, (int) bytecode()); + address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache); + __ mov(temp, (int) code); __ call_VM(noreg, entry, temp); // Update registers with resolved info @@ -2280,7 +2278,7 @@ __ verify_oop(r); } -void TemplateTable::getfield_or_static(int byte_no, bool is_static) +void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteControl rc) { const Register cache = r2; const Register index = r3; @@ -2310,11 +2308,14 @@ assert(btos == 0, "change code, btos != 0"); __ cbnz(flags, notByte); + // Don't rewrite getstatic, only getfield + if (is_static) rc = may_not_rewrite; + // btos __ load_signed_byte(r0, field); __ push(btos); // Rewrite bytecode to be faster - if (!is_static) { + if (rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_bgetfield, bc, r1); } __ b(Done); @@ -2325,7 +2326,7 @@ // atos __ load_heap_oop(r0, field); __ push(atos); - if (!is_static) { + if (rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_agetfield, bc, r1); } __ b(Done); @@ -2337,7 +2338,7 @@ __ ldrw(r0, field); __ push(itos); // Rewrite bytecode to be faster - if (!is_static) { + if (rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_igetfield, bc, r1); } __ b(Done); @@ -2349,7 +2350,7 @@ __ load_unsigned_short(r0, field); __ push(ctos); // Rewrite bytecode to be faster - if (!is_static) { + if (rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_cgetfield, bc, r1); } __ b(Done); @@ -2361,7 +2362,7 @@ __ load_signed_short(r0, field); __ push(stos); // Rewrite bytecode to be faster - if (!is_static) { + if (rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_sgetfield, bc, r1); } __ b(Done); @@ -2373,7 +2374,7 @@ __ ldr(r0, field); __ push(ltos); // Rewrite bytecode to be faster - if (!is_static) { + if (rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_lgetfield, bc, r1); } __ b(Done); @@ -2385,7 +2386,7 @@ __ ldrs(v0, field); __ push(ftos); // Rewrite bytecode to be faster - if (!is_static) { + if (rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_fgetfield, bc, r1); } __ b(Done); @@ -2399,7 +2400,7 @@ __ ldrd(v0, field); __ push(dtos); // Rewrite bytecode to be faster - if (!is_static) { + if (rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_dgetfield, bc, r1); } #ifdef ASSERT @@ -2421,6 +2422,10 @@ getfield_or_static(byte_no, false); } +void TemplateTable::nofast_getfield(int byte_no) { + getfield_or_static(byte_no, false, may_not_rewrite); +} + void TemplateTable::getstatic(int byte_no) { getfield_or_static(byte_no, true); @@ -2484,7 +2489,7 @@ } } -void TemplateTable::putfield_or_static(int byte_no, bool is_static) { +void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteControl rc) { transition(vtos, vtos); const Register cache = r2; @@ -2521,12 +2526,15 @@ assert(btos == 0, "change code, btos != 0"); __ cbnz(flags, notByte); + // Don't rewrite putstatic, only putfield + if (is_static) rc = may_not_rewrite; + // btos { __ pop(btos); if (!is_static) pop_and_check_object(obj); __ strb(r0, field); - if (!is_static) { + if (rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_bputfield, bc, r1, true, byte_no); } __ b(Done); @@ -2542,7 +2550,7 @@ if (!is_static) pop_and_check_object(obj); // Store into the field do_oop_store(_masm, field, r0, _bs->kind(), false); - if (!is_static) { + if (rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_aputfield, bc, r1, true, byte_no); } __ b(Done); @@ -2557,7 +2565,7 @@ __ pop(itos); if (!is_static) pop_and_check_object(obj); __ strw(r0, field); - if (!is_static) { + if (rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_iputfield, bc, r1, true, byte_no); } __ b(Done); @@ -2572,7 +2580,7 @@ __ pop(ctos); if (!is_static) pop_and_check_object(obj); __ strh(r0, field); - if (!is_static) { + if (rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_cputfield, bc, r1, true, byte_no); } __ b(Done); @@ -2587,7 +2595,7 @@ __ pop(stos); if (!is_static) pop_and_check_object(obj); __ strh(r0, field); - if (!is_static) { + if (rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_sputfield, bc, r1, true, byte_no); } __ b(Done); @@ -2602,7 +2610,7 @@ __ pop(ltos); if (!is_static) pop_and_check_object(obj); __ str(r0, field); - if (!is_static) { + if (rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_lputfield, bc, r1, true, byte_no); } __ b(Done); @@ -2617,7 +2625,7 @@ __ pop(ftos); if (!is_static) pop_and_check_object(obj); __ strs(v0, field); - if (!is_static) { + if (rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_fputfield, bc, r1, true, byte_no); } __ b(Done); @@ -2634,7 +2642,7 @@ __ pop(dtos); if (!is_static) pop_and_check_object(obj); __ strd(v0, field); - if (!is_static) { + if (rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_dputfield, bc, r1, true, byte_no); } } @@ -2661,6 +2669,10 @@ putfield_or_static(byte_no, false); } +void TemplateTable::nofast_putfield(int byte_no) { + putfield_or_static(byte_no, false, may_not_rewrite); +} + void TemplateTable::putstatic(int byte_no) { putfield_or_static(byte_no, true); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2015, Red Hat Inc. 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 @@ -193,6 +193,15 @@ } } + // This machine allows unaligned memory accesses + if (FLAG_IS_DEFAULT(UseUnalignedAccesses)) { + FLAG_SET_DEFAULT(UseUnalignedAccesses, true); + } + + if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { + UseMultiplyToLenIntrinsic = true; + } + #ifdef COMPILER2 if (FLAG_IS_DEFAULT(OptoScheduling)) { OptoScheduling = true; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/assembler_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/assembler_ppc.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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 @@ -85,8 +85,7 @@ } // Low-level andi-one-instruction-macro. -void Assembler::andi(Register a, Register s, const int ui16) { - assert(is_uimm(ui16, 16), "must be 16-bit unsigned immediate"); +void Assembler::andi(Register a, Register s, const long ui16) { if (is_power_of_2_long(((jlong) ui16)+1)) { // pow2minus1 clrldi(a, s, 64-log2_long((((jlong) ui16)+1))); @@ -97,6 +96,7 @@ // negpow2 clrrdi(a, s, log2_long((jlong)-ui16)); } else { + assert(is_uimm(ui16, 16), "must be 16-bit unsigned immediate"); andi_(a, s, ui16); } } @@ -356,7 +356,6 @@ // 16 bit immediate offset. int Assembler::load_const_optimized(Register d, long x, Register tmp, bool return_simm16_rest) { // Avoid accidentally trying to use R0 for indexed addressing. - assert(d != R0, "R0 not allowed"); assert_different_registers(d, tmp); short xa, xb, xc, xd; // Four 16-bit chunks of const. @@ -370,6 +369,58 @@ return 0; } + int retval = 0; + if (return_simm16_rest) { + retval = xd; + x = rem << 16; + xd = 0; + } + + if (d == R0) { // Can't use addi. + if (is_simm(x, 32)) { // opt 2: simm32 + lis(d, x >> 16); + if (xd) ori(d, d, (unsigned short)xd); + } else { + // 64-bit value: x = xa xb xc xd + xa = (x >> 48) & 0xffff; + xb = (x >> 32) & 0xffff; + xc = (x >> 16) & 0xffff; + bool xa_loaded = (xb & 0x8000) ? (xa != -1) : (xa != 0); + if (tmp == noreg || (xc == 0 && xd == 0)) { + if (xa_loaded) { + lis(d, xa); + if (xb) { ori(d, d, (unsigned short)xb); } + } else { + li(d, xb); + } + sldi(d, d, 32); + if (xc) { oris(d, d, (unsigned short)xc); } + if (xd) { ori( d, d, (unsigned short)xd); } + } else { + // Exploit instruction level parallelism if we have a tmp register. + bool xc_loaded = (xd & 0x8000) ? (xc != -1) : (xc != 0); + if (xa_loaded) { + lis(tmp, xa); + } + if (xc_loaded) { + lis(d, xc); + } + if (xa_loaded) { + if (xb) { ori(tmp, tmp, (unsigned short)xb); } + } else { + li(tmp, xb); + } + if (xc_loaded) { + if (xd) { ori(d, d, (unsigned short)xd); } + } else { + li(d, xd); + } + insrdi(d, tmp, 32, 0); + } + } + return retval; + } + xc = rem & 0xFFFF; // Next 16-bit chunk. rem = (rem >> 16) + ((unsigned short)xc >> 15); // Compensation for sign extend. @@ -377,28 +428,27 @@ lis(d, xc); } else { // High 32 bits needed. - if (tmp != noreg) { // opt 3: We have a temp reg. + if (tmp != noreg && (int)x != 0) { // opt 3: We have a temp reg. // No carry propagation between xc and higher chunks here (use logical instructions). xa = (x >> 48) & 0xffff; xb = (x >> 32) & 0xffff; // No sign compensation, we use lis+ori or li to allow usage of R0. - bool load_xa = (xa != 0) || (xb < 0); + bool xa_loaded = (xb & 0x8000) ? (xa != -1) : (xa != 0); bool return_xd = false; - if (load_xa) { lis(tmp, xa); } + if (xa_loaded) { lis(tmp, xa); } if (xc) { lis(d, xc); } - if (load_xa) { + if (xa_loaded) { if (xb) { ori(tmp, tmp, (unsigned short)xb); } // No addi, we support tmp == R0. } else { - li(tmp, xb); // non-negative + li(tmp, xb); } if (xc) { - if (return_simm16_rest && xd >= 0) { return_xd = true; } // >= 0 to avoid carry propagation after insrdi/rldimi. - else if (xd) { addi(d, d, xd); } + if (xd) { addi(d, d, xd); } } else { li(d, xd); } insrdi(d, tmp, 32, 0); - return return_xd ? xd : 0; // non-negative + return retval; } xb = rem & 0xFFFF; // Next 16-bit chunk. @@ -417,11 +467,51 @@ if (xc) { addis(d, d, xc); } } - // opt 5: Return offset to be inserted into following instruction. - if (return_simm16_rest) return xd; + if (xd) { addi(d, d, xd); } + return retval; +} + +// We emit only one addition to s to optimize latency. +int Assembler::add_const_optimized(Register d, Register s, long x, Register tmp, bool return_simm16_rest) { + assert(s != R0 && s != tmp, "unsupported"); + long rem = x; - if (xd) { addi(d, d, xd); } - return 0; + // Case 1: Can use mr or addi. + short xd = rem & 0xFFFF; // Lowest 16-bit chunk. + rem = (rem >> 16) + ((unsigned short)xd >> 15); + if (rem == 0) { + if (xd == 0) { + if (d != s) { mr(d, s); } + return 0; + } + if (return_simm16_rest) { + return xd; + } + addi(d, s, xd); + return 0; + } + + // Case 2: Can use addis. + if (xd == 0) { + short xc = rem & 0xFFFF; // 2nd 16-bit chunk. + rem = (rem >> 16) + ((unsigned short)xd >> 15); + if (rem == 0) { + addis(d, s, xc); + return 0; + } + } + + // Other cases: load & add. + Register tmp1 = tmp, + tmp2 = noreg; + if ((d != tmp) && (d != s)) { + // Can use d. + tmp1 = d; + tmp2 = tmp; + } + int simm16_rest = load_const_optimized(tmp1, x, tmp2, return_simm16_rest); + add(d, tmp1, s); + return simm16_rest; } #ifndef PRODUCT diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/assembler_ppc.hpp --- a/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp Thu May 07 20:51:12 2015 -0700 @@ -224,10 +224,13 @@ ADDIS_OPCODE = (15u << OPCODE_SHIFT), ADDIC__OPCODE = (13u << OPCODE_SHIFT), ADDE_OPCODE = (31u << OPCODE_SHIFT | 138u << 1), + ADDME_OPCODE = (31u << OPCODE_SHIFT | 234u << 1), + ADDZE_OPCODE = (31u << OPCODE_SHIFT | 202u << 1), SUBF_OPCODE = (31u << OPCODE_SHIFT | 40u << 1), SUBFC_OPCODE = (31u << OPCODE_SHIFT | 8u << 1), SUBFE_OPCODE = (31u << OPCODE_SHIFT | 136u << 1), SUBFIC_OPCODE = (8u << OPCODE_SHIFT), + SUBFME_OPCODE = (31u << OPCODE_SHIFT | 232u << 1), SUBFZE_OPCODE = (31u << OPCODE_SHIFT | 200u << 1), DIVW_OPCODE = (31u << OPCODE_SHIFT | 491u << 1), MULLW_OPCODE = (31u << OPCODE_SHIFT | 235u << 1), @@ -657,6 +660,9 @@ SYNC_OPCODE = (31u << OPCODE_SHIFT | 598u << 1), EIEIO_OPCODE = (31u << OPCODE_SHIFT | 854u << 1), + // Wait instructions for polling. + WAIT_OPCODE = (31u << OPCODE_SHIFT | 62u << 1), + // Trap instructions TDI_OPCODE = (2u << OPCODE_SHIFT), TWI_OPCODE = (3u << OPCODE_SHIFT), @@ -666,8 +672,10 @@ // Atomics. LWARX_OPCODE = (31u << OPCODE_SHIFT | 20u << 1), LDARX_OPCODE = (31u << OPCODE_SHIFT | 84u << 1), + LQARX_OPCODE = (31u << OPCODE_SHIFT | 276u << 1), STWCX_OPCODE = (31u << OPCODE_SHIFT | 150u << 1), - STDCX_OPCODE = (31u << OPCODE_SHIFT | 214u << 1) + STDCX_OPCODE = (31u << OPCODE_SHIFT | 214u << 1), + STQCX_OPCODE = (31u << OPCODE_SHIFT | 182u << 1) }; @@ -1171,6 +1179,14 @@ inline void adde_( Register d, Register a, Register b); inline void subfe( Register d, Register a, Register b); inline void subfe_( Register d, Register a, Register b); + inline void addme( Register d, Register a); + inline void addme_( Register d, Register a); + inline void subfme( Register d, Register a); + inline void subfme_(Register d, Register a); + inline void addze( Register d, Register a); + inline void addze_( Register d, Register a); + inline void subfze( Register d, Register a); + inline void subfze_(Register d, Register a); inline void neg( Register d, Register a); inline void neg_( Register d, Register a); inline void mulli( Register d, Register a, int si16); @@ -1189,6 +1205,38 @@ inline void divw( Register d, Register a, Register b); inline void divw_( Register d, Register a, Register b); + // Fixed-Point Arithmetic Instructions with Overflow detection + inline void addo( Register d, Register a, Register b); + inline void addo_( Register d, Register a, Register b); + inline void subfo( Register d, Register a, Register b); + inline void subfo_( Register d, Register a, Register b); + inline void addco( Register d, Register a, Register b); + inline void addco_( Register d, Register a, Register b); + inline void subfco( Register d, Register a, Register b); + inline void subfco_( Register d, Register a, Register b); + inline void addeo( Register d, Register a, Register b); + inline void addeo_( Register d, Register a, Register b); + inline void subfeo( Register d, Register a, Register b); + inline void subfeo_( Register d, Register a, Register b); + inline void addmeo( Register d, Register a); + inline void addmeo_( Register d, Register a); + inline void subfmeo( Register d, Register a); + inline void subfmeo_(Register d, Register a); + inline void addzeo( Register d, Register a); + inline void addzeo_( Register d, Register a); + inline void subfzeo( Register d, Register a); + inline void subfzeo_(Register d, Register a); + inline void nego( Register d, Register a); + inline void nego_( Register d, Register a); + inline void mulldo( Register d, Register a, Register b); + inline void mulldo_( Register d, Register a, Register b); + inline void mullwo( Register d, Register a, Register b); + inline void mullwo_( Register d, Register a, Register b); + inline void divdo( Register d, Register a, Register b); + inline void divdo_( Register d, Register a, Register b); + inline void divwo( Register d, Register a, Register b); + inline void divwo_( Register d, Register a, Register b); + // extended mnemonics inline void li( Register d, int si16); inline void lis( Register d, int si16); @@ -1303,7 +1351,7 @@ inline void isel_0( Register d, ConditionRegister cr, Condition cc, Register b = noreg); // PPC 1, section 3.3.11, Fixed-Point Logical Instructions - void andi( Register a, Register s, int ui16); // optimized version + void andi( Register a, Register s, long ui16); // optimized version inline void andi_( Register a, Register s, int ui16); inline void andis_( Register a, Register s, int ui16); inline void ori( Register a, Register s, int ui16); @@ -1688,14 +1736,21 @@ inline void isync(); inline void elemental_membar(int e); // Elemental Memory Barriers (>=Power 8) + // Wait instructions for polling. Attention: May result in SIGILL. + inline void wait(); + inline void waitrsv(); // >=Power7 + // atomics inline void lwarx_unchecked(Register d, Register a, Register b, int eh1 = 0); inline void ldarx_unchecked(Register d, Register a, Register b, int eh1 = 0); + inline void lqarx_unchecked(Register d, Register a, Register b, int eh1 = 0); inline bool lxarx_hint_exclusive_access(); inline void lwarx( Register d, Register a, Register b, bool hint_exclusive_access = false); inline void ldarx( Register d, Register a, Register b, bool hint_exclusive_access = false); + inline void lqarx( Register d, Register a, Register b, bool hint_exclusive_access = false); inline void stwcx_( Register s, Register a, Register b); inline void stdcx_( Register s, Register a, Register b); + inline void stqcx_( Register s, Register a, Register b); // Instructions for adjusting thread priority for simultaneous // multithreading (SMT) on Power5. @@ -2054,10 +2109,13 @@ // Atomics: use ra0mem to disallow R0 as base. inline void lwarx_unchecked(Register d, Register b, int eh1); inline void ldarx_unchecked(Register d, Register b, int eh1); + inline void lqarx_unchecked(Register d, Register b, int eh1); inline void lwarx( Register d, Register b, bool hint_exclusive_access); inline void ldarx( Register d, Register b, bool hint_exclusive_access); + inline void lqarx( Register d, Register b, bool hint_exclusive_access); inline void stwcx_(Register s, Register b); inline void stdcx_(Register s, Register b); + inline void stqcx_(Register s, Register b); inline void lfs( FloatRegister d, int si16); inline void lfsx( FloatRegister d, Register b); inline void lfd( FloatRegister d, int si16); @@ -2120,6 +2178,20 @@ return load_const_optimized(d, (long)(unsigned long)a, tmp, return_simm16_rest); } + // If return_simm16_rest, the return value needs to get added afterwards. + int add_const_optimized(Register d, Register s, long x, Register tmp = R0, bool return_simm16_rest = false); + inline int add_const_optimized(Register d, Register s, void* a, Register tmp = R0, bool return_simm16_rest = false) { + return add_const_optimized(d, s, (long)(unsigned long)a, tmp, return_simm16_rest); + } + + // If return_simm16_rest, the return value needs to get added afterwards. + inline int sub_const_optimized(Register d, Register s, long x, Register tmp = R0, bool return_simm16_rest = false) { + return add_const_optimized(d, s, -x, tmp, return_simm16_rest); + } + inline int sub_const_optimized(Register d, Register s, void* a, Register tmp = R0, bool return_simm16_rest = false) { + return sub_const_optimized(d, s, (long)(unsigned long)a, tmp, return_simm16_rest); + } + // Creation Assembler(CodeBuffer* code) : AbstractAssembler(code) { #ifdef CHECK_DELAY diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp --- a/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -100,6 +100,14 @@ inline void Assembler::adde_( Register d, Register a, Register b) { emit_int32(ADDE_OPCODE | rt(d) | ra(a) | rb(b) | oe(0) | rc(1)); } inline void Assembler::subfe( Register d, Register a, Register b) { emit_int32(SUBFE_OPCODE | rt(d) | ra(a) | rb(b) | oe(0) | rc(0)); } inline void Assembler::subfe_( Register d, Register a, Register b) { emit_int32(SUBFE_OPCODE | rt(d) | ra(a) | rb(b) | oe(0) | rc(1)); } +inline void Assembler::addme( Register d, Register a) { emit_int32(ADDME_OPCODE | rt(d) | ra(a) | oe(0) | rc(0)); } +inline void Assembler::addme_( Register d, Register a) { emit_int32(ADDME_OPCODE | rt(d) | ra(a) | oe(0) | rc(1)); } +inline void Assembler::subfme( Register d, Register a) { emit_int32(SUBFME_OPCODE | rt(d) | ra(a) | oe(0) | rc(0)); } +inline void Assembler::subfme_(Register d, Register a) { emit_int32(SUBFME_OPCODE | rt(d) | ra(a) | oe(0) | rc(1)); } +inline void Assembler::addze( Register d, Register a) { emit_int32(ADDZE_OPCODE | rt(d) | ra(a) | oe(0) | rc(0)); } +inline void Assembler::addze_( Register d, Register a) { emit_int32(ADDZE_OPCODE | rt(d) | ra(a) | oe(0) | rc(1)); } +inline void Assembler::subfze( Register d, Register a) { emit_int32(SUBFZE_OPCODE | rt(d) | ra(a) | oe(0) | rc(0)); } +inline void Assembler::subfze_(Register d, Register a) { emit_int32(SUBFZE_OPCODE | rt(d) | ra(a) | oe(0) | rc(1)); } inline void Assembler::neg( Register d, Register a) { emit_int32(NEG_OPCODE | rt(d) | ra(a) | oe(0) | rc(0)); } inline void Assembler::neg_( Register d, Register a) { emit_int32(NEG_OPCODE | rt(d) | ra(a) | oe(0) | rc(1)); } inline void Assembler::mulli( Register d, Register a, int si16) { emit_int32(MULLI_OPCODE | rt(d) | ra(a) | simm(si16, 16)); } @@ -118,6 +126,38 @@ inline void Assembler::divw( Register d, Register a, Register b) { emit_int32(DIVW_OPCODE | rt(d) | ra(a) | rb(b) | oe(0) | rc(0)); } inline void Assembler::divw_( Register d, Register a, Register b) { emit_int32(DIVW_OPCODE | rt(d) | ra(a) | rb(b) | oe(0) | rc(1)); } +// Fixed-Point Arithmetic Instructions with Overflow detection +inline void Assembler::addo( Register d, Register a, Register b) { emit_int32(ADD_OPCODE | rt(d) | ra(a) | rb(b) | oe(1) | rc(0)); } +inline void Assembler::addo_( Register d, Register a, Register b) { emit_int32(ADD_OPCODE | rt(d) | ra(a) | rb(b) | oe(1) | rc(1)); } +inline void Assembler::subfo( Register d, Register a, Register b) { emit_int32(SUBF_OPCODE | rt(d) | ra(a) | rb(b) | oe(1) | rc(0)); } +inline void Assembler::subfo_( Register d, Register a, Register b) { emit_int32(SUBF_OPCODE | rt(d) | ra(a) | rb(b) | oe(1) | rc(1)); } +inline void Assembler::addco( Register d, Register a, Register b) { emit_int32(ADDC_OPCODE | rt(d) | ra(a) | rb(b) | oe(1) | rc(0)); } +inline void Assembler::addco_( Register d, Register a, Register b) { emit_int32(ADDC_OPCODE | rt(d) | ra(a) | rb(b) | oe(1) | rc(1)); } +inline void Assembler::subfco( Register d, Register a, Register b) { emit_int32(SUBFC_OPCODE | rt(d) | ra(a) | rb(b) | oe(1) | rc(0)); } +inline void Assembler::subfco_( Register d, Register a, Register b) { emit_int32(SUBFC_OPCODE | rt(d) | ra(a) | rb(b) | oe(1) | rc(1)); } +inline void Assembler::addeo( Register d, Register a, Register b) { emit_int32(ADDE_OPCODE | rt(d) | ra(a) | rb(b) | oe(1) | rc(0)); } +inline void Assembler::addeo_( Register d, Register a, Register b) { emit_int32(ADDE_OPCODE | rt(d) | ra(a) | rb(b) | oe(1) | rc(1)); } +inline void Assembler::subfeo( Register d, Register a, Register b) { emit_int32(SUBFE_OPCODE | rt(d) | ra(a) | rb(b) | oe(1) | rc(0)); } +inline void Assembler::subfeo_( Register d, Register a, Register b) { emit_int32(SUBFE_OPCODE | rt(d) | ra(a) | rb(b) | oe(1) | rc(1)); } +inline void Assembler::addmeo( Register d, Register a) { emit_int32(ADDME_OPCODE | rt(d) | ra(a) | oe(1) | rc(0)); } +inline void Assembler::addmeo_( Register d, Register a) { emit_int32(ADDME_OPCODE | rt(d) | ra(a) | oe(1) | rc(1)); } +inline void Assembler::subfmeo( Register d, Register a) { emit_int32(SUBFME_OPCODE | rt(d) | ra(a) | oe(1) | rc(0)); } +inline void Assembler::subfmeo_(Register d, Register a) { emit_int32(SUBFME_OPCODE | rt(d) | ra(a) | oe(1) | rc(1)); } +inline void Assembler::addzeo( Register d, Register a) { emit_int32(ADDZE_OPCODE | rt(d) | ra(a) | oe(1) | rc(0)); } +inline void Assembler::addzeo_( Register d, Register a) { emit_int32(ADDZE_OPCODE | rt(d) | ra(a) | oe(1) | rc(1)); } +inline void Assembler::subfzeo( Register d, Register a) { emit_int32(SUBFZE_OPCODE | rt(d) | ra(a) | oe(1) | rc(0)); } +inline void Assembler::subfzeo_(Register d, Register a) { emit_int32(SUBFZE_OPCODE | rt(d) | ra(a) | oe(1) | rc(1)); } +inline void Assembler::nego( Register d, Register a) { emit_int32(NEG_OPCODE | rt(d) | ra(a) | oe(1) | rc(0)); } +inline void Assembler::nego_( Register d, Register a) { emit_int32(NEG_OPCODE | rt(d) | ra(a) | oe(1) | rc(1)); } +inline void Assembler::mulldo( Register d, Register a, Register b) { emit_int32(MULLD_OPCODE | rt(d) | ra(a) | rb(b) | oe(1) | rc(0)); } +inline void Assembler::mulldo_( Register d, Register a, Register b) { emit_int32(MULLD_OPCODE | rt(d) | ra(a) | rb(b) | oe(1) | rc(1)); } +inline void Assembler::mullwo( Register d, Register a, Register b) { emit_int32(MULLW_OPCODE | rt(d) | ra(a) | rb(b) | oe(1) | rc(0)); } +inline void Assembler::mullwo_( Register d, Register a, Register b) { emit_int32(MULLW_OPCODE | rt(d) | ra(a) | rb(b) | oe(1) | rc(1)); } +inline void Assembler::divdo( Register d, Register a, Register b) { emit_int32(DIVD_OPCODE | rt(d) | ra(a) | rb(b) | oe(1) | rc(0)); } +inline void Assembler::divdo_( Register d, Register a, Register b) { emit_int32(DIVD_OPCODE | rt(d) | ra(a) | rb(b) | oe(1) | rc(1)); } +inline void Assembler::divwo( Register d, Register a, Register b) { emit_int32(DIVW_OPCODE | rt(d) | ra(a) | rb(b) | oe(1) | rc(0)); } +inline void Assembler::divwo_( Register d, Register a, Register b) { emit_int32(DIVW_OPCODE | rt(d) | ra(a) | rb(b) | oe(1) | rc(1)); } + // extended mnemonics inline void Assembler::li( Register d, int si16) { Assembler::addi_r0ok( d, R0, si16); } inline void Assembler::lis( Register d, int si16) { Assembler::addis_r0ok(d, R0, si16); } @@ -540,15 +580,22 @@ inline void Assembler::isync() { emit_int32( ISYNC_OPCODE); } inline void Assembler::elemental_membar(int e) { assert(0 < e && e < 16, "invalid encoding"); emit_int32( SYNC_OPCODE | e1215(e)); } +// Wait instructions for polling. +inline void Assembler::wait() { emit_int32( WAIT_OPCODE); } +inline void Assembler::waitrsv() { emit_int32( WAIT_OPCODE | 1<<(31-10)); } // WC=0b01 >=Power7 + // atomics // Use ra0mem to disallow R0 as base. inline void Assembler::lwarx_unchecked(Register d, Register a, Register b, int eh1) { emit_int32( LWARX_OPCODE | rt(d) | ra0mem(a) | rb(b) | eh(eh1)); } inline void Assembler::ldarx_unchecked(Register d, Register a, Register b, int eh1) { emit_int32( LDARX_OPCODE | rt(d) | ra0mem(a) | rb(b) | eh(eh1)); } +inline void Assembler::lqarx_unchecked(Register d, Register a, Register b, int eh1) { emit_int32( LQARX_OPCODE | rt(d) | ra0mem(a) | rb(b) | eh(eh1)); } inline bool Assembler::lxarx_hint_exclusive_access() { return VM_Version::has_lxarxeh(); } inline void Assembler::lwarx( Register d, Register a, Register b, bool hint_exclusive_access) { lwarx_unchecked(d, a, b, (hint_exclusive_access && lxarx_hint_exclusive_access() && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } inline void Assembler::ldarx( Register d, Register a, Register b, bool hint_exclusive_access) { ldarx_unchecked(d, a, b, (hint_exclusive_access && lxarx_hint_exclusive_access() && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } +inline void Assembler::lqarx( Register d, Register a, Register b, bool hint_exclusive_access) { lqarx_unchecked(d, a, b, (hint_exclusive_access && lxarx_hint_exclusive_access() && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } inline void Assembler::stwcx_(Register s, Register a, Register b) { emit_int32( STWCX_OPCODE | rs(s) | ra0mem(a) | rb(b) | rc(1)); } inline void Assembler::stdcx_(Register s, Register a, Register b) { emit_int32( STDCX_OPCODE | rs(s) | ra0mem(a) | rb(b) | rc(1)); } +inline void Assembler::stqcx_(Register s, Register a, Register b) { emit_int32( STQCX_OPCODE | rs(s) | ra0mem(a) | rb(b) | rc(1)); } // Instructions for adjusting thread priority // for simultaneous multithreading (SMT) on POWER5. @@ -873,10 +920,13 @@ // ra0 version inline void Assembler::lwarx_unchecked(Register d, Register b, int eh1) { emit_int32( LWARX_OPCODE | rt(d) | rb(b) | eh(eh1)); } inline void Assembler::ldarx_unchecked(Register d, Register b, int eh1) { emit_int32( LDARX_OPCODE | rt(d) | rb(b) | eh(eh1)); } +inline void Assembler::lqarx_unchecked(Register d, Register b, int eh1) { emit_int32( LQARX_OPCODE | rt(d) | rb(b) | eh(eh1)); } inline void Assembler::lwarx( Register d, Register b, bool hint_exclusive_access){ lwarx_unchecked(d, b, (hint_exclusive_access && lxarx_hint_exclusive_access() && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } inline void Assembler::ldarx( Register d, Register b, bool hint_exclusive_access){ ldarx_unchecked(d, b, (hint_exclusive_access && lxarx_hint_exclusive_access() && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } +inline void Assembler::lqarx( Register d, Register b, bool hint_exclusive_access){ lqarx_unchecked(d, b, (hint_exclusive_access && lxarx_hint_exclusive_access() && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } inline void Assembler::stwcx_(Register s, Register b) { emit_int32( STWCX_OPCODE | rs(s) | rb(b) | rc(1)); } inline void Assembler::stdcx_(Register s, Register b) { emit_int32( STDCX_OPCODE | rs(s) | rb(b) | rc(1)); } +inline void Assembler::stqcx_(Register s, Register b) { emit_int32( STQCX_OPCODE | rs(s) | rb(b) | rc(1)); } // ra0 version inline void Assembler::lfs( FloatRegister d, int si16) { emit_int32( LFS_OPCODE | frt(d) | simm(si16,16)); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp --- a/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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 @@ -47,7 +47,7 @@ define_pd_global(intx, FLOATPRESSURE, 28); define_pd_global(intx, FreqInlineSize, 175); define_pd_global(intx, MinJumpTableSize, 10); -define_pd_global(intx, INTPRESSURE, 25); +define_pd_global(intx, INTPRESSURE, 26); define_pd_global(intx, InteriorEntryAlignment, 16); define_pd_global(size_t, NewSizeThreadIncrease, ScaleForWordSize(4*K)); define_pd_global(intx, RegisterCostAreaRatio, 16000); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/globals_ppc.hpp --- a/hotspot/src/cpu/ppc/vm/globals_ppc.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/globals_ppc.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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 @@ -55,10 +55,12 @@ define_pd_global(bool, UseMembar, false); +define_pd_global(bool, PreserveFramePointer, false); + // GC Ergo Flags define_pd_global(size_t, CMSYoungGenPerWorker, 16*M); // Default max size of CMS young gen, per GC worker thread. -define_pd_global(uintx, TypeProfileLevel, 0); +define_pd_global(uintx, TypeProfileLevel, 111); // Platform dependent flag handling: flags only defined on this platform. #define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \ @@ -71,14 +73,26 @@ \ product(uintx, PowerArchitecturePPC64, 0, \ "CPU Version: x for PowerX. Currently recognizes Power5 to " \ - "Power7. Default is 0. CPUs newer than Power7 will be " \ - "recognized as Power7.") \ + "Power8. Default is 0. Newer CPUs will be recognized as Power8.") \ \ /* Reoptimize code-sequences of calls at runtime, e.g. replace an */ \ /* indirect call by a direct call. */ \ product(bool, ReoptimizeCallSequences, true, \ "Reoptimize code-sequences of calls at runtime.") \ \ + /* Power 8: Configure Data Stream Control Register. */ \ + product(uint64_t,DSCR_PPC64, (uintx)-1, \ + "Power8 or later: Specify encoded value for Data Stream Control " \ + "Register") \ + product(uint64_t,DSCR_DPFD_PPC64, 8, \ + "Power8 or later: DPFD (default prefetch depth) value of the " \ + "Data Stream Control Register." \ + " 0: hardware default, 1: none, 2-7: min-max, 8: don't touch") \ + product(uint64_t,DSCR_URG_PPC64, 8, \ + "Power8 or later: URG (depth attainment urgency) value of the " \ + "Data Stream Control Register." \ + " 0: hardware default, 1: none, 2-7: min-max, 8: don't touch") \ + \ product(bool, UseLoadInstructionsForStackBangingPPC64, false, \ "Use load instructions for stack banging.") \ \ @@ -121,6 +135,41 @@ \ product(bool, ZapMemory, false, "Write 0x0101... to empty memory." \ " Use this to ease debugging.") \ - + \ + /* Use Restricted Transactional Memory for lock eliding */ \ + product(bool, UseRTMLocking, false, \ + "Enable RTM lock eliding for inflated locks in compiled code") \ + \ + experimental(bool, UseRTMForStackLocks, false, \ + "Enable RTM lock eliding for stack locks in compiled code") \ + \ + product(bool, UseRTMDeopt, false, \ + "Perform deopt and recompilation based on RTM abort ratio") \ + \ + product(uintx, RTMRetryCount, 5, \ + "Number of RTM retries on lock abort or busy") \ + \ + experimental(intx, RTMSpinLoopCount, 100, \ + "Spin count for lock to become free before RTM retry") \ + \ + experimental(intx, RTMAbortThreshold, 1000, \ + "Calculate abort ratio after this number of aborts") \ + \ + experimental(intx, RTMLockingThreshold, 10000, \ + "Lock count at which to do RTM lock eliding without " \ + "abort ratio calculation") \ + \ + experimental(intx, RTMAbortRatio, 50, \ + "Lock abort ratio at which to stop use RTM lock eliding") \ + \ + experimental(intx, RTMTotalCountIncrRate, 64, \ + "Increment total RTM attempted lock count once every n times") \ + \ + experimental(intx, RTMLockingCalculationDelay, 0, \ + "Number of milliseconds to wait before start calculating aborts " \ + "for RTM locking") \ + \ + experimental(bool, UseRTMXendForLockBusy, true, \ + "Use RTM Xend instead of Xabort when lock busy") \ #endif // CPU_PPC_VM_GLOBALS_PPC_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp --- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp Thu May 07 20:51:12 2015 -0700 @@ -446,7 +446,7 @@ } // Load object from cpool->resolved_references(index). -void InterpreterMacroAssembler::load_resolved_reference_at_index(Register result, Register index) { +void InterpreterMacroAssembler::load_resolved_reference_at_index(Register result, Register index, Label *is_null) { assert_different_registers(result, index); get_constant_pool(result); @@ -469,7 +469,7 @@ #endif // Add in the index. add(result, tmp, result); - load_heap_oop(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT), result); + load_heap_oop(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT), result, is_null); } // Generate a subtype check: branch to ok_is_subtype if sub_klass is @@ -876,7 +876,6 @@ // If condition is true we are done and hence we can store 0 in the displaced // header indicating it is a recursive lock. bne(CCR0, slow_case); - release(); std(R0/*==0!*/, BasicObjectLock::lock_offset_in_bytes() + BasicLock::displaced_header_offset_in_bytes(), monitor); b(done); @@ -1861,7 +1860,7 @@ const Register mdp = tmp1; add(mdp, tmp1, R28_mdx); - // Pffset of the current profile entry to update. + // Offset of the current profile entry to update. const Register entry_offset = tmp2; // entry_offset = array len in number of cells ld(entry_offset, in_bytes(ArrayData::array_len_offset()), mdp); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp --- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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 @@ -85,7 +85,7 @@ Register tmp1, Register tmp2, Register tmp3, Label &ok_is_subtype); // Load object from cpool->resolved_references(index). - void load_resolved_reference_at_index(Register result, Register index); + void load_resolved_reference_at_index(Register result, Register index, Label *is_null = NULL); void generate_stack_overflow_check_with_compare_and_throw(Register Rmem_frame_size, Register Rscratch1); void load_receiver(Register Rparam_count, Register Rrecv_dst); @@ -137,7 +137,6 @@ void field_offset_at(int n, Register tmp, Register dest, Register base); int field_offset_at(Register object, address bcp, int offset); void fast_iaaccess(int n, address bcp); - void fast_iagetfield(address bcp); void fast_iaputfield(address bcp, bool do_store_check); void index_check(Register array, Register index, int index_shift, Register tmp, Register res); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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 @@ -427,7 +427,6 @@ return entry; } - // Call an accessor method (assuming it is resolved, otherwise drop into // vanilla (slow path) entry. address InterpreterGenerator::generate_jump_to_normal_entry(void) { @@ -473,7 +472,8 @@ // This is not a leaf but we have a JavaFrameAnchor now and we will // check (create) exceptions afterward so this is ok. - __ call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError)); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError), + R16_thread); // Pop the C frame and restore LR. __ pop_frame(); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/interpreter_ppc.hpp --- a/hotspot/src/cpu/ppc/vm/interpreter_ppc.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/interpreter_ppc.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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 @@ -47,4 +47,4 @@ } #endif -#endif // CPU_PPC_VM_INTERPRETER_PPC_PP +#endif // CPU_PPC_VM_INTERPRETER_PPC_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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 @@ -1455,7 +1455,7 @@ // Several special cases exist to avoid that unnecessary information is generated. // void MacroAssembler::cmpxchgd(ConditionRegister flag, - Register dest_current_value, Register compare_value, Register exchange_value, + Register dest_current_value, RegisterOrConstant compare_value, Register exchange_value, Register addr_base, int semantics, bool cmpxchgx_hint, Register int_flag_success, Label* failed_ext, bool contention_hint) { Label retry; @@ -1465,7 +1465,7 @@ // Save one branch if result is returned via register and result register is different from the other ones. bool use_result_reg = (int_flag_success!=noreg); - bool preset_result_reg = (int_flag_success!=dest_current_value && int_flag_success!=compare_value && + bool preset_result_reg = (int_flag_success!=dest_current_value && int_flag_success!=compare_value.register_or_noreg() && int_flag_success!=exchange_value && int_flag_success!=addr_base); assert(int_flag_success == noreg || failed_ext == NULL, "cannot have both"); @@ -1481,7 +1481,7 @@ // Add simple guard in order to reduce risk of starving under high contention (recommended by IBM). if (contention_hint) { // Don't try to reserve if cmp fails. ld(dest_current_value, 0, addr_base); - cmpd(flag, dest_current_value, compare_value); + cmpd(flag, compare_value, dest_current_value); bne(flag, failed); } @@ -1489,7 +1489,7 @@ bind(retry); ldarx(dest_current_value, addr_base, cmpxchgx_hint); - cmpd(flag, dest_current_value, compare_value); + cmpd(flag, compare_value, dest_current_value); if (UseStaticBranchPredictionInCompareAndSwapPPC64) { bne_predict_not_taken(flag, failed); } else { @@ -1873,7 +1873,6 @@ assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); // CmpxchgX sets cr_reg to cmpX(temp2_reg, mark_reg). - fence(); // TODO: replace by MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq ? cmpxchgd(/*flag=*/cr_reg, /*current_value=*/temp2_reg, /*compare_value=*/mark_reg, /*exchange_value=*/temp_reg, /*where=*/obj_reg, @@ -1909,7 +1908,6 @@ assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); // CmpxchgX sets cr_reg to cmpX(temp2_reg, mark_reg). - fence(); // TODO: replace by MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq ? cmpxchgd(/*flag=*/cr_reg, /*current_value=*/temp2_reg, /*compare_value=*/mark_reg, /*exchange_value=*/temp_reg, /*where=*/obj_reg, @@ -1946,7 +1944,6 @@ assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); // CmpxchgX sets cr_reg to cmpX(temp2_reg, mark_reg). - fence(); // TODO: replace by MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq ? cmpxchgd(/*flag=*/cr_reg, /*current_value=*/temp2_reg, /*compare_value=*/mark_reg, /*exchange_value=*/temp_reg, /*where=*/obj_reg, @@ -1987,9 +1984,371 @@ beq(cr_reg, done); } +// TM on PPC64. +void MacroAssembler::atomic_inc_ptr(Register addr, Register result, int simm16) { + Label retry; + bind(retry); + ldarx(result, addr, /*hint*/ false); + addi(result, result, simm16); + stdcx_(result, addr); + if (UseStaticBranchPredictionInCompareAndSwapPPC64) { + bne_predict_not_taken(CCR0, retry); // stXcx_ sets CCR0 + } else { + bne( CCR0, retry); // stXcx_ sets CCR0 + } +} + +void MacroAssembler::atomic_ori_int(Register addr, Register result, int uimm16) { + Label retry; + bind(retry); + lwarx(result, addr, /*hint*/ false); + ori(result, result, uimm16); + stwcx_(result, addr); + if (UseStaticBranchPredictionInCompareAndSwapPPC64) { + bne_predict_not_taken(CCR0, retry); // stXcx_ sets CCR0 + } else { + bne( CCR0, retry); // stXcx_ sets CCR0 + } +} + +#if INCLUDE_RTM_OPT + +// Update rtm_counters based on abort status +// input: abort_status +// rtm_counters (RTMLockingCounters*) +void MacroAssembler::rtm_counters_update(Register abort_status, Register rtm_counters_Reg) { + // Mapping to keep PreciseRTMLockingStatistics similar to x86. + // x86 ppc (! means inverted, ? means not the same) + // 0 31 Set if abort caused by XABORT instruction. + // 1 ! 7 If set, the transaction may succeed on a retry. This bit is always clear if bit 0 is set. + // 2 13 Set if another logical processor conflicted with a memory address that was part of the transaction that aborted. + // 3 10 Set if an internal buffer overflowed. + // 4 ?12 Set if a debug breakpoint was hit. + // 5 ?32 Set if an abort occurred during execution of a nested transaction. + const int tm_failure_bit[] = {Assembler::tm_tabort, // Note: Seems like signal handler sets this, too. + Assembler::tm_failure_persistent, // inverted: transient + Assembler::tm_trans_cf, + Assembler::tm_footprint_of, + Assembler::tm_non_trans_cf, + Assembler::tm_suspended}; + const bool tm_failure_inv[] = {false, true, false, false, false, false}; + assert(sizeof(tm_failure_bit)/sizeof(int) == RTMLockingCounters::ABORT_STATUS_LIMIT, "adapt mapping!"); + + const Register addr_Reg = R0; + // Keep track of offset to where rtm_counters_Reg had pointed to. + int counters_offs = RTMLockingCounters::abort_count_offset(); + addi(addr_Reg, rtm_counters_Reg, counters_offs); + const Register temp_Reg = rtm_counters_Reg; + + //atomic_inc_ptr(addr_Reg, temp_Reg); We don't increment atomically + ldx(temp_Reg, addr_Reg); + addi(temp_Reg, temp_Reg, 1); + stdx(temp_Reg, addr_Reg); + + if (PrintPreciseRTMLockingStatistics) { + int counters_offs_delta = RTMLockingCounters::abortX_count_offset() - counters_offs; + + //mftexasr(abort_status); done by caller + for (int i = 0; i < RTMLockingCounters::ABORT_STATUS_LIMIT; i++) { + counters_offs += counters_offs_delta; + li(temp_Reg, counters_offs_delta); // can't use addi with R0 + add(addr_Reg, addr_Reg, temp_Reg); // point to next counter + counters_offs_delta = sizeof(uintx); + + Label check_abort; + rldicr_(temp_Reg, abort_status, tm_failure_bit[i], 0); + if (tm_failure_inv[i]) { + bne(CCR0, check_abort); + } else { + beq(CCR0, check_abort); + } + //atomic_inc_ptr(addr_Reg, temp_Reg); We don't increment atomically + ldx(temp_Reg, addr_Reg); + addi(temp_Reg, temp_Reg, 1); + stdx(temp_Reg, addr_Reg); + bind(check_abort); + } + } + li(temp_Reg, -counters_offs); // can't use addi with R0 + add(rtm_counters_Reg, addr_Reg, temp_Reg); // restore +} + +// Branch if (random & (count-1) != 0), count is 2^n +// tmp and CR0 are killed +void MacroAssembler::branch_on_random_using_tb(Register tmp, int count, Label& brLabel) { + mftb(tmp); + andi_(tmp, tmp, count-1); + bne(CCR0, brLabel); +} + +// Perform abort ratio calculation, set no_rtm bit if high ratio. +// input: rtm_counters_Reg (RTMLockingCounters* address) - KILLED +void MacroAssembler::rtm_abort_ratio_calculation(Register rtm_counters_Reg, + RTMLockingCounters* rtm_counters, + Metadata* method_data) { + Label L_done, L_check_always_rtm1, L_check_always_rtm2; + + if (RTMLockingCalculationDelay > 0) { + // Delay calculation. + ld(rtm_counters_Reg, (RegisterOrConstant)(intptr_t)RTMLockingCounters::rtm_calculation_flag_addr()); + cmpdi(CCR0, rtm_counters_Reg, 0); + beq(CCR0, L_done); + load_const_optimized(rtm_counters_Reg, (address)rtm_counters, R0); // reload + } + // Abort ratio calculation only if abort_count > RTMAbortThreshold. + // Aborted transactions = abort_count * 100 + // All transactions = total_count * RTMTotalCountIncrRate + // Set no_rtm bit if (Aborted transactions >= All transactions * RTMAbortRatio) + ld(R0, RTMLockingCounters::abort_count_offset(), rtm_counters_Reg); + cmpdi(CCR0, R0, RTMAbortThreshold); + blt(CCR0, L_check_always_rtm2); + mulli(R0, R0, 100); + + const Register tmpReg = rtm_counters_Reg; + ld(tmpReg, RTMLockingCounters::total_count_offset(), rtm_counters_Reg); + mulli(tmpReg, tmpReg, RTMTotalCountIncrRate); + mulli(tmpReg, tmpReg, RTMAbortRatio); + cmpd(CCR0, R0, tmpReg); + blt(CCR0, L_check_always_rtm1); // jump to reload + if (method_data != NULL) { + // Set rtm_state to "no rtm" in MDO. + // Not using a metadata relocation. Method and Class Loader are kept alive anyway. + // (See nmethod::metadata_do and CodeBuffer::finalize_oop_references.) + load_const(R0, (address)method_data + MethodData::rtm_state_offset_in_bytes(), tmpReg); + atomic_ori_int(R0, tmpReg, NoRTM); + } + b(L_done); + + bind(L_check_always_rtm1); + load_const_optimized(rtm_counters_Reg, (address)rtm_counters, R0); // reload + bind(L_check_always_rtm2); + ld(tmpReg, RTMLockingCounters::total_count_offset(), rtm_counters_Reg); + cmpdi(CCR0, tmpReg, RTMLockingThreshold / RTMTotalCountIncrRate); + blt(CCR0, L_done); + if (method_data != NULL) { + // Set rtm_state to "always rtm" in MDO. + // Not using a metadata relocation. See above. + load_const(R0, (address)method_data + MethodData::rtm_state_offset_in_bytes(), tmpReg); + atomic_ori_int(R0, tmpReg, UseRTM); + } + bind(L_done); +} + +// Update counters and perform abort ratio calculation. +// input: abort_status_Reg +void MacroAssembler::rtm_profiling(Register abort_status_Reg, Register temp_Reg, + RTMLockingCounters* rtm_counters, + Metadata* method_data, + bool profile_rtm) { + + assert(rtm_counters != NULL, "should not be NULL when profiling RTM"); + // Update rtm counters based on state at abort. + // Reads abort_status_Reg, updates flags. + assert_different_registers(abort_status_Reg, temp_Reg); + load_const_optimized(temp_Reg, (address)rtm_counters, R0); + rtm_counters_update(abort_status_Reg, temp_Reg); + if (profile_rtm) { + assert(rtm_counters != NULL, "should not be NULL when profiling RTM"); + rtm_abort_ratio_calculation(temp_Reg, rtm_counters, method_data); + } +} + +// Retry on abort if abort's status indicates non-persistent failure. +// inputs: retry_count_Reg +// : abort_status_Reg +// output: retry_count_Reg decremented by 1 +void MacroAssembler::rtm_retry_lock_on_abort(Register retry_count_Reg, Register abort_status_Reg, + Label& retryLabel, Label* checkRetry) { + Label doneRetry; + rldicr_(R0, abort_status_Reg, tm_failure_persistent, 0); + bne(CCR0, doneRetry); + if (checkRetry) { bind(*checkRetry); } + addic_(retry_count_Reg, retry_count_Reg, -1); + blt(CCR0, doneRetry); + smt_yield(); // Can't use wait(). No permission (SIGILL). + b(retryLabel); + bind(doneRetry); +} + +// Spin and retry if lock is busy. +// inputs: box_Reg (monitor address) +// : retry_count_Reg +// output: retry_count_Reg decremented by 1 +// CTR is killed +void MacroAssembler::rtm_retry_lock_on_busy(Register retry_count_Reg, Register owner_addr_Reg, Label& retryLabel) { + Label SpinLoop, doneRetry; + addic_(retry_count_Reg, retry_count_Reg, -1); + blt(CCR0, doneRetry); + li(R0, RTMSpinLoopCount); + mtctr(R0); + + bind(SpinLoop); + smt_yield(); // Can't use waitrsv(). No permission (SIGILL). + bdz(retryLabel); + ld(R0, 0, owner_addr_Reg); + cmpdi(CCR0, R0, 0); + bne(CCR0, SpinLoop); + b(retryLabel); + + bind(doneRetry); +} + +// Use RTM for normal stack locks. +// Input: objReg (object to lock) +void MacroAssembler::rtm_stack_locking(ConditionRegister flag, + Register obj, Register mark_word, Register tmp, + Register retry_on_abort_count_Reg, + RTMLockingCounters* stack_rtm_counters, + Metadata* method_data, bool profile_rtm, + Label& DONE_LABEL, Label& IsInflated) { + assert(UseRTMForStackLocks, "why call this otherwise?"); + assert(!UseBiasedLocking, "Biased locking is not supported with RTM locking"); + Label L_rtm_retry, L_decrement_retry, L_on_abort; + + if (RTMRetryCount > 0) { + load_const_optimized(retry_on_abort_count_Reg, RTMRetryCount); // Retry on abort + bind(L_rtm_retry); + } + andi_(R0, mark_word, markOopDesc::monitor_value); // inflated vs stack-locked|neutral|biased + bne(CCR0, IsInflated); + + if (PrintPreciseRTMLockingStatistics || profile_rtm) { + Label L_noincrement; + if (RTMTotalCountIncrRate > 1) { + branch_on_random_using_tb(tmp, (int)RTMTotalCountIncrRate, L_noincrement); + } + assert(stack_rtm_counters != NULL, "should not be NULL when profiling RTM"); + load_const_optimized(tmp, (address)stack_rtm_counters->total_count_addr(), R0); + //atomic_inc_ptr(tmp, /*temp, will be reloaded*/mark_word); We don't increment atomically + ldx(mark_word, tmp); + addi(mark_word, mark_word, 1); + stdx(mark_word, tmp); + bind(L_noincrement); + } + tbegin_(); + beq(CCR0, L_on_abort); + ld(mark_word, oopDesc::mark_offset_in_bytes(), obj); // Reload in transaction, conflicts need to be tracked. + andi(R0, mark_word, markOopDesc::biased_lock_mask_in_place); // look at 3 lock bits + cmpwi(flag, R0, markOopDesc::unlocked_value); // bits = 001 unlocked + beq(flag, DONE_LABEL); // all done if unlocked + + if (UseRTMXendForLockBusy) { + tend_(); + b(L_decrement_retry); + } else { + tabort_(); + } + bind(L_on_abort); + const Register abort_status_Reg = tmp; + mftexasr(abort_status_Reg); + if (PrintPreciseRTMLockingStatistics || profile_rtm) { + rtm_profiling(abort_status_Reg, /*temp*/mark_word, stack_rtm_counters, method_data, profile_rtm); + } + ld(mark_word, oopDesc::mark_offset_in_bytes(), obj); // reload + if (RTMRetryCount > 0) { + // Retry on lock abort if abort status is not permanent. + rtm_retry_lock_on_abort(retry_on_abort_count_Reg, abort_status_Reg, L_rtm_retry, &L_decrement_retry); + } else { + bind(L_decrement_retry); + } +} + +// Use RTM for inflating locks +// inputs: obj (object to lock) +// mark_word (current header - KILLED) +// boxReg (on-stack box address (displaced header location) - KILLED) +void MacroAssembler::rtm_inflated_locking(ConditionRegister flag, + Register obj, Register mark_word, Register boxReg, + Register retry_on_busy_count_Reg, Register retry_on_abort_count_Reg, + RTMLockingCounters* rtm_counters, + Metadata* method_data, bool profile_rtm, + Label& DONE_LABEL) { + assert(UseRTMLocking, "why call this otherwise?"); + Label L_rtm_retry, L_decrement_retry, L_on_abort; + // Clean monitor_value bit to get valid pointer. + int owner_offset = ObjectMonitor::owner_offset_in_bytes() - markOopDesc::monitor_value; + + // Store non-null, using boxReg instead of (intptr_t)markOopDesc::unused_mark(). + std(boxReg, BasicLock::displaced_header_offset_in_bytes(), boxReg); + const Register tmpReg = boxReg; + const Register owner_addr_Reg = mark_word; + addi(owner_addr_Reg, mark_word, owner_offset); + + if (RTMRetryCount > 0) { + load_const_optimized(retry_on_busy_count_Reg, RTMRetryCount); // Retry on lock busy. + load_const_optimized(retry_on_abort_count_Reg, RTMRetryCount); // Retry on abort. + bind(L_rtm_retry); + } + if (PrintPreciseRTMLockingStatistics || profile_rtm) { + Label L_noincrement; + if (RTMTotalCountIncrRate > 1) { + branch_on_random_using_tb(R0, (int)RTMTotalCountIncrRate, L_noincrement); + } + assert(rtm_counters != NULL, "should not be NULL when profiling RTM"); + load_const(R0, (address)rtm_counters->total_count_addr(), tmpReg); + //atomic_inc_ptr(R0, tmpReg); We don't increment atomically + ldx(tmpReg, R0); + addi(tmpReg, tmpReg, 1); + stdx(tmpReg, R0); + bind(L_noincrement); + } + tbegin_(); + beq(CCR0, L_on_abort); + // We don't reload mark word. Will only be reset at safepoint. + ld(R0, 0, owner_addr_Reg); // Load in transaction, conflicts need to be tracked. + cmpdi(flag, R0, 0); + beq(flag, DONE_LABEL); + + if (UseRTMXendForLockBusy) { + tend_(); + b(L_decrement_retry); + } else { + tabort_(); + } + bind(L_on_abort); + const Register abort_status_Reg = tmpReg; + mftexasr(abort_status_Reg); + if (PrintPreciseRTMLockingStatistics || profile_rtm) { + rtm_profiling(abort_status_Reg, /*temp*/ owner_addr_Reg, rtm_counters, method_data, profile_rtm); + // Restore owner_addr_Reg + ld(mark_word, oopDesc::mark_offset_in_bytes(), obj); +#ifdef ASSERT + andi_(R0, mark_word, markOopDesc::monitor_value); + asm_assert_ne("must be inflated", 0xa754); // Deflating only allowed at safepoint. +#endif + addi(owner_addr_Reg, mark_word, owner_offset); + } + if (RTMRetryCount > 0) { + // Retry on lock abort if abort status is not permanent. + rtm_retry_lock_on_abort(retry_on_abort_count_Reg, abort_status_Reg, L_rtm_retry); + } + + // Appears unlocked - try to swing _owner from null to non-null. + cmpxchgd(flag, /*current val*/ R0, (intptr_t)0, /*new val*/ R16_thread, owner_addr_Reg, + MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, + MacroAssembler::cmpxchgx_hint_acquire_lock(), noreg, &L_decrement_retry, true); + + if (RTMRetryCount > 0) { + // success done else retry + b(DONE_LABEL); + bind(L_decrement_retry); + // Spin and retry if lock is busy. + rtm_retry_lock_on_busy(retry_on_busy_count_Reg, owner_addr_Reg, L_rtm_retry); + } else { + bind(L_decrement_retry); + } +} + +#endif // INCLUDE_RTM_OPT + // "The box" is the space on the stack where we copy the object mark. void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register oop, Register box, - Register temp, Register displaced_header, Register current_header) { + Register temp, Register displaced_header, Register current_header, + bool try_bias, + RTMLockingCounters* rtm_counters, + RTMLockingCounters* stack_rtm_counters, + Metadata* method_data, + bool use_rtm, bool profile_rtm) { assert_different_registers(oop, box, temp, displaced_header, current_header); assert(flag != CCR0, "bad condition register"); Label cont; @@ -2006,10 +2365,18 @@ return; } - if (UseBiasedLocking) { + if (try_bias) { biased_locking_enter(flag, oop, displaced_header, temp, current_header, cont); } +#if INCLUDE_RTM_OPT + if (UseRTMForStackLocks && use_rtm) { + rtm_stack_locking(flag, oop, displaced_header, temp, /*temp*/ current_header, + stack_rtm_counters, method_data, profile_rtm, + cont, object_has_monitor); + } +#endif // INCLUDE_RTM_OPT + // Handle existing monitor. if ((EmitSync & 0x02) == 0) { // The object has an existing monitor iff (mark & monitor_value) != 0. @@ -2066,14 +2433,22 @@ bind(object_has_monitor); // The object's monitor m is unlocked iff m->owner == NULL, // otherwise m->owner may contain a thread or a stack address. - // + +#if INCLUDE_RTM_OPT + // Use the same RTM locking code in 32- and 64-bit VM. + if (use_rtm) { + rtm_inflated_locking(flag, oop, displaced_header, box, temp, /*temp*/ current_header, + rtm_counters, method_data, profile_rtm, cont); + } else { +#endif // INCLUDE_RTM_OPT + // Try to CAS m->owner from NULL to current thread. addi(temp, displaced_header, ObjectMonitor::owner_offset_in_bytes()-markOopDesc::monitor_value); li(displaced_header, 0); // CmpxchgX sets flag to cmpX(current, displaced). cmpxchgd(/*flag=*/flag, /*current_value=*/current_header, - /*compare_value=*/displaced_header, + /*compare_value=*/(intptr_t)0, /*exchange_value=*/R16_thread, /*where=*/temp, MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, @@ -2095,6 +2470,10 @@ //asm_assert_mem4_isnot_zero(ObjectMonitor::OwnerIsThread_offset_in_bytes(), temp, // "monitor->OwnerIsThread shouldn't be 0", -1); # endif + +#if INCLUDE_RTM_OPT + } // use_rtm() +#endif } bind(cont); @@ -2103,7 +2482,8 @@ } void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Register oop, Register box, - Register temp, Register displaced_header, Register current_header) { + Register temp, Register displaced_header, Register current_header, + bool try_bias, bool use_rtm) { assert_different_registers(oop, box, temp, displaced_header, current_header); assert(flag != CCR0, "bad condition register"); Label cont; @@ -2115,10 +2495,24 @@ return; } - if (UseBiasedLocking) { + if (try_bias) { biased_locking_exit(flag, oop, current_header, cont); } +#if INCLUDE_RTM_OPT + if (UseRTMForStackLocks && use_rtm) { + assert(!UseBiasedLocking, "Biased locking is not supported with RTM locking"); + Label L_regular_unlock; + ld(current_header, oopDesc::mark_offset_in_bytes(), oop); // fetch markword + andi(R0, current_header, markOopDesc::biased_lock_mask_in_place); // look at 3 lock bits + cmpwi(flag, R0, markOopDesc::unlocked_value); // bits = 001 unlocked + bne(flag, L_regular_unlock); // else RegularLock + tend_(); // otherwise end... + b(cont); // ... and we're done + bind(L_regular_unlock); + } +#endif + // Find the lock address and load the displaced header from the stack. ld(displaced_header, BasicLock::displaced_header_offset_in_bytes(), box); @@ -2129,13 +2523,12 @@ // Handle existing monitor. if ((EmitSync & 0x02) == 0) { // The object has an existing monitor iff (mark & monitor_value) != 0. + RTM_OPT_ONLY( if (!(UseRTMForStackLocks && use_rtm)) ) // skip load if already done ld(current_header, oopDesc::mark_offset_in_bytes(), oop); - andi(temp, current_header, markOopDesc::monitor_value); - cmpdi(flag, temp, 0); - bne(flag, object_has_monitor); + andi_(R0, current_header, markOopDesc::monitor_value); + bne(CCR0, object_has_monitor); } - // Check if it is still a light weight lock, this is is true if we see // the stack address of the basicLock in the markOop of the object. // Cmpxchg sets flag to cmpd(current_header, box). @@ -2158,6 +2551,20 @@ bind(object_has_monitor); addi(current_header, current_header, -markOopDesc::monitor_value); // monitor ld(temp, ObjectMonitor::owner_offset_in_bytes(), current_header); + + // It's inflated. +#if INCLUDE_RTM_OPT + if (use_rtm) { + Label L_regular_inflated_unlock; + // Clean monitor_value bit to get valid pointer + cmpdi(flag, temp, 0); + bne(flag, L_regular_inflated_unlock); + tend_(); + b(cont); + bind(L_regular_inflated_unlock); + } +#endif + ld(displaced_header, ObjectMonitor::recursions_offset_in_bytes(), current_header); xorr(temp, R16_thread, temp); // Will be 0 if we are the owner. orr(temp, temp, displaced_header); // Will be 0 if there are 0 recursions. @@ -2441,6 +2848,8 @@ // oop_result // R16_thread->in_bytes(JavaThread::vm_result_offset()) + verify_thread(); + ld(oop_result, in_bytes(JavaThread::vm_result_offset()), R16_thread); li(R0, 0); std(R0, in_bytes(JavaThread::vm_result_offset()), R16_thread); @@ -2462,26 +2871,24 @@ std(R0, in_bytes(JavaThread::vm_result_2_offset()), R16_thread); } - -void MacroAssembler::encode_klass_not_null(Register dst, Register src) { +Register MacroAssembler::encode_klass_not_null(Register dst, Register src) { Register current = (src != noreg) ? src : dst; // Klass is in dst if no src provided. if (Universe::narrow_klass_base() != 0) { // Use dst as temp if it is free. - load_const(R0, Universe::narrow_klass_base(), (dst != current && dst != R0) ? dst : noreg); - sub(dst, current, R0); + sub_const_optimized(dst, current, Universe::narrow_klass_base(), R0); current = dst; } if (Universe::narrow_klass_shift() != 0) { srdi(dst, current, Universe::narrow_klass_shift()); current = dst; } - mr_if_needed(dst, current); // Move may be required. + return current; } void MacroAssembler::store_klass(Register dst_oop, Register klass, Register ck) { if (UseCompressedClassPointers) { - encode_klass_not_null(ck, klass); - stw(ck, oopDesc::klass_offset_in_bytes(), dst_oop); + Register compressedKlass = encode_klass_not_null(ck, klass); + stw(compressedKlass, oopDesc::klass_offset_in_bytes(), dst_oop); } else { std(klass, oopDesc::klass_offset_in_bytes(), dst_oop); } @@ -2514,8 +2921,7 @@ sldi(shifted_src, src, Universe::narrow_klass_shift()); } if (Universe::narrow_klass_base() != 0) { - load_const(R0, Universe::narrow_klass_base()); - add(dst, shifted_src, R0); + add_const_optimized(dst, shifted_src, Universe::narrow_klass_base(), R0); } } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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 @@ -27,6 +27,7 @@ #define CPU_PPC_VM_MACROASSEMBLER_PPC_HPP #include "asm/assembler.hpp" +#include "runtime/rtmLocking.hpp" #include "utilities/macros.hpp" // MacroAssembler extends Assembler by a few frequently used macros. @@ -432,8 +433,8 @@ int semantics, bool cmpxchgx_hint = false, Register int_flag_success = noreg, bool contention_hint = false); void cmpxchgd(ConditionRegister flag, - Register dest_current_value, Register compare_value, Register exchange_value, Register addr_base, - int semantics, bool cmpxchgx_hint = false, + Register dest_current_value, RegisterOrConstant compare_value, Register exchange_value, + Register addr_base, int semantics, bool cmpxchgx_hint = false, Register int_flag_success = noreg, Label* failed = NULL, bool contention_hint = false); // interface method calling @@ -506,8 +507,42 @@ // biased locking exit case failed. void biased_locking_exit(ConditionRegister cr_reg, Register mark_addr, Register temp_reg, Label& done); - void compiler_fast_lock_object( ConditionRegister flag, Register oop, Register box, Register tmp1, Register tmp2, Register tmp3); - void compiler_fast_unlock_object(ConditionRegister flag, Register oop, Register box, Register tmp1, Register tmp2, Register tmp3); + void atomic_inc_ptr(Register addr, Register result, int simm16 = 1); + void atomic_ori_int(Register addr, Register result, int uimm16); + +#if INCLUDE_RTM_OPT + void rtm_counters_update(Register abort_status, Register rtm_counters); + void branch_on_random_using_tb(Register tmp, int count, Label& brLabel); + void rtm_abort_ratio_calculation(Register rtm_counters_reg, RTMLockingCounters* rtm_counters, + Metadata* method_data); + void rtm_profiling(Register abort_status_Reg, Register temp_Reg, + RTMLockingCounters* rtm_counters, Metadata* method_data, bool profile_rtm); + void rtm_retry_lock_on_abort(Register retry_count, Register abort_status, + Label& retryLabel, Label* checkRetry = NULL); + void rtm_retry_lock_on_busy(Register retry_count, Register owner_addr, Label& retryLabel); + void rtm_stack_locking(ConditionRegister flag, Register obj, Register mark_word, Register tmp, + Register retry_on_abort_count, + RTMLockingCounters* stack_rtm_counters, + Metadata* method_data, bool profile_rtm, + Label& DONE_LABEL, Label& IsInflated); + void rtm_inflated_locking(ConditionRegister flag, Register obj, Register mark_word, Register box, + Register retry_on_busy_count, Register retry_on_abort_count, + RTMLockingCounters* rtm_counters, + Metadata* method_data, bool profile_rtm, + Label& DONE_LABEL); +#endif + + void compiler_fast_lock_object(ConditionRegister flag, Register oop, Register box, + Register tmp1, Register tmp2, Register tmp3, + bool try_bias = UseBiasedLocking, + RTMLockingCounters* rtm_counters = NULL, + RTMLockingCounters* stack_rtm_counters = NULL, + Metadata* method_data = NULL, + bool use_rtm = false, bool profile_rtm = false); + + void compiler_fast_unlock_object(ConditionRegister flag, Register oop, Register box, + Register tmp1, Register tmp2, Register tmp3, + bool try_bias = UseBiasedLocking, bool use_rtm = false); // Support for serializing memory accesses between threads void serialize_memory(Register thread, Register tmp1, Register tmp2); @@ -576,7 +611,7 @@ Register tmp = noreg); // Null allowed. - inline void load_heap_oop(Register d, RegisterOrConstant offs, Register s1 = noreg); + inline void load_heap_oop(Register d, RegisterOrConstant offs, Register s1 = noreg, Label *is_null = NULL); // Encode/decode heap oop. Oop may not be null, else en/decoding goes wrong. // src == d allowed. @@ -593,7 +628,7 @@ void store_klass_gap(Register dst_oop, Register val = noreg); // Will store 0 if val not specified. static int instr_size_for_decode_klass_not_null(); void decode_klass_not_null(Register dst, Register src = noreg); - void encode_klass_not_null(Register dst, Register src = noreg); + Register encode_klass_not_null(Register dst, Register src = noreg); // Load common heap base into register. void reinit_heapbase(Register d, Register tmp = noreg); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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 @@ -333,19 +333,29 @@ } } -inline void MacroAssembler::load_heap_oop(Register d, RegisterOrConstant offs, Register s1) { +inline void MacroAssembler::load_heap_oop(Register d, RegisterOrConstant offs, Register s1, Label *is_null) { if (UseCompressedOops) { lwz(d, offs, s1); - decode_heap_oop(d); + if (is_null != NULL) { + cmpwi(CCR0, d, 0); + beq(CCR0, *is_null); + decode_heap_oop_not_null(d); + } else { + decode_heap_oop(d); + } } else { ld(d, offs, s1); + if (is_null != NULL) { + cmpdi(CCR0, d, 0); + beq(CCR0, *is_null); + } } } inline Register MacroAssembler::encode_heap_oop_not_null(Register d, Register src) { Register current = (src != noreg) ? src : d; // Oop to be compressed is in d if no src provided. if (Universe::narrow_oop_base_overlaps()) { - sub(d, current, R30); + sub_const_optimized(d, current, Universe::narrow_oop_base(), R0); current = d; } if (Universe::narrow_oop_shift() != 0) { @@ -358,7 +368,7 @@ inline Register MacroAssembler::decode_heap_oop_not_null(Register d, Register src) { if (Universe::narrow_oop_base_disjoint() && src != noreg && src != d && Universe::narrow_oop_shift() != 0) { - mr(d, R30); + load_const_optimized(d, Universe::narrow_oop_base(), R0); rldimi(d, src, Universe::narrow_oop_shift(), 32-Universe::narrow_oop_shift()); return d; } @@ -369,7 +379,7 @@ current = d; } if (Universe::narrow_oop_base() != NULL) { - add(d, current, R30); + add_const_optimized(d, current, Universe::narrow_oop_base(), R0); current = d; } return current; // Decoded oop is in this register. @@ -377,11 +387,19 @@ inline void MacroAssembler::decode_heap_oop(Register d) { Label isNull; + bool use_isel = false; if (Universe::narrow_oop_base() != NULL) { cmpwi(CCR0, d, 0); - beq(CCR0, isNull); + if (VM_Version::has_isel()) { + use_isel = true; + } else { + beq(CCR0, isNull); + } } decode_heap_oop_not_null(d); + if (use_isel) { + isel_0(d, CCR0, Assembler::equal); + } bind(isNull); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp Thu May 07 20:51:12 2015 -0700 @@ -466,7 +466,7 @@ strstr(adaptername, "linkTo") == NULL); // static linkers don't have MH const char* mh_reg_name = has_mh ? "R23_method_handle" : "G23"; tty->print_cr("MH %s %s="INTPTR_FORMAT " sp=" INTPTR_FORMAT, - adaptername, mh_reg_name, (intptr_t) mh, entry_sp); + adaptername, mh_reg_name, p2i(mh), p2i(entry_sp)); if (Verbose) { tty->print_cr("Registers:"); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/methodHandles_ppc.hpp --- a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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 @@ -27,9 +27,6 @@ // These definitions are inlined into class MethodHandles. // Adapters -//static unsigned int adapter_code_size() { -// return 32*K DEBUG_ONLY(+ 16*K) + (TraceMethodHandles ? 16*K : 0) + (VerifyMethodHandles ? 32*K : 0); -//} enum /* platform_dependent_constants */ { adapter_code_size = NOT_LP64(16000 DEBUG_ONLY(+ 25000)) LP64_ONLY(32000 DEBUG_ONLY(+ 150000)) }; @@ -45,7 +42,9 @@ static void verify_method_handle(MacroAssembler* _masm, Register mh_reg, Register temp_reg, Register temp2_reg) { - Unimplemented(); + verify_klass(_masm, mh_reg, SystemDictionary::WK_KLASS_ENUM_NAME(java_lang_invoke_MethodHandle), + temp_reg, temp2_reg, + "reference is a MH"); } static void verify_ref_kind(MacroAssembler* _masm, int ref_kind, Register member_reg, Register temp) NOT_DEBUG_RETURN; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/ppc.ad --- a/hotspot/src/cpu/ppc/vm/ppc.ad Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/ppc.ad Thu May 07 20:51:12 2015 -0700 @@ -447,8 +447,8 @@ R26, R27, R28, -/*R29*/ // global TOC -/*R30*/ // Narrow Oop Base +/*R29,*/ // global TOC + R30, R31 ); @@ -484,58 +484,11 @@ R26, R27, R28, -/*R29*/ -/*R30*/ // Narrow Oop Base +/*R29,*/ + R30, R31 ); -// Complement-required-in-pipeline operands for narrow oops. -reg_class bits32_reg_ro_not_complement ( -/*R0*/ // R0 - R1, // SP - R2, // TOC - R3, - R4, - R5, - R6, - R7, - R8, - R9, - R10, - R11, - R12, -/*R13,*/ // system thread id - R14, - R15, - R16, // R16_thread - R17, - R18, - R19, - R20, - R21, - R22, -/*R23, - R24, - R25, - R26, - R27, - R28,*/ -/*R29,*/ // TODO: let allocator handle TOC!! -/*R30,*/ - R31 -); - -// Complement-required-in-pipeline operands for narrow oops. -// See 64-bit declaration. -reg_class bits32_reg_ro_complement ( - R23, - R24, - R25, - R26, - R27, - R28 -); - reg_class rscratch1_bits32_reg(R11); reg_class rscratch2_bits32_reg(R12); reg_class rarg1_bits32_reg(R3); @@ -591,8 +544,8 @@ R26_H, R26, R27_H, R27, R28_H, R28, -/*R29_H, R29*/ -/*R30_H, R30*/ +/*R29_H, R29,*/ + R30_H, R30, R31_H, R31 ); @@ -629,8 +582,8 @@ R26_H, R26, R27_H, R27, R28_H, R28, -/*R29_H, R29*/ -/*R30_H, R30*/ +/*R29_H, R29,*/ + R30_H, R30, R31_H, R31 ); @@ -667,8 +620,8 @@ R26_H, R26, R27_H, R27, R28_H, R28, -/*R29_H, R29*/ -/*R30_H, R30*/ +/*R29_H, R29,*/ + R30_H, R30, R31_H, R31 ); @@ -704,64 +657,11 @@ R26_H, R26, R27_H, R27, R28_H, R28, -/*R29_H, R29*/ // TODO: let allocator handle TOC!! -/*R30_H, R30,*/ +/*R29_H, R29,*/ // TODO: let allocator handle TOC!! + R30_H, R30, R31_H, R31 ); -// Complement-required-in-pipeline operands. -reg_class bits64_reg_ro_not_complement ( -/*R0_H, R0*/ // R0 - R1_H, R1, // SP - R2_H, R2, // TOC - R3_H, R3, - R4_H, R4, - R5_H, R5, - R6_H, R6, - R7_H, R7, - R8_H, R8, - R9_H, R9, - R10_H, R10, - R11_H, R11, - R12_H, R12, -/*R13_H, R13*/ // system thread id - R14_H, R14, - R15_H, R15, - R16_H, R16, // R16_thread - R17_H, R17, - R18_H, R18, - R19_H, R19, - R20_H, R20, - R21_H, R21, - R22_H, R22, -/*R23_H, R23, - R24_H, R24, - R25_H, R25, - R26_H, R26, - R27_H, R27, - R28_H, R28,*/ -/*R29_H, R29*/ // TODO: let allocator handle TOC!! -/*R30_H, R30,*/ - R31_H, R31 -); - -// Complement-required-in-pipeline operands. -// This register mask is used for the trap instructions that implement -// the null checks on AIX. The trap instruction first computes the -// complement of the value it shall trap on. Because of this, the -// instruction can not be scheduled in the same cycle as an other -// instruction reading the normal value of the same register. So we -// force the value to check into 'bits64_reg_ro_not_complement' -// and then copy it to 'bits64_reg_ro_complement' for the trap. -reg_class bits64_reg_ro_complement ( - R23_H, R23, - R24_H, R24, - R25_H, R25, - R26_H, R26, - R27_H, R27, - R28_H, R28 -); - // ---------------------------- // Special Class for Condition Code Flags Register @@ -777,6 +677,17 @@ CCR7 ); +reg_class int_flags_ro( + CCR0, + CCR1, + CCR2, + CCR3, + CCR4, + CCR5, + CCR6, + CCR7 +); + reg_class int_flags_CR0(CCR0); reg_class int_flags_CR1(CCR1); reg_class int_flags_CR6(CCR6); @@ -2876,7 +2787,7 @@ // Use release_store for card-marking to ensure that previous // oop-stores are visible before the card-mark change. - enc_class enc_cms_card_mark(memory mem, iRegLdst releaseFieldAddr) %{ + enc_class enc_cms_card_mark(memory mem, iRegLdst releaseFieldAddr, flagsReg crx) %{ // TODO: PPC port $archOpcode(ppc64Opcode_compound); // FIXME: Implement this as a cmove and use a fixed condition code // register which is written on every transition to compiled code, @@ -2897,8 +2808,8 @@ // Check CMSCollectorCardTableModRefBSExt::_requires_release and do the // StoreStore barrier conditionally. __ lwz(R0, 0, $releaseFieldAddr$$Register); - __ cmpwi(CCR0, R0, 0); - __ beq_predict_taken(CCR0, skip_storestore); + __ cmpwi($crx$$CondRegister, R0, 0); + __ beq_predict_taken($crx$$CondRegister, skip_storestore); #endif __ li(R0, 0); __ membar(Assembler::StoreStore); @@ -3108,7 +3019,7 @@ nodes->push(n2); %} - enc_class enc_cmove_reg(iRegIdst dst, flagsReg crx, iRegIsrc src, cmpOp cmp) %{ + enc_class enc_cmove_reg(iRegIdst dst, flagsRegSrc crx, iRegIsrc src, cmpOp cmp) %{ // TODO: PPC port $archOpcode(ppc64Opcode_cmove); MacroAssembler _masm(&cbuf); @@ -3123,7 +3034,7 @@ __ bind(done); %} - enc_class enc_cmove_imm(iRegIdst dst, flagsReg crx, immI16 src, cmpOp cmp) %{ + enc_class enc_cmove_imm(iRegIdst dst, flagsRegSrc crx, immI16 src, cmpOp cmp) %{ // TODO: PPC port $archOpcode(ppc64Opcode_cmove); MacroAssembler _masm(&cbuf); @@ -3269,7 +3180,7 @@ __ bind(done); %} - enc_class enc_cmove_bso_stackSlotL(iRegLdst dst, flagsReg crx, stackSlotL mem ) %{ + enc_class enc_cmove_bso_stackSlotL(iRegLdst dst, flagsRegSrc crx, stackSlotL mem ) %{ // TODO: PPC port $archOpcode(ppc64Opcode_cmove); MacroAssembler _masm(&cbuf); @@ -3281,7 +3192,7 @@ __ bind(done); %} - enc_class enc_bc(flagsReg crx, cmpOp cmp, Label lbl) %{ + enc_class enc_bc(flagsRegSrc crx, cmpOp cmp, Label lbl) %{ // TODO: PPC port $archOpcode(ppc64Opcode_bc); MacroAssembler _masm(&cbuf); @@ -3309,7 +3220,7 @@ l); %} - enc_class enc_bc_far(flagsReg crx, cmpOp cmp, Label lbl) %{ + enc_class enc_bc_far(flagsRegSrc crx, cmpOp cmp, Label lbl) %{ // The scheduler doesn't know about branch shortening, so we set the opcode // to ppc64Opcode_bc in order to hide this detail from the scheduler. // TODO: PPC port $archOpcode(ppc64Opcode_bc); @@ -3341,7 +3252,7 @@ %} // Branch used with Power6 scheduling (can be shortened without changing the node). - enc_class enc_bc_short_far(flagsReg crx, cmpOp cmp, Label lbl) %{ + enc_class enc_bc_short_far(flagsRegSrc crx, cmpOp cmp, Label lbl) %{ // The scheduler doesn't know about branch shortening, so we set the opcode // to ppc64Opcode_bc in order to hide this detail from the scheduler. // TODO: PPC port $archOpcode(ppc64Opcode_bc); @@ -4700,6 +4611,15 @@ interface(REG_INTER); %} +operand flagsRegSrc() %{ + constraint(ALLOC_IN_RC(int_flags_ro)); + match(RegFlags); + match(flagsReg); + match(flagsRegCR0); + format %{ %} + interface(REG_INTER); +%} + // Condition Code Flag Register CR0 operand flagsRegCR0() %{ constraint(ALLOC_IN_RC(int_flags_CR0)); @@ -4783,6 +4703,13 @@ predicate(false /* TODO: PPC port MatchDecodeNodes*/); constraint(ALLOC_IN_RC(bits32_reg_ro)); match(DecodeN reg); + format %{ "$reg" %} + interface(REG_INTER) +%} + +operand iRegN2P_klass(iRegNsrc reg) %{ + predicate(Universe::narrow_klass_base() == NULL && Universe::narrow_klass_shift() == 0); + constraint(ALLOC_IN_RC(bits32_reg_ro)); match(DecodeNKlass reg); format %{ "$reg" %} interface(REG_INTER) @@ -4839,6 +4766,19 @@ predicate(false /* TODO: PPC port MatchDecodeNodes*/); constraint(ALLOC_IN_RC(bits64_reg_ro)); match(DecodeN reg); + op_cost(100); + format %{ "[$reg]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0x0); + scale(0x0); + disp(0x0); + %} +%} + +operand indirectNarrow_klass(iRegNsrc reg) %{ + predicate(Universe::narrow_klass_base() == NULL && Universe::narrow_klass_shift() == 0); + constraint(ALLOC_IN_RC(bits64_reg_ro)); match(DecodeNKlass reg); op_cost(100); format %{ "[$reg]" %} @@ -4855,6 +4795,19 @@ predicate(false /* TODO: PPC port MatchDecodeNodes*/); constraint(ALLOC_IN_RC(bits64_reg_ro)); match(AddP (DecodeN reg) offset); + op_cost(100); + format %{ "[$reg + $offset]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0x0); + scale(0x0); + disp($offset); + %} +%} + +operand indOffset16Narrow_klass(iRegNsrc reg, immL16 offset) %{ + predicate(Universe::narrow_klass_base() == NULL && Universe::narrow_klass_shift() == 0); + constraint(ALLOC_IN_RC(bits64_reg_ro)); match(AddP (DecodeNKlass reg) offset); op_cost(100); format %{ "[$reg + $offset]" %} @@ -4871,6 +4824,19 @@ predicate(false /* TODO: PPC port MatchDecodeNodes*/); constraint(ALLOC_IN_RC(bits64_reg_ro)); match(AddP (DecodeN reg) offset); + op_cost(100); + format %{ "[$reg + $offset]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0x0); + scale(0x0); + disp($offset); + %} +%} + +operand indOffset16NarrowAlg4_klass(iRegNsrc reg, immL16Alg4 offset) %{ + predicate(Universe::narrow_klass_base() == NULL && Universe::narrow_klass_shift() == 0); + constraint(ALLOC_IN_RC(bits64_reg_ro)); match(AddP (DecodeNKlass reg) offset); op_cost(100); format %{ "[$reg + $offset]" %} @@ -4998,9 +4964,9 @@ // encoding and format. The classic case of this is memory operands. // Indirect is not included since its use is limited to Compare & Swap. -opclass memory(indirect, indOffset16 /*, indIndex, tlsReference*/, indirectNarrow, indOffset16Narrow); +opclass memory(indirect, indOffset16 /*, indIndex, tlsReference*/, indirectNarrow, indirectNarrow_klass, indOffset16Narrow, indOffset16Narrow_klass); // Memory operand where offsets are 4-aligned. Required for ld, std. -opclass memoryAlg4(indirect, indOffset16Alg4, indirectNarrow, indOffset16NarrowAlg4); +opclass memoryAlg4(indirect, indOffset16Alg4, indirectNarrow, indOffset16NarrowAlg4, indOffset16NarrowAlg4_klass); opclass indirectMemory(indirect, indirectNarrow); // Special opclass for I and ConvL2I. @@ -5009,7 +4975,7 @@ // Operand classes to match encode and decode. iRegN_P2N is only used // for storeN. I have never seen an encode node elsewhere. opclass iRegN_P2N(iRegNsrc, iRegP2N); -opclass iRegP_N2P(iRegPsrc, iRegN2P); +opclass iRegP_N2P(iRegPsrc, iRegN2P, iRegN2P_klass); //----------PIPELINE----------------------------------------------------------- @@ -5593,6 +5559,19 @@ ins_pipe(pipe_class_memory); %} +instruct loadN2P_klass_unscaled(iRegPdst dst, memory mem) %{ + match(Set dst (DecodeNKlass (LoadNKlass mem))); + // SAPJVM GL 2014-05-21 Differs. + predicate(Universe::narrow_klass_base() == NULL && Universe::narrow_klass_shift() == 0 && + _kids[0]->_leaf->as_Load()->is_unordered()); + ins_cost(MEMORY_REF_COST); + + format %{ "LWZ $dst, $mem \t// DecodeN (unscaled)" %} + size(4); + ins_encode( enc_lwz(dst, mem) ); + ins_pipe(pipe_class_memory); +%} + // Load Pointer instruct loadP(iRegPdst dst, memoryAlg4 mem) %{ match(Set dst (LoadP mem)); @@ -5669,8 +5648,9 @@ %} // Load Float acquire. -instruct loadF_ac(regF dst, memory mem) %{ +instruct loadF_ac(regF dst, memory mem, flagsRegCR0 cr0) %{ match(Set dst (LoadF mem)); + effect(TEMP cr0); ins_cost(3*MEMORY_REF_COST); format %{ "LFS $dst, $mem \t// acquire\n\t" @@ -5705,8 +5685,9 @@ %} // Load Double - aligned acquire. -instruct loadD_ac(regD dst, memory mem) %{ +instruct loadD_ac(regD dst, memory mem, flagsRegCR0 cr0) %{ match(Set dst (LoadD mem)); + effect(TEMP cr0); ins_cost(3*MEMORY_REF_COST); format %{ "LFD $dst, $mem \t// acquire\n\t" @@ -6034,11 +6015,10 @@ instruct loadBase(iRegLdst dst) %{ effect(DEF dst); - format %{ "MR $dst, r30_heapbase" %} - size(4); - ins_encode %{ - // TODO: PPC port $archOpcode(ppc64Opcode_or); - __ mr($dst$$Register, R30); + format %{ "LoadConst $dst, heapbase" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ load_const_optimized($dst$$Register, Universe::narrow_oop_base(), R0); %} ins_pipe(pipe_class_default); %} @@ -6114,7 +6094,7 @@ effect(TEMP src2); ins_cost(DEFAULT_COST); - format %{ "ORI $dst, $src1, $src2 \t// narrow klass lo" %} + format %{ "ORI $dst, $src1, $src2 \t// narrow klass lo" %} size(4); ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_ori); @@ -6563,8 +6543,9 @@ // do a releasing store. For this, it gets the address of // CMSCollectorCardTableModRefBSExt::_requires_release as input. // (Using releaseFieldAddr in the match rule is a hack.) -instruct storeCM_CMS(memory mem, iRegLdst releaseFieldAddr) %{ +instruct storeCM_CMS(memory mem, iRegLdst releaseFieldAddr, flagsReg crx) %{ match(Set mem (StoreCM mem releaseFieldAddr)); + effect(TEMP crx); predicate(false); ins_cost(MEMORY_REF_COST); @@ -6572,7 +6553,7 @@ ins_cannot_rematerialize(true); format %{ "STB #0, $mem \t// CMS card-mark byte (must be 0!), checking requires_release in [$releaseFieldAddr]" %} - ins_encode( enc_cms_card_mark(mem, releaseFieldAddr) ); + ins_encode( enc_cms_card_mark(mem, releaseFieldAddr, crx) ); ins_pipe(pipe_class_memory); %} @@ -6589,8 +6570,9 @@ expand %{ immL baseImm %{ 0 /* TODO: PPC port (jlong)CMSCollectorCardTableModRefBSExt::requires_release_address() */ %} iRegLdst releaseFieldAddress; + flagsReg crx; loadConL_Ex(releaseFieldAddress, baseImm); - storeCM_CMS(mem, releaseFieldAddress); + storeCM_CMS(mem, releaseFieldAddress, crx); %} %} @@ -6639,39 +6621,34 @@ predicate(false); format %{ "SUB $dst, $src, oop_base \t// encode" %} - size(4); - ins_encode %{ - // TODO: PPC port $archOpcode(ppc64Opcode_subf); - __ subf($dst$$Register, R30, $src$$Register); + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ sub_const_optimized($dst$$Register, $src$$Register, Universe::narrow_oop_base(), R0); %} ins_pipe(pipe_class_default); %} // Conditional sub base. -instruct cond_sub_base(iRegNdst dst, flagsReg crx, iRegPsrc src1) %{ +instruct cond_sub_base(iRegNdst dst, flagsRegSrc crx, iRegPsrc src1) %{ // The match rule is needed to make it a 'MachTypeNode'! match(Set dst (EncodeP (Binary crx src1))); predicate(false); - ins_variable_size_depending_on_alignment(true); - format %{ "BEQ $crx, done\n\t" - "SUB $dst, $src1, R30 \t// encode: subtract base if != NULL\n" + "SUB $dst, $src1, heapbase \t// encode: subtract base if != NULL\n" "done:" %} - size(false /* TODO: PPC PORT (InsertEndGroupPPC64 && Compile::current()->do_hb_scheduling())*/ ? 12 : 8); - ins_encode %{ - // TODO: PPC port $archOpcode(ppc64Opcode_cmove); + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); Label done; __ beq($crx$$CondRegister, done); - __ subf($dst$$Register, R30, $src1$$Register); - // TODO PPC port __ endgroup_if_needed(_size == 12); + __ sub_const_optimized($dst$$Register, $src1$$Register, Universe::narrow_oop_base(), R0); __ bind(done); %} ins_pipe(pipe_class_default); %} // Power 7 can use isel instruction -instruct cond_set_0_oop(iRegNdst dst, flagsReg crx, iRegPsrc src1) %{ +instruct cond_set_0_oop(iRegNdst dst, flagsRegSrc crx, iRegPsrc src1) %{ // The match rule is needed to make it a 'MachTypeNode'! match(Set dst (EncodeP (Binary crx src1))); predicate(false); @@ -6777,42 +6754,37 @@ match(Set dst (DecodeN src)); predicate(false); - format %{ "ADD $dst, $src, R30 \t// DecodeN, add oop base" %} - size(4); - ins_encode %{ - // TODO: PPC port $archOpcode(ppc64Opcode_add); - __ add($dst$$Register, $src$$Register, R30); + format %{ "ADD $dst, $src, heapbase \t// DecodeN, add oop base" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ add_const_optimized($dst$$Register, $src$$Register, Universe::narrow_oop_base(), R0); %} ins_pipe(pipe_class_default); %} // conditianal add base for expand -instruct cond_add_base(iRegPdst dst, flagsReg crx, iRegPsrc src1) %{ +instruct cond_add_base(iRegPdst dst, flagsRegSrc crx, iRegPsrc src) %{ // The match rule is needed to make it a 'MachTypeNode'! // NOTICE that the rule is nonsense - we just have to make sure that: // - _matrule->_rChild->_opType == "DecodeN" (see InstructForm::captures_bottom_type() in formssel.cpp) // - we have to match 'crx' to avoid an "illegal USE of non-input: flagsReg crx" error in ADLC. - match(Set dst (DecodeN (Binary crx src1))); + match(Set dst (DecodeN (Binary crx src))); predicate(false); - ins_variable_size_depending_on_alignment(true); - format %{ "BEQ $crx, done\n\t" - "ADD $dst, $src1, R30 \t// DecodeN: add oop base if $src1 != NULL\n" + "ADD $dst, $src, heapbase \t// DecodeN: add oop base if $src != NULL\n" "done:" %} - size(false /* TODO: PPC PORT (InsertEndGroupPPC64 && Compile::current()->do_hb_scheduling()) */? 12 : 8); - ins_encode %{ - // TODO: PPC port $archOpcode(ppc64Opcode_cmove); + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); Label done; __ beq($crx$$CondRegister, done); - __ add($dst$$Register, $src1$$Register, R30); - // TODO PPC port __ endgroup_if_needed(_size == 12); + __ add_const_optimized($dst$$Register, $src$$Register, Universe::narrow_oop_base(), R0); __ bind(done); %} ins_pipe(pipe_class_default); %} -instruct cond_set_0_ptr(iRegPdst dst, flagsReg crx, iRegPsrc src1) %{ +instruct cond_set_0_ptr(iRegPdst dst, flagsRegSrc crx, iRegPsrc src1) %{ // The match rule is needed to make it a 'MachTypeNode'! // NOTICE that the rule is nonsense - we just have to make sure that: // - _matrule->_rChild->_opType == "DecodeN" (see InstructForm::captures_bottom_type() in formssel.cpp) @@ -6888,7 +6860,7 @@ Universe::narrow_oop_base_disjoint()); ins_cost(DEFAULT_COST); - format %{ "MOV $dst, R30 \t\n" + format %{ "MOV $dst, heapbase \t\n" "RLDIMI $dst, $src, shift, 32-shift \t// decode with disjoint base" %} postalloc_expand %{ loadBaseNode *n1 = new loadBaseNode(); @@ -6946,7 +6918,7 @@ assert(ra_->is_oop(this) == true, "A decodeN node must produce an oop!"); ra_->set_oop(n_cond_set, true); - + ra_->set_pair(n1->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); ra_->set_pair(n_compare->_idx, ra_->get_reg_second(n_crx), ra_->get_reg_first(n_crx)); ra_->set_pair(n2->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); @@ -7303,7 +7275,7 @@ //----------Conditional Move--------------------------------------------------- // Cmove using isel. -instruct cmovI_reg_isel(cmpOp cmp, flagsReg crx, iRegIdst dst, iRegIsrc src) %{ +instruct cmovI_reg_isel(cmpOp cmp, flagsRegSrc crx, iRegIdst dst, iRegIsrc src) %{ match(Set dst (CMoveI (Binary cmp crx) (Binary dst src))); predicate(VM_Version::has_isel()); ins_cost(DEFAULT_COST); @@ -7321,7 +7293,7 @@ ins_pipe(pipe_class_default); %} -instruct cmovI_reg(cmpOp cmp, flagsReg crx, iRegIdst dst, iRegIsrc src) %{ +instruct cmovI_reg(cmpOp cmp, flagsRegSrc crx, iRegIdst dst, iRegIsrc src) %{ match(Set dst (CMoveI (Binary cmp crx) (Binary dst src))); predicate(!VM_Version::has_isel()); ins_cost(DEFAULT_COST+BRANCH_COST); @@ -7335,7 +7307,7 @@ ins_pipe(pipe_class_default); %} -instruct cmovI_imm(cmpOp cmp, flagsReg crx, iRegIdst dst, immI16 src) %{ +instruct cmovI_imm(cmpOp cmp, flagsRegSrc crx, iRegIdst dst, immI16 src) %{ match(Set dst (CMoveI (Binary cmp crx) (Binary dst src))); ins_cost(DEFAULT_COST+BRANCH_COST); @@ -7349,7 +7321,7 @@ %} // Cmove using isel. -instruct cmovL_reg_isel(cmpOp cmp, flagsReg crx, iRegLdst dst, iRegLsrc src) %{ +instruct cmovL_reg_isel(cmpOp cmp, flagsRegSrc crx, iRegLdst dst, iRegLsrc src) %{ match(Set dst (CMoveL (Binary cmp crx) (Binary dst src))); predicate(VM_Version::has_isel()); ins_cost(DEFAULT_COST); @@ -7367,7 +7339,7 @@ ins_pipe(pipe_class_default); %} -instruct cmovL_reg(cmpOp cmp, flagsReg crx, iRegLdst dst, iRegLsrc src) %{ +instruct cmovL_reg(cmpOp cmp, flagsRegSrc crx, iRegLdst dst, iRegLsrc src) %{ match(Set dst (CMoveL (Binary cmp crx) (Binary dst src))); predicate(!VM_Version::has_isel()); ins_cost(DEFAULT_COST+BRANCH_COST); @@ -7381,7 +7353,7 @@ ins_pipe(pipe_class_default); %} -instruct cmovL_imm(cmpOp cmp, flagsReg crx, iRegLdst dst, immL16 src) %{ +instruct cmovL_imm(cmpOp cmp, flagsRegSrc crx, iRegLdst dst, immL16 src) %{ match(Set dst (CMoveL (Binary cmp crx) (Binary dst src))); ins_cost(DEFAULT_COST+BRANCH_COST); @@ -7395,7 +7367,7 @@ %} // Cmove using isel. -instruct cmovN_reg_isel(cmpOp cmp, flagsReg crx, iRegNdst dst, iRegNsrc src) %{ +instruct cmovN_reg_isel(cmpOp cmp, flagsRegSrc crx, iRegNdst dst, iRegNsrc src) %{ match(Set dst (CMoveN (Binary cmp crx) (Binary dst src))); predicate(VM_Version::has_isel()); ins_cost(DEFAULT_COST); @@ -7414,7 +7386,7 @@ %} // Conditional move for RegN. Only cmov(reg, reg). -instruct cmovN_reg(cmpOp cmp, flagsReg crx, iRegNdst dst, iRegNsrc src) %{ +instruct cmovN_reg(cmpOp cmp, flagsRegSrc crx, iRegNdst dst, iRegNsrc src) %{ match(Set dst (CMoveN (Binary cmp crx) (Binary dst src))); predicate(!VM_Version::has_isel()); ins_cost(DEFAULT_COST+BRANCH_COST); @@ -7428,7 +7400,7 @@ ins_pipe(pipe_class_default); %} -instruct cmovN_imm(cmpOp cmp, flagsReg crx, iRegNdst dst, immN_0 src) %{ +instruct cmovN_imm(cmpOp cmp, flagsRegSrc crx, iRegNdst dst, immN_0 src) %{ match(Set dst (CMoveN (Binary cmp crx) (Binary dst src))); ins_cost(DEFAULT_COST+BRANCH_COST); @@ -7442,7 +7414,7 @@ %} // Cmove using isel. -instruct cmovP_reg_isel(cmpOp cmp, flagsReg crx, iRegPdst dst, iRegPsrc src) %{ +instruct cmovP_reg_isel(cmpOp cmp, flagsRegSrc crx, iRegPdst dst, iRegPsrc src) %{ match(Set dst (CMoveP (Binary cmp crx) (Binary dst src))); predicate(VM_Version::has_isel()); ins_cost(DEFAULT_COST); @@ -7460,7 +7432,7 @@ ins_pipe(pipe_class_default); %} -instruct cmovP_reg(cmpOp cmp, flagsReg crx, iRegPdst dst, iRegP_N2P src) %{ +instruct cmovP_reg(cmpOp cmp, flagsRegSrc crx, iRegPdst dst, iRegP_N2P src) %{ match(Set dst (CMoveP (Binary cmp crx) (Binary dst src))); predicate(!VM_Version::has_isel()); ins_cost(DEFAULT_COST+BRANCH_COST); @@ -7474,7 +7446,7 @@ ins_pipe(pipe_class_default); %} -instruct cmovP_imm(cmpOp cmp, flagsReg crx, iRegPdst dst, immP_0 src) %{ +instruct cmovP_imm(cmpOp cmp, flagsRegSrc crx, iRegPdst dst, immP_0 src) %{ match(Set dst (CMoveP (Binary cmp crx) (Binary dst src))); ins_cost(DEFAULT_COST+BRANCH_COST); @@ -7487,7 +7459,7 @@ ins_pipe(pipe_class_default); %} -instruct cmovF_reg(cmpOp cmp, flagsReg crx, regF dst, regF src) %{ +instruct cmovF_reg(cmpOp cmp, flagsRegSrc crx, regF dst, regF src) %{ match(Set dst (CMoveF (Binary cmp crx) (Binary dst src))); ins_cost(DEFAULT_COST+BRANCH_COST); @@ -7509,7 +7481,7 @@ ins_pipe(pipe_class_default); %} -instruct cmovD_reg(cmpOp cmp, flagsReg crx, regD dst, regD src) %{ +instruct cmovD_reg(cmpOp cmp, flagsRegSrc crx, regD dst, regD src) %{ match(Set dst (CMoveD (Binary cmp crx) (Binary dst src))); ins_cost(DEFAULT_COST+BRANCH_COST); @@ -7542,8 +7514,9 @@ // Mem_ptr must be a memory operand, else this node does not get // Flag_needs_anti_dependence_check set by adlc. If this is not set this node // can be rematerialized which leads to errors. -instruct storeLConditional_regP_regL_regL(flagsReg crx, indirect mem_ptr, iRegLsrc oldVal, iRegLsrc newVal) %{ +instruct storeLConditional_regP_regL_regL(flagsReg crx, indirect mem_ptr, iRegLsrc oldVal, iRegLsrc newVal, flagsRegCR0 cr0) %{ match(Set crx (StoreLConditional mem_ptr (Binary oldVal newVal))); + effect(TEMP cr0); format %{ "CMPXCHGD if ($crx = ($oldVal == *$mem_ptr)) *mem_ptr = $newVal; as bool" %} ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_compound); @@ -7560,16 +7533,16 @@ // Mem_ptr must be a memory operand, else this node does not get // Flag_needs_anti_dependence_check set by adlc. If this is not set this node // can be rematerialized which leads to errors. -instruct storePConditional_regP_regP_regP(flagsReg crx, indirect mem_ptr, iRegPsrc oldVal, iRegPsrc newVal) %{ - match(Set crx (StorePConditional mem_ptr (Binary oldVal newVal))); - format %{ "CMPXCHGD if ($crx = ($oldVal == *$mem_ptr)) *mem_ptr = $newVal; as bool" %} - ins_encode %{ - // TODO: PPC port $archOpcode(ppc64Opcode_compound); - __ cmpxchgd($crx$$CondRegister, R0, $oldVal$$Register, $newVal$$Register, $mem_ptr$$Register, - MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - noreg, NULL, true); - %} - ins_pipe(pipe_class_default); +instruct storePConditional_regP_regP_regP(flagsRegCR0 cr0, indirect mem_ptr, iRegPsrc oldVal, iRegPsrc newVal) %{ + match(Set cr0 (StorePConditional mem_ptr (Binary oldVal newVal))); + ins_cost(2*MEMORY_REF_COST); + + format %{ "STDCX_ if ($cr0 = ($oldVal == *$mem_ptr)) *mem_ptr = $newVal; as bool" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_stdcx_); + __ stdcx_($newVal$$Register, $mem_ptr$$Register); + %} + ins_pipe(pipe_class_memory); %} // Implement LoadPLocked. Must be ordered against changes of the memory location @@ -7577,13 +7550,14 @@ // Don't know whether this is ever used. instruct loadPLocked(iRegPdst dst, memory mem) %{ match(Set dst (LoadPLocked mem)); - ins_cost(MEMORY_REF_COST); - - format %{ "LD $dst, $mem \t// loadPLocked\n\t" - "TWI $dst\n\t" - "ISYNC" %} - size(12); - ins_encode( enc_ld_ac(dst, mem) ); + ins_cost(2*MEMORY_REF_COST); + + format %{ "LDARX $dst, $mem \t// loadPLocked\n\t" %} + size(4); + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_ldarx); + __ ldarx($dst$$Register, $mem$$Register, MacroAssembler::cmpxchgx_hint_atomic_update()); + %} ins_pipe(pipe_class_memory); %} @@ -7593,8 +7567,9 @@ // (CompareAndSwap ...)" or "If (CmpI (CompareAndSwap ..))" cannot be // matched. -instruct compareAndSwapI_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src1, iRegIsrc src2) %{ +instruct compareAndSwapI_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src1, iRegIsrc src2, flagsRegCR0 cr0) %{ match(Set res (CompareAndSwapI mem_ptr (Binary src1 src2))); + effect(TEMP cr0); format %{ "CMPXCHGW $res, $mem_ptr, $src1, $src2; as bool" %} // Variable size: instruction count smaller if regs are disjoint. ins_encode %{ @@ -7607,8 +7582,9 @@ ins_pipe(pipe_class_default); %} -instruct compareAndSwapN_regP_regN_regN(iRegIdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2) %{ +instruct compareAndSwapN_regP_regN_regN(iRegIdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, flagsRegCR0 cr0) %{ match(Set res (CompareAndSwapN mem_ptr (Binary src1 src2))); + effect(TEMP cr0); format %{ "CMPXCHGW $res, $mem_ptr, $src1, $src2; as bool" %} // Variable size: instruction count smaller if regs are disjoint. ins_encode %{ @@ -7621,8 +7597,9 @@ ins_pipe(pipe_class_default); %} -instruct compareAndSwapL_regP_regL_regL(iRegIdst res, iRegPdst mem_ptr, iRegLsrc src1, iRegLsrc src2) %{ +instruct compareAndSwapL_regP_regL_regL(iRegIdst res, iRegPdst mem_ptr, iRegLsrc src1, iRegLsrc src2, flagsRegCR0 cr0) %{ match(Set res (CompareAndSwapL mem_ptr (Binary src1 src2))); + effect(TEMP cr0); format %{ "CMPXCHGD $res, $mem_ptr, $src1, $src2; as bool" %} // Variable size: instruction count smaller if regs are disjoint. ins_encode %{ @@ -7635,8 +7612,9 @@ ins_pipe(pipe_class_default); %} -instruct compareAndSwapP_regP_regP_regP(iRegIdst res, iRegPdst mem_ptr, iRegPsrc src1, iRegPsrc src2) %{ +instruct compareAndSwapP_regP_regP_regP(iRegIdst res, iRegPdst mem_ptr, iRegPsrc src1, iRegPsrc src2, flagsRegCR0 cr0) %{ match(Set res (CompareAndSwapP mem_ptr (Binary src1 src2))); + effect(TEMP cr0); format %{ "CMPXCHGD $res, $mem_ptr, $src1, $src2; as bool; ptr" %} // Variable size: instruction count smaller if regs are disjoint. ins_encode %{ @@ -7649,48 +7627,54 @@ ins_pipe(pipe_class_default); %} -instruct getAndAddI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src) %{ +instruct getAndAddI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src, flagsRegCR0 cr0) %{ match(Set res (GetAndAddI mem_ptr src)); + effect(TEMP cr0); format %{ "GetAndAddI $res, $mem_ptr, $src" %} // Variable size: instruction count smaller if regs are disjoint. ins_encode( enc_GetAndAddI(res, mem_ptr, src) ); ins_pipe(pipe_class_default); %} -instruct getAndAddL(iRegLdst res, iRegPdst mem_ptr, iRegLsrc src) %{ +instruct getAndAddL(iRegLdst res, iRegPdst mem_ptr, iRegLsrc src, flagsRegCR0 cr0) %{ match(Set res (GetAndAddL mem_ptr src)); + effect(TEMP cr0); format %{ "GetAndAddL $res, $mem_ptr, $src" %} // Variable size: instruction count smaller if regs are disjoint. ins_encode( enc_GetAndAddL(res, mem_ptr, src) ); ins_pipe(pipe_class_default); %} -instruct getAndSetI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src) %{ +instruct getAndSetI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src, flagsRegCR0 cr0) %{ match(Set res (GetAndSetI mem_ptr src)); + effect(TEMP cr0); format %{ "GetAndSetI $res, $mem_ptr, $src" %} // Variable size: instruction count smaller if regs are disjoint. ins_encode( enc_GetAndSetI(res, mem_ptr, src) ); ins_pipe(pipe_class_default); %} -instruct getAndSetL(iRegLdst res, iRegPdst mem_ptr, iRegLsrc src) %{ +instruct getAndSetL(iRegLdst res, iRegPdst mem_ptr, iRegLsrc src, flagsRegCR0 cr0) %{ match(Set res (GetAndSetL mem_ptr src)); + effect(TEMP cr0); format %{ "GetAndSetL $res, $mem_ptr, $src" %} // Variable size: instruction count smaller if regs are disjoint. ins_encode( enc_GetAndSetL(res, mem_ptr, src) ); ins_pipe(pipe_class_default); %} -instruct getAndSetP(iRegPdst res, iRegPdst mem_ptr, iRegPsrc src) %{ +instruct getAndSetP(iRegPdst res, iRegPdst mem_ptr, iRegPsrc src, flagsRegCR0 cr0) %{ match(Set res (GetAndSetP mem_ptr src)); + effect(TEMP cr0); format %{ "GetAndSetP $res, $mem_ptr, $src" %} // Variable size: instruction count smaller if regs are disjoint. ins_encode( enc_GetAndSetL(res, mem_ptr, src) ); ins_pipe(pipe_class_default); %} -instruct getAndSetN(iRegNdst res, iRegPdst mem_ptr, iRegNsrc src) %{ +instruct getAndSetN(iRegNdst res, iRegPdst mem_ptr, iRegNsrc src, flagsRegCR0 cr0) %{ match(Set res (GetAndSetN mem_ptr src)); + effect(TEMP cr0); format %{ "GetAndSetN $res, $mem_ptr, $src" %} // Variable size: instruction count smaller if regs are disjoint. ins_encode( enc_GetAndSetI(res, mem_ptr, src) ); @@ -7898,18 +7882,8 @@ %} // Immediate Subtraction -// The compiler converts "x-c0" into "x+ -c0" (see SubINode::Ideal), -// so this rule seems to be unused. -instruct subI_reg_imm16(iRegIdst dst, iRegIsrc src1, immI16 src2) %{ - match(Set dst (SubI src1 src2)); - format %{ "SUBI $dst, $src1, $src2" %} - size(4); - ins_encode %{ - // TODO: PPC port $archOpcode(ppc64Opcode_addi); - __ addi($dst$$Register, $src1$$Register, ($src2$$constant) * (-1)); - %} - ins_pipe(pipe_class_default); -%} +// Immediate Subtraction: The compiler converts "x-c0" into "x+ -c0" (see SubLNode::Ideal), +// Don't try to use addi with - $src2$$constant since it can overflow when $src2$$constant == minI16. // SubI from constant (using subfic). instruct subI_imm16_reg(iRegIdst dst, immI16 src1, iRegIsrc src2) %{ @@ -7989,22 +7963,6 @@ ins_pipe(pipe_class_default); %} -// Immediate Subtraction -// The compiler converts "x-c0" into "x+ -c0" (see SubLNode::Ideal), -// so this rule seems to be unused. -// No constant pool entries required. -instruct subL_reg_imm16(iRegLdst dst, iRegLsrc src1, immL16 src2) %{ - match(Set dst (SubL src1 src2)); - - format %{ "SUBI $dst, $src1, $src2 \t// long" %} - size(4); - ins_encode %{ - // TODO: PPC port $archOpcode(ppc64Opcode_addi); - __ addi($dst$$Register, $src1$$Register, ($src2$$constant) * (-1)); - %} - ins_pipe(pipe_class_default); -%} - // Turn the sign-bit of a long into a 64-bit mask, 0x0...0 for // positive longs and 0xF...F for negative ones. instruct signmask64I_regL(iRegIdst dst, iRegLsrc src) %{ @@ -8165,7 +8123,7 @@ ins_pipe(pipe_class_default); %} -instruct cmovI_bne_negI_reg(iRegIdst dst, flagsReg crx, iRegIsrc src1) %{ +instruct cmovI_bne_negI_reg(iRegIdst dst, flagsRegSrc crx, iRegIsrc src1) %{ effect(USE_DEF dst, USE src1, USE crx); predicate(false); @@ -8228,7 +8186,7 @@ ins_pipe(pipe_class_default); %} -instruct cmovL_bne_negL_reg(iRegLdst dst, flagsReg crx, iRegLsrc src1) %{ +instruct cmovL_bne_negL_reg(iRegLdst dst, flagsRegSrc crx, iRegLsrc src1) %{ effect(USE_DEF dst, USE src1, USE crx); predicate(false); @@ -8281,7 +8239,7 @@ %} // Long Remainder with registers -instruct modL_reg_reg_Ex(iRegLdst dst, iRegLsrc src1, iRegLsrc src2, flagsRegCR0 cr0) %{ +instruct modL_reg_reg_Ex(iRegLdst dst, iRegLsrc src1, iRegLsrc src2) %{ match(Set dst (ModL src1 src2)); ins_cost(10*DEFAULT_COST); @@ -9011,7 +8969,6 @@ instruct andL_reg_uimm16(iRegLdst dst, iRegLsrc src1, uimmL16 src2, flagsRegCR0 cr0) %{ match(Set dst (AndL src1 src2)); effect(KILL cr0); - ins_cost(DEFAULT_COST); format %{ "ANDI $dst, $src1, $src2 \t// long" %} size(4); @@ -9803,7 +9760,7 @@ ins_pipe(pipe_class_default); %} -instruct cmovI_bso_stackSlotL(iRegIdst dst, flagsReg crx, stackSlotL src) %{ +instruct cmovI_bso_stackSlotL(iRegIdst dst, flagsRegSrc crx, stackSlotL src) %{ // no match-rule, false predicate effect(DEF dst, USE crx, USE src); predicate(false); @@ -9817,7 +9774,7 @@ ins_pipe(pipe_class_default); %} -instruct cmovI_bso_stackSlotL_conLvalue0_Ex(iRegIdst dst, flagsReg crx, stackSlotL mem) %{ +instruct cmovI_bso_stackSlotL_conLvalue0_Ex(iRegIdst dst, flagsRegSrc crx, stackSlotL mem) %{ // no match-rule, false predicate effect(DEF dst, USE crx, USE mem); predicate(false); @@ -9972,7 +9929,7 @@ ins_pipe(pipe_class_default); %} -instruct cmovL_bso_stackSlotL(iRegLdst dst, flagsReg crx, stackSlotL src) %{ +instruct cmovL_bso_stackSlotL(iRegLdst dst, flagsRegSrc crx, stackSlotL src) %{ // no match-rule, false predicate effect(DEF dst, USE crx, USE src); predicate(false); @@ -9986,7 +9943,7 @@ ins_pipe(pipe_class_default); %} -instruct cmovL_bso_stackSlotL_conLvalue0_Ex(iRegLdst dst, flagsReg crx, stackSlotL mem) %{ +instruct cmovL_bso_stackSlotL_conLvalue0_Ex(iRegLdst dst, flagsRegSrc crx, stackSlotL mem) %{ // no match-rule, false predicate effect(DEF dst, USE crx, USE mem); predicate(false); @@ -10255,7 +10212,6 @@ size(4); ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_andi_); - // FIXME: avoid andi_ ? __ andi_(R0, $src1$$Register, $src2$$constant); %} ins_pipe(pipe_class_compare); @@ -10302,13 +10258,12 @@ size(4); ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_andi_); - // FIXME: avoid andi_ ? __ andi_(R0, $src1$$Register, $src2$$constant); %} ins_pipe(pipe_class_compare); %} -instruct cmovI_conIvalueMinus1_conIvalue1(iRegIdst dst, flagsReg crx) %{ +instruct cmovI_conIvalueMinus1_conIvalue1(iRegIdst dst, flagsRegSrc crx) %{ // no match-rule, false predicate effect(DEF dst, USE crx); predicate(false); @@ -10332,7 +10287,7 @@ ins_pipe(pipe_class_compare); %} -instruct cmovI_conIvalueMinus1_conIvalue0_conIvalue1_Ex(iRegIdst dst, flagsReg crx) %{ +instruct cmovI_conIvalueMinus1_conIvalue0_conIvalue1_Ex(iRegIdst dst, flagsRegSrc crx) %{ // no match-rule, false predicate effect(DEF dst, USE crx); predicate(false); @@ -10622,8 +10577,9 @@ //----------Float Compares---------------------------------------------------- instruct cmpFUnordered_reg_reg(flagsReg crx, regF src1, regF src2) %{ + // Needs matchrule, see cmpDUnordered. + match(Set crx (CmpF src1 src2)); // no match-rule, false predicate - effect(DEF crx, USE src1, USE src2); predicate(false); format %{ "cmpFUrd $crx, $src1, $src2" %} @@ -10731,8 +10687,14 @@ %} instruct cmpDUnordered_reg_reg(flagsReg crx, regD src1, regD src2) %{ - // no match-rule, false predicate - effect(DEF crx, USE src1, USE src2); + // Needs matchrule so that ideal opcode is Cmp. This causes that gcm places the + // node right before the conditional move using it. + // In jck test api/java_awt/geom/QuadCurve2DFloat/index.html#SetCurveTesttestCase7, + // compilation of java.awt.geom.RectangularShape::getBounds()Ljava/awt/Rectangle + // crashed in register allocation where the flags Reg between cmpDUnoredered and a + // conditional move was supposed to be spilled. + match(Set crx (CmpD src1 src2)); + // False predicate, shall not be matched. predicate(false); format %{ "cmpFUrd $crx, $src1, $src2" %} @@ -10830,7 +10792,7 @@ %} // Conditional Near Branch -instruct branchCon(cmpOp cmp, flagsReg crx, label lbl) %{ +instruct branchCon(cmpOp cmp, flagsRegSrc crx, label lbl) %{ // Same match rule as `branchConFar'. match(If cmp crx); effect(USE lbl); @@ -10853,7 +10815,7 @@ // expensive. // // Conditional Far Branch -instruct branchConFar(cmpOp cmp, flagsReg crx, label lbl) %{ +instruct branchConFar(cmpOp cmp, flagsRegSrc crx, label lbl) %{ // Same match rule as `branchCon'. match(If cmp crx); effect(USE crx, USE lbl); @@ -10871,7 +10833,7 @@ %} // Conditional Branch used with Power6 scheduler (can be far or short). -instruct branchConSched(cmpOp cmp, flagsReg crx, label lbl) %{ +instruct branchConSched(cmpOp cmp, flagsRegSrc crx, label lbl) %{ // Same match rule as `branchCon'. match(If cmp crx); effect(USE crx, USE lbl); @@ -10890,7 +10852,7 @@ ins_pipe(pipe_class_default); %} -instruct branchLoopEnd(cmpOp cmp, flagsReg crx, label labl) %{ +instruct branchLoopEnd(cmpOp cmp, flagsRegSrc crx, label labl) %{ match(CountedLoopEnd cmp crx); effect(USE labl); ins_cost(BRANCH_COST); @@ -10904,7 +10866,7 @@ ins_pipe(pipe_class_default); %} -instruct branchLoopEndFar(cmpOp cmp, flagsReg crx, label labl) %{ +instruct branchLoopEndFar(cmpOp cmp, flagsRegSrc crx, label labl) %{ match(CountedLoopEnd cmp crx); effect(USE labl); predicate(!false /* TODO: PPC port HB_Schedule */); @@ -10920,7 +10882,7 @@ %} // Conditional Branch used with Power6 scheduler (can be far or short). -instruct branchLoopEndSched(cmpOp cmp, flagsReg crx, label labl) %{ +instruct branchLoopEndSched(cmpOp cmp, flagsRegSrc crx, label labl) %{ match(CountedLoopEnd cmp crx); effect(USE labl); predicate(false /* TODO: PPC port HB_Schedule */); @@ -10969,13 +10931,36 @@ instruct cmpFastLock(flagsReg crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3) %{ match(Set crx (FastLock oop box)); effect(TEMP tmp1, TEMP tmp2, TEMP tmp3); - // TODO PPC port predicate(!UseNewFastLockPPC64 || UseBiasedLocking); + predicate(/*(!UseNewFastLockPPC64 || UseBiasedLocking) &&*/ !Compile::current()->use_rtm()); format %{ "FASTLOCK $oop, $box, $tmp1, $tmp2, $tmp3" %} ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_compound); __ compiler_fast_lock_object($crx$$CondRegister, $oop$$Register, $box$$Register, - $tmp3$$Register, $tmp1$$Register, $tmp2$$Register); + $tmp3$$Register, $tmp1$$Register, $tmp2$$Register, + UseBiasedLocking && !UseOptoBiasInlining); // SAPJVM MD 2014-11-06 UseOptoBiasInlining + // If locking was successfull, crx should indicate 'EQ'. + // The compiler generates a branch to the runtime call to + // _complete_monitor_locking_Java for the case where crx is 'NE'. + %} + ins_pipe(pipe_class_compare); +%} + +// Separate version for TM. Use bound register for box to enable USE_KILL. +instruct cmpFastLock_tm(flagsReg crx, iRegPdst oop, rarg2RegP box, iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3) %{ + match(Set crx (FastLock oop box)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, USE_KILL box); + predicate(Compile::current()->use_rtm()); + + format %{ "FASTLOCK $oop, $box, $tmp1, $tmp2, $tmp3 (TM)" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ compiler_fast_lock_object($crx$$CondRegister, $oop$$Register, $box$$Register, + $tmp3$$Register, $tmp1$$Register, $tmp2$$Register, + /*Biased Locking*/ false, + _rtm_counters, _stack_rtm_counters, + ((Method*)(ra_->C->method()->constant_encoding()))->method_data(), + /*TM*/ true, ra_->C->profile_rtm()); // If locking was successfull, crx should indicate 'EQ'. // The compiler generates a branch to the runtime call to // _complete_monitor_locking_Java for the case where crx is 'NE'. @@ -10986,12 +10971,33 @@ instruct cmpFastUnlock(flagsReg crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3) %{ match(Set crx (FastUnlock oop box)); effect(TEMP tmp1, TEMP tmp2, TEMP tmp3); + predicate(!Compile::current()->use_rtm()); format %{ "FASTUNLOCK $oop, $box, $tmp1, $tmp2" %} ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_compound); __ compiler_fast_unlock_object($crx$$CondRegister, $oop$$Register, $box$$Register, - $tmp3$$Register, $tmp1$$Register, $tmp2$$Register); + $tmp3$$Register, $tmp1$$Register, $tmp2$$Register, + UseBiasedLocking && !UseOptoBiasInlining, + false); + // If unlocking was successfull, crx should indicate 'EQ'. + // The compiler generates a branch to the runtime call to + // _complete_monitor_unlocking_Java for the case where crx is 'NE'. + %} + ins_pipe(pipe_class_compare); +%} + +instruct cmpFastUnlock_tm(flagsReg crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3) %{ + match(Set crx (FastUnlock oop box)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3); + predicate(Compile::current()->use_rtm()); + + format %{ "FASTUNLOCK $oop, $box, $tmp1, $tmp2 (TM)" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ compiler_fast_unlock_object($crx$$CondRegister, $oop$$Register, $box$$Register, + $tmp3$$Register, $tmp1$$Register, $tmp2$$Register, + /*Biased Locking*/ false, /*TM*/ true); // If unlocking was successfull, crx should indicate 'EQ'. // The compiler generates a branch to the runtime call to // _complete_monitor_unlocking_Java for the case where crx is 'NE'. @@ -11658,6 +11664,66 @@ ins_pipe(pipe_class_default); %} + +//----------Overflow Math Instructions----------------------------------------- + +// Note that we have to make sure that XER.SO is reset before using overflow instructions. +// Simple Overflow operations can be matched by very few instructions (e.g. addExact: xor, and_, bc). +// Seems like only Long intrinsincs have an advantage. (The only expensive one is OverflowMulL.) + +instruct overflowAddL_reg_reg(flagsRegCR0 cr0, iRegLsrc op1, iRegLsrc op2) %{ + match(Set cr0 (OverflowAddL op1 op2)); + + format %{ "add_ $op1, $op2\t# overflow check long" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ li(R0, 0); + __ mtxer(R0); // clear XER.SO + __ addo_(R0, $op1$$Register, $op2$$Register); + %} + ins_pipe(pipe_class_default); +%} + +instruct overflowSubL_reg_reg(flagsRegCR0 cr0, iRegLsrc op1, iRegLsrc op2) %{ + match(Set cr0 (OverflowSubL op1 op2)); + + format %{ "subfo_ R0, $op2, $op1\t# overflow check long" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ li(R0, 0); + __ mtxer(R0); // clear XER.SO + __ subfo_(R0, $op2$$Register, $op1$$Register); + %} + ins_pipe(pipe_class_default); +%} + +instruct overflowNegL_reg(flagsRegCR0 cr0, immL_0 zero, iRegLsrc op2) %{ + match(Set cr0 (OverflowSubL zero op2)); + + format %{ "nego_ R0, $op2\t# overflow check long" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ li(R0, 0); + __ mtxer(R0); // clear XER.SO + __ nego_(R0, $op2$$Register); + %} + ins_pipe(pipe_class_default); +%} + +instruct overflowMulL_reg_reg(flagsRegCR0 cr0, iRegLsrc op1, iRegLsrc op2) %{ + match(Set cr0 (OverflowMulL op1 op2)); + + format %{ "mulldo_ R0, $op1, $op2\t# overflow check long" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ li(R0, 0); + __ mtxer(R0); // clear XER.SO + __ mulldo_(R0, $op1$$Register, $op2$$Register); + %} + ins_pipe(pipe_class_default); +%} + + // ============================================================================ // Safepoint Instruction diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/register_definitions_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/register_definitions_ppc.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/register_definitions_ppc.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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 @@ -23,19 +23,10 @@ * */ -// make sure the defines don't screw up the declarations later on in this file +// Make sure the defines don't screw up the declarations later on in this file. #define DONT_USE_REGISTER_DEFINES -#include "precompiled.hpp" -#include "asm/macroAssembler.hpp" #include "asm/register.hpp" -#include "register_ppc.hpp" -#ifdef TARGET_ARCH_MODEL_ppc_32 -# include "interp_masm_ppc_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_ppc_64 -# include "interp_masm_ppc_64.hpp" -#endif REGISTER_DEFINITION(Register, noreg); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/relocInfo_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/relocInfo_ppc.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/relocInfo_ppc.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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 @@ -25,14 +25,12 @@ #include "precompiled.hpp" #include "asm/assembler.inline.hpp" -#include "assembler_ppc.inline.hpp" #include "code/relocInfo.hpp" #include "nativeInst_ppc.hpp" #include "oops/oop.inline.hpp" #include "runtime/safepoint.hpp" void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) { - bool copy_back_to_oop_pool = true; // TODO: PPC port // The following comment is from the declaration of DataRelocation: // // "The "o" (displacement) argument is relevant only to split relocations diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "code/debugInfoRec.hpp" #include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" +#include "frame_ppc.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interp_masm.hpp" #include "oops/compiledICHolder.hpp" @@ -194,8 +195,8 @@ RegisterSaver_LiveIntReg( R27 ), RegisterSaver_LiveIntReg( R28 ), RegisterSaver_LiveIntReg( R29 ), - RegisterSaver_LiveIntReg( R31 ), - RegisterSaver_LiveIntReg( R30 ), // r30 must be the last register + RegisterSaver_LiveIntReg( R30 ), + RegisterSaver_LiveIntReg( R31 ), // must be the last register (see save/restore functions below) }; OopMap* RegisterSaver::push_frame_reg_args_and_save_live_registers(MacroAssembler* masm, @@ -229,29 +230,30 @@ BLOCK_COMMENT("push_frame_reg_args_and_save_live_registers {"); - // Save r30 in the last slot of the not yet pushed frame so that we + // Save r31 in the last slot of the not yet pushed frame so that we // can use it as scratch reg. - __ std(R30, -reg_size, R1_SP); + __ std(R31, -reg_size, R1_SP); assert(-reg_size == register_save_offset - frame_size_in_bytes + ((regstosave_num-1)*reg_size), "consistency check"); // save the flags // Do the save_LR_CR by hand and adjust the return pc if requested. - __ mfcr(R30); - __ std(R30, _abi(cr), R1_SP); + __ mfcr(R31); + __ std(R31, _abi(cr), R1_SP); switch (return_pc_location) { - case return_pc_is_lr: __ mflr(R30); break; - case return_pc_is_r4: __ mr(R30, R4); break; + case return_pc_is_lr: __ mflr(R31); break; + case return_pc_is_r4: __ mr(R31, R4); break; case return_pc_is_thread_saved_exception_pc: - __ ld(R30, thread_(saved_exception_pc)); break; + __ ld(R31, thread_(saved_exception_pc)); break; default: ShouldNotReachHere(); } - if (return_pc_adjustment != 0) - __ addi(R30, R30, return_pc_adjustment); - __ std(R30, _abi(lr), R1_SP); + if (return_pc_adjustment != 0) { + __ addi(R31, R31, return_pc_adjustment); + } + __ std(R31, _abi(lr), R1_SP); // push a new frame - __ push_frame(frame_size_in_bytes, R30); + __ push_frame(frame_size_in_bytes, R31); // save all registers (ints and floats) offset = register_save_offset; @@ -261,7 +263,7 @@ switch (reg_type) { case RegisterSaver::int_reg: { - if (reg_num != 30) { // We spilled R30 right at the beginning. + if (reg_num != 31) { // We spilled R31 right at the beginning. __ std(as_Register(reg_num), offset, R1_SP); } break; @@ -272,8 +274,8 @@ } case RegisterSaver::special_reg: { if (reg_num == SR_CTR_SpecialRegisterEnumValue) { - __ mfctr(R30); - __ std(R30, offset, R1_SP); + __ mfctr(R31); + __ std(R31, offset, R1_SP); } else { Unimplemented(); } @@ -321,7 +323,7 @@ switch (reg_type) { case RegisterSaver::int_reg: { - if (reg_num != 30) // R30 restored at the end, it's the tmp reg! + if (reg_num != 31) // R31 restored at the end, it's the tmp reg! __ ld(as_Register(reg_num), offset, R1_SP); break; } @@ -332,8 +334,8 @@ case RegisterSaver::special_reg: { if (reg_num == SR_CTR_SpecialRegisterEnumValue) { if (restore_ctr) { // Nothing to do here if ctr already contains the next address. - __ ld(R30, offset, R1_SP); - __ mtctr(R30); + __ ld(R31, offset, R1_SP); + __ mtctr(R31); } } else { Unimplemented(); @@ -350,10 +352,10 @@ __ pop_frame(); // restore the flags - __ restore_LR_CR(R30); + __ restore_LR_CR(R31); // restore scratch register's value - __ ld(R30, -reg_size, R1_SP); + __ ld(R31, -reg_size, R1_SP); BLOCK_COMMENT("} restore_live_registers_and_pop_frame"); } @@ -2021,6 +2023,8 @@ __ push_frame(frame_size_in_bytes, r_temp_1); // Push the c2n adapter's frame. frame_done_pc = (intptr_t)__ pc(); + __ verify_thread(); + // Native nmethod wrappers never take possesion of the oop arguments. // So the caller will gc the arguments. // The only thing we need an oopMap for is if the call is static. @@ -2594,7 +2598,7 @@ } uint SharedRuntime::out_preserve_stack_slots() { -#ifdef COMPILER2 +#if defined(COMPILER1) || defined(COMPILER2) return frame::jit_out_preserve_size / VMRegImpl::stack_slot_size; #else return 0; @@ -2868,11 +2872,6 @@ __ std(R0, in_bytes(JavaThread::exception_oop_offset()), R16_thread); __ BIND(skip_restore_excp); - // reload narrro_oop_base - if (UseCompressedOops && Universe::narrow_oop_base() != 0) { - __ load_const_optimized(R30, Universe::narrow_oop_base()); - } - __ pop_frame(); // stack: (deoptee, optional i2c, caller of deoptee, ...). diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp Thu May 07 20:51:12 2015 -0700 @@ -261,9 +261,6 @@ // global toc register __ load_const(R29, MacroAssembler::global_toc(), R11_scratch1); - // Load narrow oop base. - __ reinit_heapbase(R30, R11_scratch1); - // Remember the senderSP so we interpreter can pop c2i arguments off of the stack // when called via a c2i. @@ -418,6 +415,23 @@ // or native call stub. The pending exception in Thread is // converted into a Java-level exception. // + // Read: + // + // LR: The pc the runtime library callee wants to return to. + // Since the exception occurred in the callee, the return pc + // from the point of view of Java is the exception pc. + // thread: Needed for method handles. + // + // Invalidate: + // + // volatile registers (except below). + // + // Update: + // + // R4_ARG2: exception + // + // (LR is unchanged and is live out). + // address generate_forward_exception() { StubCodeMark mark(this, "StubRoutines", "forward_exception"); address start = __ pc(); @@ -1256,9 +1270,9 @@ Register tmp3 = R8_ARG6; #if defined(ABI_ELFv2) - address nooverlap_target = aligned ? - StubRoutines::arrayof_jbyte_disjoint_arraycopy() : - StubRoutines::jbyte_disjoint_arraycopy(); + address nooverlap_target = aligned ? + StubRoutines::arrayof_jbyte_disjoint_arraycopy() : + StubRoutines::jbyte_disjoint_arraycopy(); #else address nooverlap_target = aligned ? ((FunctionDescriptor*)StubRoutines::arrayof_jbyte_disjoint_arraycopy())->entry() : diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2013, 2014 SAP AG. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013, 2015 SAP AG. 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 @@ -264,11 +264,11 @@ __ cmpdi(CCR0, Rmdo, 0); __ beq(CCR0, no_mdo); - // Increment invocation counter in the MDO. - const int mdo_ic_offs = in_bytes(MethodData::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); - __ lwz(Rscratch2, mdo_ic_offs, Rmdo); + // Increment backedge counter in the MDO. + const int mdo_bc_offs = in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); + __ lwz(Rscratch2, mdo_bc_offs, Rmdo); __ addi(Rscratch2, Rscratch2, increment); - __ stw(Rscratch2, mdo_ic_offs, Rmdo); + __ stw(Rscratch2, mdo_bc_offs, Rmdo); __ load_const_optimized(Rscratch1, mask, R0); __ and_(Rscratch1, Rscratch2, Rscratch1); __ bne(CCR0, done); @@ -276,12 +276,12 @@ } // Increment counter in MethodCounters*. - const int mo_ic_offs = in_bytes(MethodCounters::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); + const int mo_bc_offs = in_bytes(MethodCounters::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); __ bind(no_mdo); __ get_method_counters(R19_method, R3_counters, done); - __ lwz(Rscratch2, mo_ic_offs, R3_counters); + __ lwz(Rscratch2, mo_bc_offs, R3_counters); __ addi(Rscratch2, Rscratch2, increment); - __ stw(Rscratch2, mo_ic_offs, R3_counters); + __ stw(Rscratch2, mo_bc_offs, R3_counters); __ load_const_optimized(Rscratch1, mask, R0); __ and_(Rscratch1, Rscratch2, Rscratch1); __ beq(CCR0, *overflow); @@ -611,12 +611,7 @@ // For others we can use a normal (native) entry. inline bool math_entry_available(AbstractInterpreter::MethodKind kind) { - // Provide math entry with debugging on demand. - // Note: Debugging changes which code will get executed: - // Debugging or disabled InlineIntrinsics: java method will get interpreted and performs a native call. - // Not debugging and enabled InlineIntrinics: processor instruction will get used. - // Result might differ slightly due to rounding etc. - if (!InlineIntrinsics && (!FLAG_IS_ERGO(InlineIntrinsics))) return false; // Generate a vanilla entry. + if (!InlineIntrinsics) return false; return ((kind==Interpreter::java_lang_math_sqrt && VM_Version::has_fsqrt()) || (kind==Interpreter::java_lang_math_abs)); @@ -628,15 +623,8 @@ return Interpreter::entry_for_kind(Interpreter::zerolocals); } - Label Lslow_path; - const Register Rjvmti_mode = R11_scratch1; address entry = __ pc(); - // Provide math entry with debugging on demand. - __ lwz(Rjvmti_mode, thread_(interp_only_mode)); - __ cmpwi(CCR0, Rjvmti_mode, 0); - __ bne(CCR0, Lslow_path); // jvmti_mode!=0 - __ lfd(F1_RET, Interpreter::stackElementSize, R15_esp); // Pop c2i arguments (if any) off when we return. @@ -659,9 +647,6 @@ // And we're done. __ blr(); - // Provide slow path for JVMTI case. - __ bind(Lslow_path); - __ branch_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals), R12_scratch2); __ flush(); return entry; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp --- a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2013, 2014 SAP AG. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013, 2015 SAP AG. 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 @@ -34,7 +34,7 @@ // Run with +PrintInterpreter to get the VM to print out the size. // Max size with JVMTI - const static int InterpreterCodeSize = 210*K; + const static int InterpreterCodeSize = 230*K; #endif // CPU_PPC_VM_TEMPLATEINTERPRETER_PPC_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp --- a/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright 2013, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -375,23 +375,22 @@ int index_size = wide ? sizeof(u2) : sizeof(u1); const Register Rscratch = R11_scratch1; - Label resolved; + Label is_null; // We are resolved if the resolved reference cache entry contains a // non-null object (CallSite, etc.) __ get_cache_index_at_bcp(Rscratch, 1, index_size); // Load index. - __ load_resolved_reference_at_index(R17_tos, Rscratch); - __ cmpdi(CCR0, R17_tos, 0); - __ bne(CCR0, resolved); + __ load_resolved_reference_at_index(R17_tos, Rscratch, &is_null); + __ verify_oop(R17_tos); + __ dispatch_epilog(atos, Bytecodes::length_for(bytecode())); + + __ bind(is_null); __ load_const_optimized(R3_ARG1, (int)bytecode()); address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc); // First time invocation - must resolve first. __ call_VM(R17_tos, entry, R3_ARG1); - - __ align(32, 12); - __ bind(resolved); __ verify_oop(R17_tos); } @@ -437,6 +436,14 @@ } void TemplateTable::iload() { + iload_internal(); +} + +void TemplateTable::nofast_iload() { + iload_internal(may_not_rewrite); +} + +void TemplateTable::iload_internal(RewriteControl rc) { transition(vtos, itos); // Get the local value into tos @@ -445,7 +452,7 @@ // Rewrite iload,iload pair into fast_iload2 // iload,caload pair into fast_icaload - if (RewriteFrequentPairs) { + if (RewriteFrequentPairs && rc == may_rewrite) { Label Lrewrite, Ldone; Register Rnext_byte = R3_ARG1, Rrewrite_to = R6_ARG4, @@ -709,6 +716,14 @@ } void TemplateTable::aload_0() { + aload_0_internal(); +} + +void TemplateTable::nofast_aload_0() { + aload_0_internal(may_not_rewrite); +} + +void TemplateTable::aload_0_internal(RewriteControl rc) { transition(vtos, atos); // According to bytecode histograms, the pairs: // @@ -732,7 +747,7 @@ // These bytecodes with a small amount of code are most profitable // to rewrite. - if (RewriteFrequentPairs) { + if (RewriteFrequentPairs && rc == may_rewrite) { Label Lrewrite, Ldont_rewrite; Register Rnext_byte = R3_ARG1, @@ -2144,6 +2159,12 @@ __ get_cache_and_index_at_bcp(Rcache, 1, index_size); Label Lresolved, Ldone; + Bytecodes::Code code = bytecode(); + switch (code) { + case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break; + case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break; + } + assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); // We are resolved if the indices offset contains the current bytecode. #if defined(VM_LITTLE_ENDIAN) @@ -2152,24 +2173,11 @@ __ lbz(Rscratch, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset()) + 7 - (byte_no + 1), Rcache); #endif // Acquire by cmp-br-isync (see below). - __ cmpdi(CCR0, Rscratch, (int)bytecode()); + __ cmpdi(CCR0, Rscratch, (int)code); __ beq(CCR0, Lresolved); - address entry = NULL; - switch (bytecode()) { - case Bytecodes::_getstatic : // fall through - case Bytecodes::_putstatic : // fall through - case Bytecodes::_getfield : // fall through - case Bytecodes::_putfield : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_get_put); break; - case Bytecodes::_invokevirtual : // fall through - case Bytecodes::_invokespecial : // fall through - case Bytecodes::_invokestatic : // fall through - case Bytecodes::_invokeinterface: entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invoke); break; - case Bytecodes::_invokehandle : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokehandle); break; - case Bytecodes::_invokedynamic : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokedynamic); break; - default : ShouldNotReachHere(); break; - } - __ li(R4_ARG2, (int)bytecode()); + address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache); + __ li(R4_ARG2, code); __ call_VM(noreg, entry, R4_ARG2, true); // Update registers with resolved info. @@ -2350,7 +2358,7 @@ } // PPC64: implement volatile loads as fence-store-acquire. -void TemplateTable::getfield_or_static(int byte_no, bool is_static) { +void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteControl rc) { transition(vtos, vtos); Label Lacquire, Lisync; @@ -2366,7 +2374,7 @@ static address field_branch_table[number_of_states], static_branch_table[number_of_states]; - address* branch_table = is_static ? static_branch_table : field_branch_table; + address* branch_table = (is_static || rc == may_not_rewrite) ? static_branch_table : field_branch_table; // Get field offset. resolve_cache_and_index(byte_no, Rcache, Rscratch, sizeof(u2)); @@ -2417,7 +2425,14 @@ #ifdef ASSERT __ bind(LFlagInvalid); __ stop("got invalid flag", 0x654); - +#endif + + if (!is_static && rc == may_not_rewrite) { + // We reuse the code from is_static. It's jumped to via the table above. + return; + } + +#ifdef ASSERT // __ bind(Lvtos); address pc_before_fence = __ pc(); __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). @@ -2434,7 +2449,9 @@ branch_table[dtos] = __ pc(); // non-volatile_entry point __ lfdx(F15_ftos, Rclass_or_obj, Roffset); __ push(dtos); - if (!is_static) patch_bytecode(Bytecodes::_fast_dgetfield, Rbc, Rscratch); + if (!is_static && rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_dgetfield, Rbc, Rscratch); + } { Label acquire_double; __ beq(CCR6, acquire_double); // Volatile? @@ -2453,7 +2470,9 @@ branch_table[ftos] = __ pc(); // non-volatile_entry point __ lfsx(F15_ftos, Rclass_or_obj, Roffset); __ push(ftos); - if (!is_static) { patch_bytecode(Bytecodes::_fast_fgetfield, Rbc, Rscratch); } + if (!is_static && rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_fgetfield, Rbc, Rscratch); + } { Label acquire_float; __ beq(CCR6, acquire_float); // Volatile? @@ -2472,7 +2491,9 @@ branch_table[itos] = __ pc(); // non-volatile_entry point __ lwax(R17_tos, Rclass_or_obj, Roffset); __ push(itos); - if (!is_static) patch_bytecode(Bytecodes::_fast_igetfield, Rbc, Rscratch); + if (!is_static && rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_igetfield, Rbc, Rscratch); + } __ beq(CCR6, Lacquire); // Volatile? __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); @@ -2483,7 +2504,9 @@ branch_table[ltos] = __ pc(); // non-volatile_entry point __ ldx(R17_tos, Rclass_or_obj, Roffset); __ push(ltos); - if (!is_static) patch_bytecode(Bytecodes::_fast_lgetfield, Rbc, Rscratch); + if (!is_static && rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_lgetfield, Rbc, Rscratch); + } __ beq(CCR6, Lacquire); // Volatile? __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); @@ -2495,7 +2518,9 @@ __ lbzx(R17_tos, Rclass_or_obj, Roffset); __ extsb(R17_tos, R17_tos); __ push(btos); - if (!is_static) patch_bytecode(Bytecodes::_fast_bgetfield, Rbc, Rscratch); + if (!is_static && rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_bgetfield, Rbc, Rscratch); + } __ beq(CCR6, Lacquire); // Volatile? __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); @@ -2506,7 +2531,9 @@ branch_table[ctos] = __ pc(); // non-volatile_entry point __ lhzx(R17_tos, Rclass_or_obj, Roffset); __ push(ctos); - if (!is_static) patch_bytecode(Bytecodes::_fast_cgetfield, Rbc, Rscratch); + if (!is_static && rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_cgetfield, Rbc, Rscratch); + } __ beq(CCR6, Lacquire); // Volatile? __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); @@ -2517,7 +2544,9 @@ branch_table[stos] = __ pc(); // non-volatile_entry point __ lhax(R17_tos, Rclass_or_obj, Roffset); __ push(stos); - if (!is_static) patch_bytecode(Bytecodes::_fast_sgetfield, Rbc, Rscratch); + if (!is_static && rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_sgetfield, Rbc, Rscratch); + } __ beq(CCR6, Lacquire); // Volatile? __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); @@ -2530,7 +2559,9 @@ __ verify_oop(R17_tos); __ push(atos); //__ dcbt(R17_tos); // prefetch - if (!is_static) patch_bytecode(Bytecodes::_fast_agetfield, Rbc, Rscratch); + if (!is_static && rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_agetfield, Rbc, Rscratch); + } __ beq(CCR6, Lacquire); // Volatile? __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); @@ -2553,6 +2584,10 @@ getfield_or_static(byte_no, false); } +void TemplateTable::nofast_getfield(int byte_no) { + getfield_or_static(byte_no, false, may_not_rewrite); +} + void TemplateTable::getstatic(int byte_no) { getfield_or_static(byte_no, true); } @@ -2643,7 +2678,7 @@ } // PPC64: implement volatile stores as release-store (return bytecode contains an additional release). -void TemplateTable::putfield_or_static(int byte_no, bool is_static) { +void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteControl rc) { Label Lvolatile; const Register Rcache = R5_ARG3, // Do not use ARG1/2 (causes trouble in jvmti_post_field_mod). @@ -2657,10 +2692,12 @@ Rbc = Rscratch3; const ConditionRegister CR_is_vol = CCR2; // Non-volatile condition register (survives runtime call in do_oop_store). - static address field_branch_table[number_of_states], + static address field_rw_branch_table[number_of_states], + field_norw_branch_table[number_of_states], static_branch_table[number_of_states]; - address* branch_table = is_static ? static_branch_table : field_branch_table; + address* branch_table = is_static ? static_branch_table : + (rc == may_rewrite ? field_rw_branch_table : field_norw_branch_table); // Stack (grows up): // value @@ -2688,7 +2725,9 @@ // Load from branch table and dispatch (volatile case: one instruction ahead). __ sldi(Rflags, Rflags, LogBytesPerWord); - if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { __ cmpwi(CR_is_vol, Rscratch, 1); } // Volatile? + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ cmpwi(CR_is_vol, Rscratch, 1); // Volatile? + } __ sldi(Rscratch, Rscratch, exact_log2(BytesPerInstWord)); // Volatile? size of instruction 1 : 0. __ ldx(Rbtable, Rbtable, Rflags); @@ -2715,9 +2754,13 @@ assert(branch_table[dtos] == 0, "can't compute twice"); branch_table[dtos] = __ pc(); // non-volatile_entry point __ pop(dtos); - if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1. + if (!is_static) { + pop_and_check_object(Rclass_or_obj); // Kills R11_scratch1. + } __ stfdx(F15_ftos, Rclass_or_obj, Roffset); - if (!is_static) { patch_bytecode(Bytecodes::_fast_dputfield, Rbc, Rscratch, true, byte_no); } + if (!is_static && rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_dputfield, Rbc, Rscratch, true, byte_no); + } if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { __ beq(CR_is_vol, Lvolatile); // Volatile? } @@ -2731,7 +2774,9 @@ __ pop(ftos); if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1. __ stfsx(F15_ftos, Rclass_or_obj, Roffset); - if (!is_static) { patch_bytecode(Bytecodes::_fast_fputfield, Rbc, Rscratch, true, byte_no); } + if (!is_static && rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_fputfield, Rbc, Rscratch, true, byte_no); + } if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { __ beq(CR_is_vol, Lvolatile); // Volatile? } @@ -2745,7 +2790,9 @@ __ pop(itos); if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1. __ stwx(R17_tos, Rclass_or_obj, Roffset); - if (!is_static) { patch_bytecode(Bytecodes::_fast_iputfield, Rbc, Rscratch, true, byte_no); } + if (!is_static && rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_iputfield, Rbc, Rscratch, true, byte_no); + } if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { __ beq(CR_is_vol, Lvolatile); // Volatile? } @@ -2759,7 +2806,9 @@ __ pop(ltos); if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1. __ stdx(R17_tos, Rclass_or_obj, Roffset); - if (!is_static) { patch_bytecode(Bytecodes::_fast_lputfield, Rbc, Rscratch, true, byte_no); } + if (!is_static && rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_lputfield, Rbc, Rscratch, true, byte_no); + } if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { __ beq(CR_is_vol, Lvolatile); // Volatile? } @@ -2773,7 +2822,9 @@ __ pop(btos); if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1. __ stbx(R17_tos, Rclass_or_obj, Roffset); - if (!is_static) { patch_bytecode(Bytecodes::_fast_bputfield, Rbc, Rscratch, true, byte_no); } + if (!is_static && rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_bputfield, Rbc, Rscratch, true, byte_no); + } if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { __ beq(CR_is_vol, Lvolatile); // Volatile? } @@ -2787,7 +2838,9 @@ __ pop(ctos); if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1.. __ sthx(R17_tos, Rclass_or_obj, Roffset); - if (!is_static) { patch_bytecode(Bytecodes::_fast_cputfield, Rbc, Rscratch, true, byte_no); } + if (!is_static && rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_cputfield, Rbc, Rscratch, true, byte_no); + } if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { __ beq(CR_is_vol, Lvolatile); // Volatile? } @@ -2801,7 +2854,9 @@ __ pop(stos); if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1. __ sthx(R17_tos, Rclass_or_obj, Roffset); - if (!is_static) { patch_bytecode(Bytecodes::_fast_sputfield, Rbc, Rscratch, true, byte_no); } + if (!is_static && rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_sputfield, Rbc, Rscratch, true, byte_no); + } if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { __ beq(CR_is_vol, Lvolatile); // Volatile? } @@ -2815,7 +2870,9 @@ __ pop(atos); if (!is_static) { pop_and_check_object(Rclass_or_obj); } // kills R11_scratch1 do_oop_store(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, Rscratch2, Rscratch3, _bs->kind(), false /* precise */, true /* check null */); - if (!is_static) { patch_bytecode(Bytecodes::_fast_aputfield, Rbc, Rscratch, true, byte_no); } + if (!is_static && rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_aputfield, Rbc, Rscratch, true, byte_no); + } if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { __ beq(CR_is_vol, Lvolatile); // Volatile? __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); @@ -2839,6 +2896,10 @@ putfield_or_static(byte_no, false); } +void TemplateTable::nofast_putfield(int byte_no) { + putfield_or_static(byte_no, false, may_not_rewrite); +} + void TemplateTable::putstatic(int byte_no) { putfield_or_static(byte_no, true); } @@ -3259,7 +3320,9 @@ __ testbitdi(CCR0, R0, Rflags, ConstantPoolCacheEntry::is_vfinal_shift); __ bfalse(CCR0, LnotFinal); - patch_bytecode(Bytecodes::_fast_invokevfinal, Rnew_bc, R12_scratch2); + if (RewriteBytecodes && !UseSharedSpaces) { + patch_bytecode(Bytecodes::_fast_invokevfinal, Rnew_bc, R12_scratch2); + } invokevfinal_helper(Rvtableindex_or_method, Rflags, R11_scratch1, R12_scratch2); __ align(32, 12); @@ -3795,9 +3858,9 @@ transition(atos, itos); Label Ldone, Lis_null, Lquicked, Lresolved; - Register Roffset = R5_ARG3, + Register Roffset = R6_ARG4, RobjKlass = R4_ARG2, - RspecifiedKlass = R6_ARG4, // Generate_ClassCastException_verbose_handler will expect the value in this register. + RspecifiedKlass = R5_ARG3, Rcpool = R11_scratch1, Rtags = R12_scratch2; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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 @@ -32,12 +32,13 @@ #include "runtime/os.hpp" #include "runtime/stubCodeGenerator.hpp" #include "utilities/defaultStream.hpp" +#include "utilities/globalDefinitions.hpp" #include "vm_version_ppc.hpp" # include int VM_Version::_features = VM_Version::unknown_m; -int VM_Version::_measured_cache_line_size = 128; // default value +int VM_Version::_measured_cache_line_size = 32; // pessimistic init value const char* VM_Version::_features_str = ""; bool VM_Version::_is_determine_features_test_running = false; @@ -55,7 +56,9 @@ // If PowerArchitecturePPC64 hasn't been specified explicitly determine from features. if (FLAG_IS_DEFAULT(PowerArchitecturePPC64)) { - if (VM_Version::has_popcntw()) { + if (VM_Version::has_lqarx()) { + FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 8); + } else if (VM_Version::has_popcntw()) { FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 7); } else if (VM_Version::has_cmpb()) { FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 6); @@ -66,8 +69,14 @@ } } guarantee(PowerArchitecturePPC64 == 0 || PowerArchitecturePPC64 == 5 || - PowerArchitecturePPC64 == 6 || PowerArchitecturePPC64 == 7, - "PowerArchitecturePPC64 should be 0, 5, 6 or 7"); + PowerArchitecturePPC64 == 6 || PowerArchitecturePPC64 == 7 || + PowerArchitecturePPC64 == 8, + "PowerArchitecturePPC64 should be 0, 5, 6, 7, or 8"); + + // Power 8: Configure Data Stream Control Register. + if (PowerArchitecturePPC64 >= 8) { + config_dscr(); + } if (!UseSIGTRAP) { MSG(TrapBasedICMissChecks); @@ -97,7 +106,7 @@ // Create and print feature-string. char buf[(num_features+1) * 16]; // Max 16 chars per feature. jio_snprintf(buf, sizeof(buf), - "ppc64%s%s%s%s%s%s%s%s", + "ppc64%s%s%s%s%s%s%s%s%s%s%s%s", (has_fsqrt() ? " fsqrt" : ""), (has_isel() ? " isel" : ""), (has_lxarxeh() ? " lxarxeh" : ""), @@ -106,11 +115,17 @@ (has_popcntb() ? " popcntb" : ""), (has_popcntw() ? " popcntw" : ""), (has_fcfids() ? " fcfids" : ""), - (has_vand() ? " vand" : "") + (has_vand() ? " vand" : ""), + (has_lqarx() ? " lqarx" : ""), + (has_vcipher() ? " vcipher" : ""), + (has_vpmsumb() ? " vpmsumb" : ""), + (has_tcheck() ? " tcheck" : "") // Make sure number of %s matches num_features! ); _features_str = os::strdup(buf); - NOT_PRODUCT(if (Verbose) print_features();); + if (Verbose) { + print_features(); + } // PPC64 supports 8-byte compare-exchange operations (see // Atomic::cmpxchg and StubGenerator::generate_atomic_cmpxchg_ptr) @@ -171,7 +186,86 @@ FLAG_SET_DEFAULT(UseSHA256Intrinsics, false); FLAG_SET_DEFAULT(UseSHA512Intrinsics, false); } + // Adjust RTM (Restricted Transactional Memory) flags. + if (!has_tcheck() && UseRTMLocking) { + // Can't continue because UseRTMLocking affects UseBiasedLocking flag + // setting during arguments processing. See use_biased_locking(). + // VM_Version_init() is executed after UseBiasedLocking is used + // in Thread::allocate(). + vm_exit_during_initialization("RTM instructions are not available on this CPU"); + } + if (UseRTMLocking) { +#if INCLUDE_RTM_OPT + if (!UnlockExperimentalVMOptions) { + vm_exit_during_initialization("UseRTMLocking is only available as experimental option on this platform. " + "It must be enabled via -XX:+UnlockExperimentalVMOptions flag."); + } else { + warning("UseRTMLocking is only available as experimental option on this platform."); + } + if (!FLAG_IS_CMDLINE(UseRTMLocking)) { + // RTM locking should be used only for applications with + // high lock contention. For now we do not use it by default. + vm_exit_during_initialization("UseRTMLocking flag should be only set on command line"); + } + if (!is_power_of_2(RTMTotalCountIncrRate)) { + warning("RTMTotalCountIncrRate must be a power of 2, resetting it to 64"); + FLAG_SET_DEFAULT(RTMTotalCountIncrRate, 64); + } + if (RTMAbortRatio < 0 || RTMAbortRatio > 100) { + warning("RTMAbortRatio must be in the range 0 to 100, resetting it to 50"); + FLAG_SET_DEFAULT(RTMAbortRatio, 50); + } + FLAG_SET_ERGO(bool, UseNewFastLockPPC64, false); // Does not implement TM. + guarantee(RTMSpinLoopCount > 0, "unsupported"); +#else + // Only C2 does RTM locking optimization. + // Can't continue because UseRTMLocking affects UseBiasedLocking flag + // setting during arguments processing. See use_biased_locking(). + vm_exit_during_initialization("RTM locking optimization is not supported in this VM"); +#endif + } else { // !UseRTMLocking + if (UseRTMForStackLocks) { + if (!FLAG_IS_DEFAULT(UseRTMForStackLocks)) { + warning("UseRTMForStackLocks flag should be off when UseRTMLocking flag is off"); + } + FLAG_SET_DEFAULT(UseRTMForStackLocks, false); + } + if (UseRTMDeopt) { + FLAG_SET_DEFAULT(UseRTMDeopt, false); + } + if (PrintPreciseRTMLockingStatistics) { + FLAG_SET_DEFAULT(PrintPreciseRTMLockingStatistics, false); + } + } + + // This machine does not allow unaligned memory accesses + if (UseUnalignedAccesses) { + if (!FLAG_IS_DEFAULT(UseUnalignedAccesses)) + warning("Unaligned memory access is not available on this CPU"); + FLAG_SET_DEFAULT(UseUnalignedAccesses, false); + } +} + +bool VM_Version::use_biased_locking() { +#if INCLUDE_RTM_OPT + // RTM locking is most useful when there is high lock contention and + // low data contention. With high lock contention the lock is usually + // inflated and biased locking is not suitable for that case. + // RTM locking code requires that biased locking is off. + // Note: we can't switch off UseBiasedLocking in get_processor_features() + // because it is used by Thread::allocate() which is called before + // VM_Version::initialize(). + if (UseRTMLocking && UseBiasedLocking) { + if (FLAG_IS_DEFAULT(UseBiasedLocking)) { + FLAG_SET_DEFAULT(UseBiasedLocking, false); + } else { + warning("Biased locking is not supported with RTM locking; ignoring UseBiasedLocking flag." ); + UseBiasedLocking = false; + } + } +#endif + return UseBiasedLocking; } void VM_Version::print_features() { @@ -437,16 +531,19 @@ // Don't use R0 in ldarx. // Keep R3_ARG1 unmodified, it contains &field (see below). // Keep R4_ARG2 unmodified, it contains offset = 0 (see below). - a->fsqrt(F3, F4); // code[0] -> fsqrt_m - a->fsqrts(F3, F4); // code[1] -> fsqrts_m - a->isel(R7, R5, R6, 0); // code[2] -> isel_m - a->ldarx_unchecked(R7, R3_ARG1, R4_ARG2, 1); // code[3] -> lxarx_m - a->cmpb(R7, R5, R6); // code[4] -> bcmp - //a->mftgpr(R7, F3); // code[5] -> mftgpr - a->popcntb(R7, R5); // code[6] -> popcntb - a->popcntw(R7, R5); // code[7] -> popcntw - a->fcfids(F3, F4); // code[8] -> fcfids - a->vand(VR0, VR0, VR0); // code[9] -> vand + a->fsqrt(F3, F4); // code[0] -> fsqrt_m + a->fsqrts(F3, F4); // code[1] -> fsqrts_m + a->isel(R7, R5, R6, 0); // code[2] -> isel_m + a->ldarx_unchecked(R7, R3_ARG1, R4_ARG2, 1); // code[3] -> lxarx_m + a->cmpb(R7, R5, R6); // code[4] -> cmpb + a->popcntb(R7, R5); // code[5] -> popcntb + a->popcntw(R7, R5); // code[6] -> popcntw + a->fcfids(F3, F4); // code[7] -> fcfids + a->vand(VR0, VR0, VR0); // code[8] -> vand + a->lqarx_unchecked(R7, R3_ARG1, R4_ARG2, 1); // code[9] -> lqarx_m + a->vcipher(VR0, VR1, VR2); // code[10] -> vcipher + a->vpmsumb(VR0, VR1, VR2); // code[11] -> vpmsumb + a->tcheck(0); // code[12] -> tcheck a->blr(); // Emit function to set one cache line to zero. Emit function descriptor and get pointer to it. @@ -485,11 +582,14 @@ if (code[feature_cntr++]) features |= isel_m; if (code[feature_cntr++]) features |= lxarxeh_m; if (code[feature_cntr++]) features |= cmpb_m; - //if(code[feature_cntr++])features |= mftgpr_m; if (code[feature_cntr++]) features |= popcntb_m; if (code[feature_cntr++]) features |= popcntw_m; if (code[feature_cntr++]) features |= fcfids_m; if (code[feature_cntr++]) features |= vand_m; + if (code[feature_cntr++]) features |= lqarx_m; + if (code[feature_cntr++]) features |= vcipher_m; + if (code[feature_cntr++]) features |= vpmsumb_m; + if (code[feature_cntr++]) features |= tcheck_m; // Print the detection code. if (PrintAssembly) { @@ -501,6 +601,69 @@ _features = features; } +// Power 8: Configure Data Stream Control Register. +void VM_Version::config_dscr() { + assert(has_tcheck(), "Only execute on Power 8 or later!"); + + // 7 InstWords for each call (function descriptor + blr instruction). + const int code_size = (2+2*7)*BytesPerInstWord; + + // Allocate space for the code. + ResourceMark rm; + CodeBuffer cb("config_dscr", code_size, 0); + MacroAssembler* a = new MacroAssembler(&cb); + + // Emit code. + uint64_t (*get_dscr)() = (uint64_t(*)())(void *)a->emit_fd(); + uint32_t *code = (uint32_t *)a->pc(); + a->mfdscr(R3); + a->blr(); + + void (*set_dscr)(long) = (void(*)(long))(void *)a->emit_fd(); + a->mtdscr(R3); + a->blr(); + + uint32_t *code_end = (uint32_t *)a->pc(); + a->flush(); + + // Print the detection code. + if (PrintAssembly) { + ttyLocker ttyl; + tty->print_cr("Decoding dscr configuration stub at " INTPTR_FORMAT " before execution:", code); + Disassembler::decode((u_char*)code, (u_char*)code_end, tty); + } + + // Apply the configuration if needed. + uint64_t dscr_val = (*get_dscr)(); + if (Verbose) { + tty->print_cr("dscr value was 0x%lx" , dscr_val); + } + bool change_requested = false; + if (DSCR_PPC64 != (uintx)-1) { + dscr_val = DSCR_PPC64; + change_requested = true; + } + if (DSCR_DPFD_PPC64 <= 7) { + uint64_t mask = 0x7; + if ((dscr_val & mask) != DSCR_DPFD_PPC64) { + dscr_val = (dscr_val & ~mask) | (DSCR_DPFD_PPC64); + change_requested = true; + } + } + if (DSCR_URG_PPC64 <= 7) { + uint64_t mask = 0x7 << 6; + if ((dscr_val & mask) != DSCR_DPFD_PPC64 << 6) { + dscr_val = (dscr_val & ~mask) | (DSCR_URG_PPC64 << 6); + change_requested = true; + } + } + if (change_requested) { + (*set_dscr)(dscr_val); + if (Verbose) { + tty->print_cr("dscr was set to 0x%lx" , (*get_dscr)()); + } + } +} static int saved_features = 0; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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 @@ -41,7 +41,10 @@ popcntw, fcfids, vand, - dcba, + lqarx, + vcipher, + vpmsumb, + tcheck, num_features // last entry to count features }; enum Feature_Flag_Set { @@ -55,7 +58,10 @@ popcntw_m = (1 << popcntw), fcfids_m = (1 << fcfids ), vand_m = (1 << vand ), - dcba_m = (1 << dcba ), + lqarx_m = (1 << lqarx ), + vcipher_m = (1 << vcipher), + vpmsumb_m = (1 << vpmsumb), + tcheck_m = (1 << tcheck ), all_features_m = -1 }; static int _features; @@ -65,12 +71,16 @@ static void print_features(); static void determine_features(); // also measures cache line size + static void config_dscr(); // Power 8: Configure Data Stream Control Register. static void determine_section_size(); static void power6_micro_bench(); public: // Initialization static void initialize(); + // Override Abstract_VM_Version implementation + static bool use_biased_locking(); + static bool is_determine_features_test_running() { return _is_determine_features_test_running; } // CPU instruction support static bool has_fsqrt() { return (_features & fsqrt_m) != 0; } @@ -82,7 +92,10 @@ static bool has_popcntw() { return (_features & popcntw_m) != 0; } static bool has_fcfids() { return (_features & fcfids_m) != 0; } static bool has_vand() { return (_features & vand_m) != 0; } - static bool has_dcba() { return (_features & dcba_m) != 0; } + static bool has_lqarx() { return (_features & lqarx_m) != 0; } + static bool has_vcipher() { return (_features & vcipher_m) != 0; } + static bool has_vpmsumb() { return (_features & vpmsumb_m) != 0; } + static bool has_tcheck() { return (_features & tcheck_m) != 0; } static const char* cpu_features() { return _features_str; } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp --- a/hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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,7 +24,6 @@ */ #include "precompiled.hpp" -#include "asm/assembler.hpp" #include "asm/macroAssembler.inline.hpp" #include "code/vtableStubs.hpp" #include "interp_masm_ppc_64.hpp" diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/sparc/vm/globals_sparc.hpp --- a/hotspot/src/cpu/sparc/vm/globals_sparc.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/globals_sparc.hpp Thu May 07 20:51:12 2015 -0700 @@ -74,6 +74,8 @@ define_pd_global(bool, UseMembar, false); +define_pd_global(bool, PreserveFramePointer, false); + // GC Ergo Flags define_pd_global(size_t, CMSYoungGenPerWorker, 16*M); // default max size of CMS young gen, per GC worker thread diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp --- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -203,7 +203,6 @@ void field_offset_at(int n, Register tmp, Register dest, Register base); int field_offset_at(Register object, address bcp, int offset); void fast_iaaccess(int n, address bcp); - void fast_iagetfield(address bcp); void fast_iaputfield(address bcp, bool do_store_check ); void index_check(Register array, Register index, int index_shift, Register tmp, Register res); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp Thu May 07 20:51:12 2015 -0700 @@ -3019,44 +3019,107 @@ // past the store that releases the lock. But TSO is a strong memory model // and that particular flavor of barrier is a noop, so we can safely elide it. // Note that we use 1-0 locking by default for the inflated case. We - // close the resultant (and rare) race by having contented threads in + // close the resultant (and rare) race by having contended threads in // monitorenter periodically poll _owner. - ld_ptr(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), Rscratch); - ld_ptr(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions), Rbox); - xor3(Rscratch, G2_thread, Rscratch); - orcc(Rbox, Rscratch, Rbox); - brx(Assembler::notZero, false, Assembler::pn, done); - delayed()-> - ld_ptr(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList), Rscratch); - ld_ptr(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq), Rbox); - orcc(Rbox, Rscratch, G0); - if (EmitSync & 65536) { - Label LSucc ; - brx(Assembler::notZero, false, Assembler::pn, LSucc); - delayed()->nop(); - ba(done); - delayed()->st_ptr(G0, Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)); - - bind(LSucc); - st_ptr(G0, Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)); - if (os::is_MP()) { membar (StoreLoad); } - ld_ptr(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ), Rscratch); - andcc(Rscratch, Rscratch, G0); - brx(Assembler::notZero, false, Assembler::pt, done); - delayed()->andcc(G0, G0, G0); - add(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), Rmark); - mov(G2_thread, Rscratch); - cas_ptr(Rmark, G0, Rscratch); - // invert icc.zf and goto done - br_notnull(Rscratch, false, Assembler::pt, done); - delayed()->cmp(G0, G0); - ba(done); - delayed()->cmp(G0, 1); + + if (EmitSync & 1024) { + // Emit code to check that _owner == Self + // We could fold the _owner test into subsequent code more efficiently + // than using a stand-alone check, but since _owner checking is off by + // default we don't bother. We also might consider predicating the + // _owner==Self check on Xcheck:jni or running on a debug build. + ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), Rscratch); + orcc(Rscratch, G0, G0); + brx(Assembler::notZero, false, Assembler::pn, done); + delayed()->nop(); + } + + if (EmitSync & 512) { + // classic lock release code absent 1-0 locking + // m->Owner = null; + // membar #storeload + // if (m->cxq|m->EntryList) == null goto Success + // if (m->succ != null) goto Success + // if CAS (&m->Owner,0,Self) != 0 goto Success + // goto SlowPath + ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), Rbox); + orcc(Rbox, G0, G0); + brx(Assembler::notZero, false, Assembler::pn, done); + delayed()->nop(); + st_ptr(G0, Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); + if (os::is_MP()) { membar(StoreLoad); } + ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList)), Rscratch); + ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq)), Rbox); + orcc(Rbox, Rscratch, G0); + brx(Assembler::zero, false, Assembler::pt, done); + delayed()-> + ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), Rscratch); + andcc(Rscratch, Rscratch, G0); + brx(Assembler::notZero, false, Assembler::pt, done); + delayed()->andcc(G0, G0, G0); + add(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), Rmark); + mov(G2_thread, Rscratch); + cas_ptr(Rmark, G0, Rscratch); + cmp(Rscratch, G0); + // invert icc.zf and goto done + brx(Assembler::notZero, false, Assembler::pt, done); + delayed()->cmp(G0, G0); + br(Assembler::always, false, Assembler::pt, done); + delayed()->cmp(G0, 1); } else { - brx(Assembler::notZero, false, Assembler::pn, done); - delayed()->nop(); - ba(done); - delayed()->st_ptr(G0, Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)); + // 1-0 form : avoids CAS and MEMBAR in the common case + // Do not bother to ratify that m->Owner == Self. + ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), Rbox); + orcc(Rbox, G0, G0); + brx(Assembler::notZero, false, Assembler::pn, done); + delayed()-> + ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList)), Rscratch); + ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq)), Rbox); + orcc(Rbox, Rscratch, G0); + if (EmitSync & 16384) { + // As an optional optimization, if (EntryList|cxq) != null and _succ is null then + // we should transfer control directly to the slow-path. + // This test makes the reacquire operation below very infrequent. + // The logic is equivalent to : + // if (cxq|EntryList) == null : Owner=null; goto Success + // if succ == null : goto SlowPath + // Owner=null; membar #storeload + // if succ != null : goto Success + // if CAS(&Owner,null,Self) != null goto Success + // goto SlowPath + brx(Assembler::zero, true, Assembler::pt, done); + delayed()-> + st_ptr(G0, Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); + ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), Rscratch); + andcc(Rscratch, Rscratch, G0) ; + brx(Assembler::zero, false, Assembler::pt, done); + delayed()->orcc(G0, 1, G0); + st_ptr(G0, Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); + } else { + brx(Assembler::zero, false, Assembler::pt, done); + delayed()-> + st_ptr(G0, Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); + } + if (os::is_MP()) { membar(StoreLoad); } + // Check that _succ is (or remains) non-zero + ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), Rscratch); + andcc(Rscratch, Rscratch, G0); + brx(Assembler::notZero, false, Assembler::pt, done); + delayed()->andcc(G0, G0, G0); + add(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), Rmark); + mov(G2_thread, Rscratch); + cas_ptr(Rmark, G0, Rscratch); + cmp(Rscratch, G0); + // invert icc.zf and goto done + // A slightly better v8+/v9 idiom would be the following: + // movrnz Rscratch,1,Rscratch + // ba done + // xorcc Rscratch,1,G0 + // In v8+ mode the idiom would be valid IFF Rscratch was a G or O register + brx(Assembler::notZero, false, Assembler::pt, done); + delayed()->cmp(G0, G0); + br(Assembler::always, false, Assembler::pt, done); + delayed()->cmp(G0, 1); } bind (LStacked); @@ -3632,23 +3695,11 @@ if (satb_log_enqueue_with_frame == 0) { generate_satb_log_enqueue(with_frame); assert(satb_log_enqueue_with_frame != 0, "postcondition."); - if (G1SATBPrintStubs) { - tty->print_cr("Generated with-frame satb enqueue:"); - Disassembler::decode((u_char*)satb_log_enqueue_with_frame, - satb_log_enqueue_with_frame_end, - tty); - } } } else { if (satb_log_enqueue_frameless == 0) { generate_satb_log_enqueue(with_frame); assert(satb_log_enqueue_frameless != 0, "postcondition."); - if (G1SATBPrintStubs) { - tty->print_cr("Generated frameless satb enqueue:"); - Disassembler::decode((u_char*)satb_log_enqueue_frameless, - satb_log_enqueue_frameless_end, - tty); - } } } } @@ -3841,12 +3892,6 @@ if (dirty_card_log_enqueue == 0) { generate_dirty_card_log_enqueue(byte_map_base); assert(dirty_card_log_enqueue != 0, "postcondition."); - if (G1SATBPrintStubs) { - tty->print_cr("Generated dirty_card enqueue:"); - Disassembler::decode((u_char*)dirty_card_log_enqueue, - dirty_card_log_enqueue_end, - tty); - } } } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2664,6 +2664,9 @@ // disallows any pending_exception. __ mov(L3_box, O1); + // Pass in current thread pointer + __ mov(G2_thread, O2); + __ call(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_unlocking_C), relocInfo::runtime_call_type); __ delayed()->mov(L4, O0); // Need oop in O0 diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Thu May 07 20:51:12 2015 -0700 @@ -385,7 +385,6 @@ __ verify_oop(Otos_i); } - void TemplateTable::ldc2_w() { transition(vtos, vtos); Label Long, exit; @@ -430,22 +429,28 @@ __ bind(exit); } - void TemplateTable::locals_index(Register reg, int offset) { __ ldub( at_bcp(offset), reg ); } - void TemplateTable::locals_index_wide(Register reg) { // offset is 2, not 1, because Lbcp points to wide prefix code __ get_2_byte_integer_at_bcp(2, G4_scratch, reg, InterpreterMacroAssembler::Unsigned); } void TemplateTable::iload() { + iload_internal(); +} + +void TemplateTable::nofast_iload() { + iload_internal(may_not_rewrite); +} + +void TemplateTable::iload_internal(RewriteControl rc) { transition(vtos, itos); // Rewrite iload,iload pair into fast_iload2 // iload,caload pair into fast_icaload - if (RewriteFrequentPairs) { + if (RewriteFrequentPairs && rc == may_rewrite) { Label rewrite, done; // get next byte @@ -672,8 +677,15 @@ __ ld_ptr( Llocals, Interpreter::local_offset_in_bytes(n), Otos_i ); } - void TemplateTable::aload_0() { + aload_0_internal(); +} + +void TemplateTable::nofast_aload_0() { + aload_0_internal(may_not_rewrite); +} + +void TemplateTable::aload_0_internal(RewriteControl rc) { transition(vtos, atos); // According to bytecode histograms, the pairs: @@ -687,7 +699,7 @@ // bytecode into a pair bytecode; otherwise it rewrites the current // bytecode into _fast_aload_0 that doesn't do the pair check anymore. // - if (RewriteFrequentPairs) { + if (RewriteFrequentPairs && rc == may_rewrite) { Label rewrite, done; // get next byte @@ -731,7 +743,6 @@ } } - void TemplateTable::istore() { transition(itos, vtos); locals_index(G3_scratch); @@ -2045,30 +2056,21 @@ Register index, size_t index_size) { // Depends on cpCacheOop layout! + Label resolved; - - assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); - __ get_cache_and_index_and_bytecode_at_bcp(Rcache, index, Lbyte_code, byte_no, 1, index_size); - __ cmp(Lbyte_code, (int) bytecode()); // have we resolved this bytecode? - __ br(Assembler::equal, false, Assembler::pt, resolved); - __ delayed()->set((int)bytecode(), O1); - - address entry; - switch (bytecode()) { - case Bytecodes::_getstatic : // fall through - case Bytecodes::_putstatic : // fall through - case Bytecodes::_getfield : // fall through - case Bytecodes::_putfield : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_get_put); break; - case Bytecodes::_invokevirtual : // fall through - case Bytecodes::_invokespecial : // fall through - case Bytecodes::_invokestatic : // fall through - case Bytecodes::_invokeinterface: entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invoke); break; - case Bytecodes::_invokehandle : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokehandle); break; - case Bytecodes::_invokedynamic : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokedynamic); break; - default: - fatal(err_msg("unexpected bytecode: %s", Bytecodes::name(bytecode()))); - break; + Bytecodes::Code code = bytecode(); + switch (code) { + case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break; + case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break; } + + assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); + __ get_cache_and_index_and_bytecode_at_bcp(Rcache, index, Lbyte_code, byte_no, 1, index_size); + __ cmp(Lbyte_code, code); // have we resolved this bytecode? + __ br(Assembler::equal, false, Assembler::pt, resolved); + __ delayed()->set(code, O1); + + address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache); // first time invocation - must resolve first __ call_VM(noreg, entry, O1); // Update registers with resolved info @@ -2183,7 +2185,7 @@ } } -void TemplateTable::getfield_or_static(int byte_no, bool is_static) { +void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteControl rc) { transition(vtos, vtos); Register Rcache = G3_scratch; @@ -2231,7 +2233,7 @@ __ load_heap_oop(Rclass, Roffset, Otos_i); __ verify_oop(Otos_i); __ push(atos); - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_agetfield, G3_scratch, G4_scratch); } __ ba(checkVolatile); @@ -2246,7 +2248,7 @@ // itos __ ld(Rclass, Roffset, Otos_i); __ push(itos); - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_igetfield, G3_scratch, G4_scratch); } __ ba(checkVolatile); @@ -2262,7 +2264,7 @@ // load must be atomic __ ld_long(Rclass, Roffset, Otos_l); __ push(ltos); - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_lgetfield, G3_scratch, G4_scratch); } __ ba(checkVolatile); @@ -2277,7 +2279,7 @@ // btos __ ldsb(Rclass, Roffset, Otos_i); __ push(itos); - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_bgetfield, G3_scratch, G4_scratch); } __ ba(checkVolatile); @@ -2292,7 +2294,7 @@ // ctos __ lduh(Rclass, Roffset, Otos_i); __ push(itos); - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_cgetfield, G3_scratch, G4_scratch); } __ ba(checkVolatile); @@ -2307,7 +2309,7 @@ // stos __ ldsh(Rclass, Roffset, Otos_i); __ push(itos); - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_sgetfield, G3_scratch, G4_scratch); } __ ba(checkVolatile); @@ -2323,7 +2325,7 @@ // ftos __ ldf(FloatRegisterImpl::S, Rclass, Roffset, Ftos_f); __ push(ftos); - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_fgetfield, G3_scratch, G4_scratch); } __ ba(checkVolatile); @@ -2335,7 +2337,7 @@ // dtos __ ldf(FloatRegisterImpl::D, Rclass, Roffset, Ftos_d); __ push(dtos); - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_dgetfield, G3_scratch, G4_scratch); } @@ -2350,16 +2352,18 @@ __ bind(exit); } - void TemplateTable::getfield(int byte_no) { getfield_or_static(byte_no, false); } +void TemplateTable::nofast_getfield(int byte_no) { + getfield_or_static(byte_no, false, may_not_rewrite); +} + void TemplateTable::getstatic(int byte_no) { getfield_or_static(byte_no, true); } - void TemplateTable::fast_accessfield(TosState state) { transition(atos, state); Register Rcache = G3_scratch; @@ -2544,7 +2548,7 @@ __ verify_oop(r); } -void TemplateTable::putfield_or_static(int byte_no, bool is_static) { +void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteControl rc) { transition(vtos, vtos); Register Rcache = G3_scratch; Register index = G4_scratch; @@ -2620,7 +2624,7 @@ __ pop_i(); pop_and_check_object(Rclass); __ st(Otos_i, Rclass, Roffset); - patch_bytecode(Bytecodes::_fast_iputfield, G3_scratch, G4_scratch, true, byte_no); + if (rc == may_rewrite) patch_bytecode(Bytecodes::_fast_iputfield, G3_scratch, G4_scratch, true, byte_no); __ ba(checkVolatile); __ delayed()->tst(Lscratch); } @@ -2636,7 +2640,7 @@ pop_and_check_object(Rclass); __ verify_oop(Otos_i); do_oop_store(_masm, Rclass, Roffset, 0, Otos_i, G1_scratch, _bs->kind(), false); - patch_bytecode(Bytecodes::_fast_aputfield, G3_scratch, G4_scratch, true, byte_no); + if (rc == may_rewrite) patch_bytecode(Bytecodes::_fast_aputfield, G3_scratch, G4_scratch, true, byte_no); __ ba(checkVolatile); __ delayed()->tst(Lscratch); } @@ -2653,7 +2657,7 @@ __ pop_i(); if (!is_static) pop_and_check_object(Rclass); __ stb(Otos_i, Rclass, Roffset); - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_bputfield, G3_scratch, G4_scratch, true, byte_no); } __ ba(checkVolatile); @@ -2670,7 +2674,7 @@ __ pop_l(); if (!is_static) pop_and_check_object(Rclass); __ st_long(Otos_l, Rclass, Roffset); - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_lputfield, G3_scratch, G4_scratch, true, byte_no); } __ ba(checkVolatile); @@ -2687,7 +2691,7 @@ __ pop_i(); if (!is_static) pop_and_check_object(Rclass); __ sth(Otos_i, Rclass, Roffset); - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_cputfield, G3_scratch, G4_scratch, true, byte_no); } __ ba(checkVolatile); @@ -2704,7 +2708,7 @@ __ pop_i(); if (!is_static) pop_and_check_object(Rclass); __ sth(Otos_i, Rclass, Roffset); - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_sputfield, G3_scratch, G4_scratch, true, byte_no); } __ ba(checkVolatile); @@ -2721,7 +2725,7 @@ __ pop_f(); if (!is_static) pop_and_check_object(Rclass); __ stf(FloatRegisterImpl::S, Ftos_f, Rclass, Roffset); - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_fputfield, G3_scratch, G4_scratch, true, byte_no); } __ ba(checkVolatile); @@ -2735,7 +2739,7 @@ __ pop_d(); if (!is_static) pop_and_check_object(Rclass); __ stf(FloatRegisterImpl::D, Ftos_d, Rclass, Roffset); - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_dputfield, G3_scratch, G4_scratch, true, byte_no); } } @@ -2809,16 +2813,18 @@ } } - void TemplateTable::putfield(int byte_no) { putfield_or_static(byte_no, false); } +void TemplateTable::nofast_putfield(int byte_no) { + putfield_or_static(byte_no, false, may_not_rewrite); +} + void TemplateTable::putstatic(int byte_no) { putfield_or_static(byte_no, true); } - void TemplateTable::fast_xaccess(TosState state) { transition(vtos, state); Register Rcache = G3_scratch; @@ -2971,7 +2977,9 @@ __ br(Assembler::zero, false, Assembler::pt, notFinal); __ delayed()->and3(Rret, 0xFF, G4_scratch); // gets number of parameters - patch_bytecode(Bytecodes::_fast_invokevfinal, Rscratch, Rtemp); + if (RewriteBytecodes && !UseSharedSpaces) { + patch_bytecode(Bytecodes::_fast_invokevfinal, Rscratch, Rtemp); + } invokevfinal_helper(Rscratch, Rret); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ int VM_Version::_features = VM_Version::unknown_m; const char* VM_Version::_features_str = ""; -unsigned int VM_Version::_L2_cache_line_size = 0; +unsigned int VM_Version::_L2_data_cache_line_size = 0; void VM_Version::initialize() { _features = determine_features(); @@ -356,10 +356,17 @@ (cache_line_size > ContendedPaddingWidth)) ContendedPaddingWidth = cache_line_size; + // This machine does not allow unaligned memory accesses + if (UseUnalignedAccesses) { + if (!FLAG_IS_DEFAULT(UseUnalignedAccesses)) + warning("Unaligned memory access is not available on this CPU"); + FLAG_SET_DEFAULT(UseUnalignedAccesses, false); + } + #ifndef PRODUCT if (PrintMiscellaneous && Verbose) { tty->print_cr("L1 data cache line size: %u", L1_data_cache_line_size()); - tty->print_cr("L2 cache line size: %u", L2_cache_line_size()); + tty->print_cr("L2 data cache line size: %u", L2_data_cache_line_size()); tty->print("Allocation"); if (AllocatePrefetchStyle <= 0) { tty->print_cr(": no prefetching"); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp Thu May 07 20:51:12 2015 -0700 @@ -96,8 +96,8 @@ static int _features; static const char* _features_str; - static unsigned int _L2_cache_line_size; - static unsigned int L2_cache_line_size() { return _L2_cache_line_size; } + static unsigned int _L2_data_cache_line_size; + static unsigned int L2_data_cache_line_size() { return _L2_data_cache_line_size; } static void print_features(); static int determine_features(); @@ -171,7 +171,7 @@ static const char* cpu_features() { return _features_str; } // default prefetch block size on sparc - static intx prefetch_data_size() { return L2_cache_line_size(); } + static intx prefetch_data_size() { return L2_data_cache_line_size(); } // Prefetch static intx prefetch_copy_interval_in_bytes() { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/assembler_x86.cpp --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp Thu May 07 20:51:12 2015 -0700 @@ -3359,6 +3359,20 @@ // Integer vector arithmetic +void Assembler::vphaddw(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) { + assert(VM_Version::supports_avx() && !vector256 || VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2"); + int encode = vex_prefix_and_encode(dst, nds, src, VEX_SIMD_66, vector256, VEX_OPCODE_0F_38); + emit_int8(0x01); + emit_int8((unsigned char)(0xC0 | encode)); +} + +void Assembler::vphaddd(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) { + assert(VM_Version::supports_avx() && !vector256 || VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2"); + int encode = vex_prefix_and_encode(dst, nds, src, VEX_SIMD_66, vector256, VEX_OPCODE_0F_38); + emit_int8(0x02); + emit_int8((unsigned char)(0xC0 | encode)); +} + void Assembler::paddb(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); emit_simd_arith(0xFC, dst, src, VEX_SIMD_66); @@ -3379,6 +3393,20 @@ emit_simd_arith(0xD4, dst, src, VEX_SIMD_66); } +void Assembler::phaddw(XMMRegister dst, XMMRegister src) { + NOT_LP64(assert(VM_Version::supports_sse3(), "")); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38); + emit_int8(0x01); + emit_int8((unsigned char)(0xC0 | encode)); +} + +void Assembler::phaddd(XMMRegister dst, XMMRegister src) { + NOT_LP64(assert(VM_Version::supports_sse3(), "")); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38); + emit_int8(0x02); + emit_int8((unsigned char)(0xC0 | encode)); +} + void Assembler::vpaddb(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) { assert(VM_Version::supports_avx() && !vector256 || VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2"); emit_vex_arith(0xFC, dst, nds, src, VEX_SIMD_66, vector256); @@ -3804,6 +3832,17 @@ emit_int8(0x01); } +void Assembler::vextractf128h(XMMRegister dst, XMMRegister src) { + assert(VM_Version::supports_avx(), ""); + bool vector256 = true; + int encode = vex_prefix_and_encode(src, xnoreg, dst, VEX_SIMD_66, vector256, VEX_OPCODE_0F_3A); + emit_int8(0x19); + emit_int8((unsigned char)(0xC0 | encode)); + // 0x00 - insert into lower 128 bits + // 0x01 - insert into upper 128 bits + emit_int8(0x01); +} + void Assembler::vextractf128h(Address dst, XMMRegister src) { assert(VM_Version::supports_avx(), ""); InstructionMark im(this); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/assembler_x86.hpp --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp Thu May 07 20:51:12 2015 -0700 @@ -142,8 +142,10 @@ #endif // _LP64 -// JSR 292 fixed register usages: -REGISTER_DECLARATION(Register, rbp_mh_SP_save, rbp); +// JSR 292 +// On x86, the SP does not have to be saved when invoking method handle intrinsics +// or compiled lambda forms. We indicate that by setting rbp_mh_SP_save to noreg. +REGISTER_DECLARATION(Register, rbp_mh_SP_save, noreg); // Address is an abstraction used to represent a memory location // using any of the amd64 addressing modes with one object. @@ -1777,6 +1779,12 @@ void vxorpd(XMMRegister dst, XMMRegister nds, Address src, bool vector256); void vxorps(XMMRegister dst, XMMRegister nds, Address src, bool vector256); + // Add horizontal packed integers + void vphaddw(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256); + void vphaddd(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256); + void phaddw(XMMRegister dst, XMMRegister src); + void phaddd(XMMRegister dst, XMMRegister src); + // Add packed integers void paddb(XMMRegister dst, XMMRegister src); void paddw(XMMRegister dst, XMMRegister src); @@ -1869,6 +1877,7 @@ // Copy low 128bit into high 128bit of YMM registers. void vinsertf128h(XMMRegister dst, XMMRegister nds, XMMRegister src); void vinserti128h(XMMRegister dst, XMMRegister nds, XMMRegister src); + void vextractf128h(XMMRegister dst, XMMRegister src); // Load/store high 128bit of YMM registers which does not destroy other half. void vinsertf128h(XMMRegister dst, Address src); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/c1_FrameMap_x86.cpp --- a/hotspot/src/cpu/x86/vm/c1_FrameMap_x86.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/c1_FrameMap_x86.cpp Thu May 07 20:51:12 2015 -0700 @@ -343,14 +343,13 @@ return FrameMap::rsp_opr; } - // JSR 292 +// On x86, there is no need to save the SP, because neither +// method handle intrinsics, nor compiled lambda forms modify it. LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() { - assert(rbp == rbp_mh_SP_save, "must be same register"); - return rbp_opr; + return LIR_OprFact::illegalOpr; } - bool FrameMap::validate_frame() { return true; } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp --- a/hotspot/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp Thu May 07 20:51:12 2015 -0700 @@ -360,6 +360,9 @@ generate_stack_overflow_check(bang_size_in_bytes); push(rbp); + if (PreserveFramePointer) { + mov(rbp, rsp); + } #ifdef TIERED // c2 leaves fpu stack dirty. Clean it on entry if (UseSSE < 2 ) { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp --- a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp Thu May 07 20:51:12 2015 -0700 @@ -754,14 +754,9 @@ // WIN64_ONLY: No need to add frame::arg_reg_save_area_bytes to SP // since we do a leave anyway. - // Pop the return address since we are possibly changing SP (restoring from BP). + // Pop the return address. __ leave(); __ pop(rcx); - - // Restore SP from BP if the exception PC is a method handle call site. - NOT_LP64(__ get_thread(thread);) - __ cmpl(Address(thread, JavaThread::is_method_handle_return_offset()), 0); - __ cmovptr(Assembler::notEqual, rsp, rbp_mh_SP_save); __ jmp(rcx); // jump to exception handler break; default: ShouldNotReachHere(); @@ -832,11 +827,6 @@ // the pop is also necessary to simulate the effect of a ret(0) __ pop(exception_pc); - // Restore SP from BP if the exception PC is a method handle call site. - NOT_LP64(__ get_thread(thread);) - __ cmpl(Address(thread, JavaThread::is_method_handle_return_offset()), 0); - __ cmovptr(Assembler::notEqual, rsp, rbp_mh_SP_save); - // continue at exception handler (return address removed) // note: do *not* remove arguments when unwinding the // activation since the caller assumes having diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/frame_x86.cpp --- a/hotspot/src/cpu/x86/vm/frame_x86.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/frame_x86.cpp Thu May 07 20:51:12 2015 -0700 @@ -224,7 +224,8 @@ if (sender_blob->is_nmethod()) { nmethod* nm = sender_blob->as_nmethod_or_null(); if (nm != NULL) { - if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc)) { + if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc) || + nm->method()->is_method_handle_intrinsic()) { return false; } } @@ -391,10 +392,9 @@ // frame::verify_deopt_original_pc // // Verifies the calculated original PC of a deoptimization PC for the -// given unextended SP. The unextended SP might also be the saved SP -// for MethodHandle call sites. +// given unextended SP. #ifdef ASSERT -void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return) { +void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp) { frame fr; // This is ugly but it's better than to change {get,set}_original_pc @@ -404,33 +404,23 @@ address original_pc = nm->get_original_pc(&fr); assert(nm->insts_contains(original_pc), "original PC must be in nmethod"); - assert(nm->is_method_handle_return(original_pc) == is_method_handle_return, "must be"); } #endif //------------------------------------------------------------------------------ // frame::adjust_unextended_sp void frame::adjust_unextended_sp() { - // If we are returning to a compiled MethodHandle call site, the - // saved_fp will in fact be a saved value of the unextended SP. The - // simplest way to tell whether we are returning to such a call site - // is as follows: + // On x86, sites calling method handle intrinsics and lambda forms are treated + // as any other call site. Therefore, no special action is needed when we are + // returning to any of these call sites. nmethod* sender_nm = (_cb == NULL) ? NULL : _cb->as_nmethod_or_null(); if (sender_nm != NULL) { - // If the sender PC is a deoptimization point, get the original - // PC. For MethodHandle call site the unextended_sp is stored in - // saved_fp. - if (sender_nm->is_deopt_mh_entry(_pc)) { - DEBUG_ONLY(verify_deopt_mh_original_pc(sender_nm, _fp)); - _unextended_sp = _fp; - } - else if (sender_nm->is_deopt_entry(_pc)) { + // If the sender PC is a deoptimization point, get the original PC. + if (sender_nm->is_deopt_entry(_pc) || + sender_nm->is_deopt_mh_entry(_pc)) { DEBUG_ONLY(verify_deopt_original_pc(sender_nm, _unextended_sp)); } - else if (sender_nm->is_method_handle_return(_pc)) { - _unextended_sp = _fp; - } } } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/frame_x86.hpp --- a/hotspot/src/cpu/x86/vm/frame_x86.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/frame_x86.hpp Thu May 07 20:51:12 2015 -0700 @@ -76,11 +76,11 @@ // [locals and parameters ] // <- sender sp -// [1] When the c++ interpreter calls a new method it returns to the frame +// [1] When the C++ interpreter calls a new method it returns to the frame // manager which allocates a new frame on the stack. In that case there // is no real callee of this newly allocated frame. The frame manager is -// aware of the additional frame(s) and will pop them as nested calls -// complete. Howevers tTo make it look good in the debugger the frame +// aware of the additional frame(s) and will pop them as nested calls +// complete. However, to make it look good in the debugger the frame // manager actually installs a dummy pc pointing to RecursiveInterpreterActivation // with a fake interpreter_state* parameter to make it easy to debug // nested calls. @@ -88,7 +88,7 @@ // Note that contrary to the layout for the assembly interpreter the // expression stack allocated for the C++ interpreter is full sized. // However this is not as bad as it seems as the interpreter frame_manager -// will truncate the unused space on succesive method calls. +// will truncate the unused space on successive method calls. // // ------------------------------ C++ interpreter ---------------------------------------- @@ -167,10 +167,7 @@ #ifdef ASSERT // Used in frame::sender_for_{interpreter,compiled}_frame - static void verify_deopt_original_pc( nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return = false); - static void verify_deopt_mh_original_pc(nmethod* nm, intptr_t* unextended_sp) { - verify_deopt_original_pc(nm, unextended_sp, true); - } + static void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp); #endif public: diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/frame_x86.inline.hpp --- a/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -94,7 +94,7 @@ // find_blob call. This is also why we can have no asserts on the validity // of the pc we find here. AsyncGetCallTrace -> pd_get_top_frame_for_signal_handler // -> pd_last_frame should use a specialized version of pd_last_frame which could - // call a specilaized frame constructor instead of this one. + // call a specialized frame constructor instead of this one. // Then we could use the assert below. However this assert is of somewhat dubious // value. // assert(_pc != NULL, "no pc?"); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/globalDefinitions_x86.hpp --- a/hotspot/src/cpu/x86/vm/globalDefinitions_x86.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/globalDefinitions_x86.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,4 +58,9 @@ #endif #endif +#if defined(COMPILER2) && !defined(JAVASE_EMBEDDED) +// Include Restricted Transactional Memory lock eliding optimization +#define INCLUDE_RTM_OPT 1 +#endif + #endif // CPU_X86_VM_GLOBALDEFINITIONS_X86_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/globals_x86.hpp --- a/hotspot/src/cpu/x86/vm/globals_x86.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/globals_x86.hpp Thu May 07 20:51:12 2015 -0700 @@ -82,14 +82,13 @@ define_pd_global(uintx, TypeProfileLevel, 111); +define_pd_global(bool, PreserveFramePointer, false); + #define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \ \ develop(bool, IEEEPrecision, true, \ "Enables IEEE precision (for INTEL only)") \ \ - product(intx, FenceInstruction, 0, \ - "(Unsafe,Unstable) Experimental") \ - \ product(bool, UseStoreImmI16, true, \ "Use store immediate 16-bits value instruction on x86") \ \ diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Thu May 07 20:51:12 2015 -0700 @@ -1958,6 +1958,11 @@ // Programmer's Guide and Specification" claims that an object locked by jni_monitorenter // should not be unlocked by "normal" java-level locking and vice-versa. The specification // doesn't specify what will occur if a program engages in such mixed-mode locking, however. +// Arguably given that the spec legislates the JNI case as undefined our implementation +// could reasonably *avoid* checking owner in Fast_Unlock(). +// In the interest of performance we elide m->Owner==Self check in unlock. +// A perfectly viable alternative is to elide the owner check except when +// Xcheck:jni is enabled. void MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register tmpReg, bool use_rtm) { assert(boxReg == rax, ""); @@ -1966,24 +1971,6 @@ if (EmitSync & 4) { // Disable - inhibit all inlining. Force control through the slow-path cmpptr (rsp, 0); - } else - if (EmitSync & 8) { - Label DONE_LABEL; - if (UseBiasedLocking) { - biased_locking_exit(objReg, tmpReg, DONE_LABEL); - } - // Classic stack-locking code ... - // Check whether the displaced header is 0 - //(=> recursive unlock) - movptr(tmpReg, Address(boxReg, 0)); - testptr(tmpReg, tmpReg); - jccb(Assembler::zero, DONE_LABEL); - // If not recursive lock, reset the header to displaced header - if (os::is_MP()) { - lock(); - } - cmpxchgptr(tmpReg, Address(objReg, 0)); // Uses RAX which is box - bind(DONE_LABEL); } else { Label DONE_LABEL, Stacked, CheckSucc; @@ -2060,9 +2047,9 @@ // the number of loads below (currently 4) to just 2 or 3. // Refer to the comments in synchronizer.cpp. // In practice the chain of fetches doesn't seem to impact performance, however. + xorptr(boxReg, boxReg); if ((EmitSync & 65536) == 0 && (EmitSync & 256)) { // Attempt to reduce branch density - AMD's branch predictor. - xorptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); @@ -2070,7 +2057,6 @@ movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD); jmpb (DONE_LABEL); } else { - xorptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); jccb (Assembler::notZero, DONE_LABEL); movptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); @@ -2093,10 +2079,8 @@ bind (CheckSucc); // Optional pre-test ... it's safe to elide this - if ((EmitSync & 16) == 0) { - cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), (int32_t)NULL_WORD); - jccb (Assembler::zero, LGoSlowPath); - } + cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), (int32_t)NULL_WORD); + jccb(Assembler::zero, LGoSlowPath); // We have a classic Dekker-style idiom: // ST m->_owner = 0 ; MEMBAR; LD m->_succ @@ -2109,7 +2093,8 @@ // In older IA32 processors MFENCE is slower than lock:add or xchg // particularly if the write-buffer is full as might be the case if // if stores closely precede the fence or fence-equivalent instruction. - // In more modern implementations MFENCE appears faster, however. + // See https://blogs.oracle.com/dave/entry/instruction_selection_for_volatile_fences + // as the situation has changed with Nehalem and Shanghai. // (3) In lieu of an explicit fence, use lock:addl to the top-of-stack // The $lines underlying the top-of-stack should be in M-state. // The locked add instruction is serializing, of course. @@ -2126,11 +2111,7 @@ movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD); if (os::is_MP()) { - if (VM_Version::supports_sse2() && 1 == FenceInstruction) { - mfence(); - } else { - lock (); addptr(Address(rsp, 0), 0); - } + lock(); addptr(Address(rsp, 0), 0); } // Ratify _succ remains non-null cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), 0); @@ -2179,8 +2160,17 @@ } #else // _LP64 // It's inflated - movptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); - xorptr(boxReg, r15_thread); + if (EmitSync & 1024) { + // Emit code to check that _owner == Self + // We could fold the _owner test into subsequent code more efficiently + // than using a stand-alone check, but since _owner checking is off by + // default we don't bother. We also might consider predicating the + // _owner==Self check on Xcheck:jni or running on a debug build. + movptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); + xorptr(boxReg, r15_thread); + } else { + xorptr(boxReg, boxReg); + } orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); jccb (Assembler::notZero, DONE_LABEL); movptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); @@ -2190,23 +2180,51 @@ jmpb (DONE_LABEL); if ((EmitSync & 65536) == 0) { + // Try to avoid passing control into the slow_path ... Label LSuccess, LGoSlowPath ; bind (CheckSucc); + + // The following optional optimization can be elided if necessary + // Effectively: if (succ == null) goto SlowPath + // The code reduces the window for a race, however, + // and thus benefits performance. cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), (int32_t)NULL_WORD); jccb (Assembler::zero, LGoSlowPath); - // I'd much rather use lock:andl m->_owner, 0 as it's faster than the - // the explicit ST;MEMBAR combination, but masm doesn't currently support - // "ANDQ M,IMM". Don't use MFENCE here. lock:add to TOS, xchg, etc - // are all faster when the write buffer is populated. - movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), (int32_t)NULL_WORD); - if (os::is_MP()) { - lock (); addl (Address(rsp, 0), 0); + if ((EmitSync & 16) && os::is_MP()) { + orptr(boxReg, boxReg); + xchgptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); + } else { + movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), (int32_t)NULL_WORD); + if (os::is_MP()) { + // Memory barrier/fence + // Dekker pivot point -- fulcrum : ST Owner; MEMBAR; LD Succ + // Instead of MFENCE we use a dummy locked add of 0 to the top-of-stack. + // This is faster on Nehalem and AMD Shanghai/Barcelona. + // See https://blogs.oracle.com/dave/entry/instruction_selection_for_volatile_fences + // We might also restructure (ST Owner=0;barrier;LD _Succ) to + // (mov box,0; xchgq box, &m->Owner; LD _succ) . + lock(); addl(Address(rsp, 0), 0); + } } cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), (int32_t)NULL_WORD); jccb (Assembler::notZero, LSuccess); - movptr (boxReg, (int32_t)NULL_WORD); // box is really EAX + // Rare inopportune interleaving - race. + // The successor vanished in the small window above. + // The lock is contended -- (cxq|EntryList) != null -- and there's no apparent successor. + // We need to ensure progress and succession. + // Try to reacquire the lock. + // If that fails then the new owner is responsible for succession and this + // thread needs to take no further action and can exit via the fast path (success). + // If the re-acquire succeeds then pass control into the slow path. + // As implemented, this latter mode is horrible because we generated more + // coherence traffic on the lock *and* artifically extended the critical section + // length while by virtue of passing control into the slow path. + + // box is really RAX -- the following CMPXCHG depends on that binding + // cmpxchg R,[M] is equivalent to rax = CAS(M,rax,R) + movptr(boxReg, (int32_t)NULL_WORD); if (os::is_MP()) { lock(); } cmpxchgptr(r15_thread, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); jccb (Assembler::notEqual, LSuccess); @@ -2231,10 +2249,6 @@ } #endif bind(DONE_LABEL); - // Avoid branch to branch on AMD processors - if (EmitSync & 32768) { - nop(); - } } } #endif // COMPILER2 @@ -6090,6 +6104,10 @@ // We always push rbp, so that on return to interpreter rbp, will be // restored correctly and we can correct the stack. push(rbp); + // Save caller's stack pointer into RBP if the frame pointer is preserved. + if (PreserveFramePointer) { + mov(rbp, rsp); + } // Remove word for ebp framesize -= wordSize; @@ -6104,6 +6122,11 @@ // Save RBP register now. framesize -= wordSize; movptr(Address(rsp, framesize), rbp); + // Save caller's stack pointer into RBP if the frame pointer is preserved. + if (PreserveFramePointer) { + movptr(rbp, rsp); + addptr(rbp, framesize + wordSize); + } } if (VerifyStackAtCalls) { // Majik cookie to verify stack depth @@ -6657,7 +6680,7 @@ subl(cnt2, stride2); jccb(Assembler::notZero, COMPARE_WIDE_VECTORS_LOOP); // clean upper bits of YMM registers - vzeroupper(); + vpxor(vec1, vec1); // compare wide vectors tail bind(COMPARE_WIDE_TAIL); @@ -6672,7 +6695,7 @@ // Identifies the mismatching (higher or lower)16-bytes in the 32-byte vectors. bind(VECTOR_NOT_EQUAL); // clean upper bits of YMM registers - vzeroupper(); + vpxor(vec1, vec1); lea(str1, Address(str1, result, scale)); lea(str2, Address(str2, result, scale)); jmp(COMPARE_16_CHARS); @@ -6931,7 +6954,8 @@ bind(DONE); if (UseAVX >= 2) { // clean upper bits of YMM registers - vzeroupper(); + vpxor(vec1, vec1); + vpxor(vec2, vec2); } } @@ -7065,7 +7089,8 @@ BIND(L_check_fill_8_bytes); // clean upper bits of YMM registers - vzeroupper(); + movdl(xtmp, value); + pshufd(xtmp, xtmp, 0); } else { // Fill 32-byte chunks pshufd(xtmp, xtmp, 0); @@ -7228,7 +7253,11 @@ bind(L_copy_16_chars_exit); if (UseAVX >= 2) { // clean upper bits of YMM registers - vzeroupper(); + vpxor(tmp2Reg, tmp2Reg); + vpxor(tmp3Reg, tmp3Reg); + vpxor(tmp4Reg, tmp4Reg); + movdl(tmp1Reg, tmp5); + pshufd(tmp1Reg, tmp1Reg, 0); } subptr(len, 8); jccb(Assembler::greater, L_copy_8_chars_exit); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/methodHandles_x86.cpp --- a/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp Thu May 07 20:51:12 2015 -0700 @@ -374,7 +374,7 @@ // member_reg - MemberName that was the trailing argument // temp1_recv_klass - klass of stacked receiver, if needed // rsi/r13 - interpreter linkage (if interpreted) - // rcx, rdx, rsi, rdi, r8, r8 - compiler arguments (if compiled) + // rcx, rdx, rsi, rdi, r8 - compiler arguments (if compiled) Label L_incompatible_class_change_error; switch (iid) { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/rtmLocking.cpp --- a/hotspot/src/cpu/x86/vm/rtmLocking.cpp Thu May 07 10:19:31 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2014, 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.inline.hpp" -#include "runtime/task.hpp" -#include "runtime/rtmLocking.hpp" - -// One-shot PeriodicTask subclass for enabling RTM locking -uintx RTMLockingCounters::_calculation_flag = 0; - -class RTMLockingCalculationTask : public PeriodicTask { - public: - RTMLockingCalculationTask(size_t interval_time) : PeriodicTask(interval_time){ } - - virtual void task() { - RTMLockingCounters::_calculation_flag = 1; - // Reclaim our storage and disenroll ourself - delete this; - } -}; - -void RTMLockingCounters::init() { - if (UseRTMLocking && RTMLockingCalculationDelay > 0) { - RTMLockingCalculationTask* task = new RTMLockingCalculationTask(RTMLockingCalculationDelay); - task->enroll(); - } else { - _calculation_flag = 1; - } -} - -//------------------------------print_on------------------------------- -void RTMLockingCounters::print_on(outputStream* st) { - tty->print_cr("# rtm locks total (estimated): " UINTX_FORMAT, _total_count * RTMTotalCountIncrRate); - tty->print_cr("# rtm lock aborts : " UINTX_FORMAT, _abort_count); - for (int i = 0; i < ABORT_STATUS_LIMIT; i++) { - tty->print_cr("# rtm lock aborts %d: " UINTX_FORMAT, i, _abortX_count[i]); - } -} diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/runtime_x86_32.cpp --- a/hotspot/src/cpu/x86/vm/runtime_x86_32.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/runtime_x86_32.cpp Thu May 07 20:51:12 2015 -0700 @@ -126,10 +126,6 @@ // rax: exception handler for given - // Restore SP from BP if the exception PC is a MethodHandle call site. - __ cmpl(Address(rcx, JavaThread::is_method_handle_return_offset()), 0); - __ cmovptr(Assembler::notEqual, rsp, rbp_mh_SP_save); - // We have a handler in rax, (could be deopt blob) // rdx - throwing pc, deopt blob will need it. diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2343,12 +2343,14 @@ // should be a peal // +wordSize because of the push above + // args are (oop obj, BasicLock* lock, JavaThread* thread) + __ push(thread); __ lea(rax, Address(rbp, lock_slot_rbp_offset)); __ push(rax); __ push(obj_reg); __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_unlocking_C))); - __ addptr(rsp, 2*wordSize); + __ addptr(rsp, 3*wordSize); #ifdef ASSERT { Label L; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2581,6 +2581,7 @@ __ lea(c_rarg1, Address(rsp, lock_slot_offset * VMRegImpl::stack_slot_size)); __ mov(c_rarg0, obj_reg); + __ mov(c_rarg2, r15_thread); __ mov(r12, rsp); // remember sp __ subptr(rsp, frame::arg_reg_save_area_bytes); // windows __ andptr(rsp, -16); // align stack as required by ABI @@ -2590,6 +2591,7 @@ __ movptr(rbx, Address(r15_thread, in_bytes(Thread::pending_exception_offset()))); __ movptr(Address(r15_thread, in_bytes(Thread::pending_exception_offset())), (int32_t)NULL_WORD); + // args are (oop obj, BasicLock* lock, JavaThread* thread) __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_unlocking_C))); __ mov(rsp, r12); // restore sp __ reinit_heapbase(); @@ -3393,8 +3395,8 @@ // Save callee-saved registers. See x86_64.ad. - // rbp is an implicitly saved callee saved register (i.e. the calling - // convention will save restore it in prolog/epilog) Other than that + // rbp is an implicitly saved callee saved register (i.e., the calling + // convention will save/restore it in the prolog/epilog). Other than that // there are no callee save registers now that adapter frames are gone. __ movptr(Address(rsp, SimpleRuntimeFrame::rbp_off << LogBytesPerInt), rbp); @@ -3436,9 +3438,9 @@ // Restore callee-saved registers - // rbp is an implicitly saved callee saved register (i.e. the calling + // rbp is an implicitly saved callee-saved register (i.e., the calling // convention will save restore it in prolog/epilog) Other than that - // there are no callee save registers no that adapter frames are gone. + // there are no callee save registers now that adapter frames are gone. __ movptr(rbp, Address(rsp, SimpleRuntimeFrame::rbp_off << LogBytesPerInt)); @@ -3447,10 +3449,6 @@ // rax: exception handler - // Restore SP from BP if the exception PC is a MethodHandle call site. - __ cmpl(Address(r15_thread, JavaThread::is_method_handle_return_offset()), 0); - __ cmovptr(Assembler::notEqual, rsp, rbp_mh_SP_save); - // We have a handler in rax (could be deopt blob). __ mov(r8, rax); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp Thu May 07 20:51:12 2015 -0700 @@ -835,7 +835,8 @@ if (UseUnalignedLoadStores && (UseAVX >= 2)) { // clean upper bits of YMM registers - __ vzeroupper(); + __ vpxor(xmm0, xmm0); + __ vpxor(xmm1, xmm1); } __ addl(qword_count, 8); __ jccb(Assembler::zero, L_exit); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp Thu May 07 20:51:12 2015 -0700 @@ -1352,7 +1352,8 @@ __ BIND(L_end); if (UseAVX >= 2) { // clean upper bits of YMM registers - __ vzeroupper(); + __ vpxor(xmm0, xmm0); + __ vpxor(xmm1, xmm1); } } else { // Copy 32-bytes per iteration @@ -1429,7 +1430,8 @@ __ BIND(L_end); if (UseAVX >= 2) { // clean upper bits of YMM registers - __ vzeroupper(); + __ vpxor(xmm0, xmm0); + __ vpxor(xmm1, xmm1); } } else { // Copy 32-bytes per iteration diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/templateTable_x86.cpp --- a/hotspot/src/cpu/x86/vm/templateTable_x86.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/templateTable_x86.cpp Thu May 07 20:51:12 2015 -0700 @@ -543,8 +543,16 @@ } void TemplateTable::iload() { + iload_internal(); +} + +void TemplateTable::nofast_iload() { + iload_internal(may_not_rewrite); +} + +void TemplateTable::iload_internal(RewriteControl rc) { transition(vtos, itos); - if (RewriteFrequentPairs) { + if (RewriteFrequentPairs && rc == may_rewrite) { Label rewrite, done; const Register bc = LP64_ONLY(c_rarg3) NOT_LP64(rcx); LP64_ONLY(assert(rbx != bc, "register damaged")); @@ -815,6 +823,14 @@ } void TemplateTable::aload_0() { + aload_0_internal(); +} + +void TemplateTable::nofast_aload_0() { + aload_0_internal(may_not_rewrite); +} + +void TemplateTable::aload_0_internal(RewriteControl rc) { transition(vtos, atos); // According to bytecode histograms, the pairs: // @@ -837,7 +853,7 @@ // aload_0, iload_1 // These bytecodes with a small amount of code are most profitable // to rewrite - if (RewriteFrequentPairs) { + if (RewriteFrequentPairs && rc == may_rewrite) { Label rewrite, done; const Register bc = LP64_ONLY(c_rarg3) NOT_LP64(rcx); @@ -2491,29 +2507,21 @@ assert_different_registers(Rcache, index, temp); Label resolved; - assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); - __ get_cache_and_index_and_bytecode_at_bcp(Rcache, index, temp, byte_no, 1, index_size); - __ cmpl(temp, (int) bytecode()); // have we resolved this bytecode? - __ jcc(Assembler::equal, resolved); + + Bytecodes::Code code = bytecode(); + switch (code) { + case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break; + case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break; + } + + assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); + __ get_cache_and_index_and_bytecode_at_bcp(Rcache, index, temp, byte_no, 1, index_size); + __ cmpl(temp, code); // have we resolved this bytecode? + __ jcc(Assembler::equal, resolved); // resolve first time through - address entry; - switch (bytecode()) { - case Bytecodes::_getstatic : // fall through - case Bytecodes::_putstatic : // fall through - case Bytecodes::_getfield : // fall through - case Bytecodes::_putfield : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_get_put); break; - case Bytecodes::_invokevirtual : // fall through - case Bytecodes::_invokespecial : // fall through - case Bytecodes::_invokestatic : // fall through - case Bytecodes::_invokeinterface: entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invoke); break; - case Bytecodes::_invokehandle : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokehandle); break; - case Bytecodes::_invokedynamic : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokedynamic); break; - default: - fatal(err_msg("unexpected bytecode: %s", Bytecodes::name(bytecode()))); - break; - } - __ movl(temp, (int)bytecode()); + address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache); + __ movl(temp, code); __ call_VM(noreg, entry, temp); // Update registers with resolved info __ get_cache_and_index_at_bcp(Rcache, index, 1, index_size); @@ -2628,7 +2636,7 @@ __ verify_oop(r); } -void TemplateTable::getfield_or_static(int byte_no, bool is_static) { +void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteControl rc) { transition(vtos, vtos); const Register cache = rcx; @@ -2660,7 +2668,7 @@ __ load_signed_byte(rax, field); __ push(btos); // Rewrite bytecode to be faster - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_bgetfield, bc, rbx); } __ jmp(Done); @@ -2671,7 +2679,7 @@ // atos __ load_heap_oop(rax, field); __ push(atos); - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_agetfield, bc, rbx); } __ jmp(Done); @@ -2683,7 +2691,7 @@ __ movl(rax, field); __ push(itos); // Rewrite bytecode to be faster - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_igetfield, bc, rbx); } __ jmp(Done); @@ -2695,7 +2703,7 @@ __ load_unsigned_short(rax, field); __ push(ctos); // Rewrite bytecode to be faster - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_cgetfield, bc, rbx); } __ jmp(Done); @@ -2707,7 +2715,7 @@ __ load_signed_short(rax, field); __ push(stos); // Rewrite bytecode to be faster - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_sgetfield, bc, rbx); } __ jmp(Done); @@ -2731,7 +2739,7 @@ __ push(ltos); // Rewrite bytecode to be faster - LP64_ONLY(if (!is_static) patch_bytecode(Bytecodes::_fast_lgetfield, bc, rbx)); + LP64_ONLY(if (!is_static && rc == may_rewrite) patch_bytecode(Bytecodes::_fast_lgetfield, bc, rbx)); __ jmp(Done); __ bind(notLong); @@ -2743,7 +2751,7 @@ NOT_LP64(__ fld_s(field)); __ push(ftos); // Rewrite bytecode to be faster - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_fgetfield, bc, rbx); } __ jmp(Done); @@ -2758,7 +2766,7 @@ NOT_LP64(__ fld_d(field)); __ push(dtos); // Rewrite bytecode to be faster - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_dgetfield, bc, rbx); } #ifdef ASSERT @@ -2779,6 +2787,10 @@ getfield_or_static(byte_no, false); } +void TemplateTable::nofast_getfield(int byte_no) { + getfield_or_static(byte_no, false, may_not_rewrite); +} + void TemplateTable::getstatic(int byte_no) { getfield_or_static(byte_no, true); } @@ -2870,7 +2882,7 @@ } } -void TemplateTable::putfield_or_static(int byte_no, bool is_static) { +void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteControl rc) { transition(vtos, vtos); const Register cache = rcx; @@ -2911,7 +2923,7 @@ __ pop(btos); if (!is_static) pop_and_check_object(obj); __ movb(field, rax); - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_bputfield, bc, rbx, true, byte_no); } __ jmp(Done); @@ -2927,7 +2939,7 @@ if (!is_static) pop_and_check_object(obj); // Store into the field do_oop_store(_masm, field, rax, _bs->kind(), false); - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_aputfield, bc, rbx, true, byte_no); } __ jmp(Done); @@ -2942,7 +2954,7 @@ __ pop(itos); if (!is_static) pop_and_check_object(obj); __ movl(field, rax); - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_iputfield, bc, rbx, true, byte_no); } __ jmp(Done); @@ -2957,7 +2969,7 @@ __ pop(ctos); if (!is_static) pop_and_check_object(obj); __ movw(field, rax); - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_cputfield, bc, rbx, true, byte_no); } __ jmp(Done); @@ -2972,7 +2984,7 @@ __ pop(stos); if (!is_static) pop_and_check_object(obj); __ movw(field, rax); - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_sputfield, bc, rbx, true, byte_no); } __ jmp(Done); @@ -2988,7 +3000,7 @@ __ pop(ltos); if (!is_static) pop_and_check_object(obj); __ movq(field, rax); - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_lputfield, bc, rbx, true, byte_no); } __ jmp(Done); @@ -3035,7 +3047,7 @@ if (!is_static) pop_and_check_object(obj); NOT_LP64( __ fstp_s(field);) LP64_ONLY( __ movflt(field, xmm0);) - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_fputfield, bc, rbx, true, byte_no); } __ jmp(Done); @@ -3053,7 +3065,7 @@ if (!is_static) pop_and_check_object(obj); NOT_LP64( __ fstp_d(field);) LP64_ONLY( __ movdbl(field, xmm0);) - if (!is_static) { + if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_dputfield, bc, rbx, true, byte_no); } } @@ -3079,6 +3091,10 @@ putfield_or_static(byte_no, false); } +void TemplateTable::nofast_putfield(int byte_no) { + putfield_or_static(byte_no, false, may_not_rewrite); +} + void TemplateTable::putstatic(int byte_no) { putfield_or_static(byte_no, true); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/templateTable_x86.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/cpu/x86/vm/templateTable_x86.hpp Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef CPU_X86_VM_TEMPLATETABLE_X86_HPP +#define CPU_X86_VM_TEMPLATETABLE_X86_HPP + + static void prepare_invoke(int byte_no, + Register method, // linked method (or i-klass) + Register index = noreg, // itable index, MethodType, etc. + Register recv = noreg, // if caller wants to see it + Register flags = noreg // if caller wants to test it + ); + static void invokevirtual_helper(Register index, Register recv, + Register flags); + static void volatile_barrier(Assembler::Membar_mask_bits order_constraint); + + // Helpers + static void index_check(Register array, Register index); + static void index_check_without_pop(Register array, Register index); + +#endif // CPU_X86_VM_TEMPLATETABLE_X86_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/templateTable_x86_32.hpp --- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.hpp Thu May 07 10:19:31 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* - * Copyright (c) 1998, 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 CPU_X86_VM_TEMPLATETABLE_X86_32_HPP -#define CPU_X86_VM_TEMPLATETABLE_X86_32_HPP - - static void prepare_invoke(int byte_no, - Register method, // linked method (or i-klass) - Register index = noreg, // itable index, MethodType, etc. - Register recv = noreg, // if caller wants to see it - Register flags = noreg // if caller wants to test it - ); - static void invokevirtual_helper(Register index, Register recv, - Register flags); - static void volatile_barrier(Assembler::Membar_mask_bits order_constraint); - - // Helpers - static void index_check(Register array, Register index); - static void index_check_without_pop(Register array, Register index); - -#endif // CPU_X86_VM_TEMPLATETABLE_X86_32_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/templateTable_x86_64.hpp --- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.hpp Thu May 07 10:19:31 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2003, 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 CPU_X86_VM_TEMPLATETABLE_X86_64_HPP -#define CPU_X86_VM_TEMPLATETABLE_X86_64_HPP - - static void prepare_invoke(int byte_no, - Register method, // linked method (or i-klass) - Register index = noreg, // itable index, MethodType, etc. - Register recv = noreg, // if caller wants to see it - Register flags = noreg // if caller wants to test it - ); - static void invokevirtual_helper(Register index, Register recv, - Register flags); - static void volatile_barrier(Assembler::Membar_mask_bits order_constraint); - - // Helpers - static void index_check(Register array, Register index); - static void index_check_without_pop(Register array, Register index); - -#endif // CPU_X86_VM_TEMPLATETABLE_X86_64_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/vm_version_x86.cpp --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp Thu May 07 20:51:12 2015 -0700 @@ -379,15 +379,6 @@ }; }; - -void VM_Version::get_cpu_info_wrapper() { - get_cpu_info_stub(&_cpuid_info); -} - -#ifndef CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED - #define CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(f) f() -#endif - void VM_Version::get_processor_features() { _cpu = 4; // 486 by default @@ -401,9 +392,7 @@ if (!Use486InstrsOnly) { // Get raw processor info - // Some platforms (like Win*) need a wrapper around here - // in order to properly handle SEGV for YMM registers test. - CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(get_cpu_info_wrapper); + get_cpu_info_stub(&_cpuid_info); assert_is_initialized(); _cpu = extended_cpu_family(); @@ -980,6 +969,11 @@ (cache_line_size > ContendedPaddingWidth)) ContendedPaddingWidth = cache_line_size; + // This machine allows unaligned memory accesses + if (FLAG_IS_DEFAULT(UseUnalignedAccesses)) { + FLAG_SET_DEFAULT(UseUnalignedAccesses, true); + } + #ifndef PRODUCT if (PrintMiscellaneous && Verbose) { tty->print_cr("Logical CPUs per core: %u", diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/x86.ad --- a/hotspot/src/cpu/x86/vm/x86.ad Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/x86.ad Thu May 07 20:51:12 2015 -0700 @@ -490,7 +490,7 @@ class NativeJump; class CallStubImpl { - + //-------------------------------------------------------------- //---< Used for optimization in Compile::shorten_branches >--- //-------------------------------------------------------------- @@ -500,9 +500,9 @@ static uint size_call_trampoline() { return 0; // no call trampolines on this platform } - + // number of relocations needed by a call trampoline stub - static uint reloc_call_trampoline() { + static uint reloc_call_trampoline() { return 0; // no call trampolines on this platform } }; @@ -623,6 +623,22 @@ if ((UseSSE < 4) && (UseAVX < 1)) // only with SSE4_1 or AVX return false; break; + case Op_AddReductionVL: + if (UseAVX < 3) // only EVEX : vector connectivity becomes an issue here + return false; + case Op_AddReductionVI: + if (UseSSE < 3) // requires at least SSE3 + return false; + case Op_MulReductionVI: + if (UseSSE < 4) // requires at least SSE4 + return false; + case Op_AddReductionVF: + case Op_AddReductionVD: + case Op_MulReductionVF: + case Op_MulReductionVD: + if (UseSSE < 1) // requires at least SSE + return false; + break; case Op_CompareAndSwapL: #ifdef _LP64 case Op_CompareAndSwapP: @@ -914,21 +930,6 @@ encode %{ - enc_class preserve_SP %{ - debug_only(int off0 = cbuf.insts_size()); - MacroAssembler _masm(&cbuf); - // RBP is preserved across all calls, even compiled calls. - // Use it to preserve RSP in places where the callee might change the SP. - __ movptr(rbp_mh_SP_save, rsp); - debug_only(int off1 = cbuf.insts_size()); - assert(off1 - off0 == preserve_SP_size(), "correct size prediction"); - %} - - enc_class restore_SP %{ - MacroAssembler _masm(&cbuf); - __ movptr(rsp, rbp_mh_SP_save); - %} - enc_class call_epilog %{ if (VerifyStackAtCalls) { // Check that stack depth is unchanged: find majik cookie on stack @@ -2532,6 +2533,574 @@ ins_pipe( fpu_reg_reg ); %} +// ====================REDUCTION ARITHMETIC======================================= + +instruct rsadd2I_reduction_reg(rRegI dst, rRegI src1, vecD src2, regF tmp, regF tmp2) %{ + predicate(UseSSE > 2 && UseAVX == 0); + match(Set dst (AddReductionVI src1 src2)); + effect(TEMP tmp2, TEMP tmp); + format %{ "movdqu $tmp2,$src2\n\t" + "phaddd $tmp2,$tmp2\n\t" + "movd $tmp,$src1\n\t" + "paddd $tmp,$tmp2\n\t" + "movd $dst,$tmp\t! add reduction2I" %} + ins_encode %{ + __ movdqu($tmp2$$XMMRegister, $src2$$XMMRegister); + __ phaddd($tmp2$$XMMRegister, $tmp2$$XMMRegister); + __ movdl($tmp$$XMMRegister, $src1$$Register); + __ paddd($tmp$$XMMRegister, $tmp2$$XMMRegister); + __ movdl($dst$$Register, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvadd2I_reduction_reg(rRegI dst, rRegI src1, vecD src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (AddReductionVI src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "vphaddd $tmp,$src2,$src2\n\t" + "movd $tmp2,$src1\n\t" + "vpaddd $tmp2,$tmp2,$tmp\n\t" + "movd $dst,$tmp2\t! add reduction2I" %} + ins_encode %{ + __ vphaddd($tmp$$XMMRegister, $src2$$XMMRegister, $src2$$XMMRegister, false); + __ movdl($tmp2$$XMMRegister, $src1$$Register); + __ vpaddd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister, false); + __ movdl($dst$$Register, $tmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rsadd4I_reduction_reg(rRegI dst, rRegI src1, vecX src2, regF tmp, regF tmp2) %{ + predicate(UseSSE > 2 && UseAVX == 0); + match(Set dst (AddReductionVI src1 src2)); + effect(TEMP tmp2, TEMP tmp); + format %{ "movdqu $tmp2,$src2\n\t" + "phaddd $tmp2,$tmp2\n\t" + "phaddd $tmp2,$tmp2\n\t" + "movd $tmp,$src1\n\t" + "paddd $tmp,$tmp2\n\t" + "movd $dst,$tmp\t! add reduction4I" %} + ins_encode %{ + __ movdqu($tmp2$$XMMRegister, $src2$$XMMRegister); + __ phaddd($tmp2$$XMMRegister, $tmp2$$XMMRegister); + __ phaddd($tmp2$$XMMRegister, $tmp2$$XMMRegister); + __ movdl($tmp$$XMMRegister, $src1$$Register); + __ paddd($tmp$$XMMRegister, $tmp2$$XMMRegister); + __ movdl($dst$$Register, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvadd4I_reduction_reg(rRegI dst, rRegI src1, vecX src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (AddReductionVI src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "vphaddd $tmp,$src2,$src2\n\t" + "vphaddd $tmp,$tmp,$tmp2\n\t" + "movd $tmp2,$src1\n\t" + "vpaddd $tmp2,$tmp2,$tmp\n\t" + "movd $dst,$tmp2\t! add reduction4I" %} + ins_encode %{ + __ vphaddd($tmp$$XMMRegister, $src2$$XMMRegister, $src2$$XMMRegister, false); + __ vphaddd($tmp$$XMMRegister, $tmp$$XMMRegister, $tmp2$$XMMRegister, false); + __ movdl($tmp2$$XMMRegister, $src1$$Register); + __ vpaddd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister, false); + __ movdl($dst$$Register, $tmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvadd8I_reduction_reg(rRegI dst, rRegI src1, vecY src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (AddReductionVI src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "vphaddd $tmp,$src2,$src2\n\t" + "vphaddd $tmp,$tmp,$tmp2\n\t" + "vextractf128 $tmp2,$tmp\n\t" + "vpaddd $tmp,$tmp,$tmp2\n\t" + "movd $tmp2,$src1\n\t" + "vpaddd $tmp2,$tmp2,$tmp\n\t" + "movd $dst,$tmp2\t! add reduction8I" %} + ins_encode %{ + __ vphaddd($tmp$$XMMRegister, $src2$$XMMRegister, $src2$$XMMRegister, true); + __ vphaddd($tmp$$XMMRegister, $tmp$$XMMRegister, $tmp2$$XMMRegister, true); + __ vextractf128h($tmp2$$XMMRegister, $tmp$$XMMRegister); + __ vpaddd($tmp$$XMMRegister, $tmp$$XMMRegister, $tmp2$$XMMRegister, false); + __ movdl($tmp2$$XMMRegister, $src1$$Register); + __ vpaddd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister, false); + __ movdl($dst$$Register, $tmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rsadd2F_reduction_reg(regF dst, regF src1, vecD src2, regF tmp, regF tmp2) %{ + predicate(UseSSE >= 1 && UseAVX == 0); + match(Set dst (AddReductionVF src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "movdqu $tmp,$src1\n\t" + "addss $tmp,$src2\n\t" + "pshufd $tmp2,$src2,0x01\n\t" + "addss $tmp,$tmp2\n\t" + "movdqu $dst,$tmp\t! add reduction2F" %} + ins_encode %{ + __ movdqu($tmp$$XMMRegister, $src1$$XMMRegister); + __ addss($tmp$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x01); + __ addss($tmp$$XMMRegister, $tmp2$$XMMRegister); + __ movdqu($dst$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvadd2F_reduction_reg(regF dst, regF src1, vecD src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (AddReductionVF src1 src2)); + effect(TEMP tmp2, TEMP tmp); + format %{ "vaddss $tmp2,$src1,$src2\n\t" + "pshufd $tmp,$src2,0x01\n\t" + "vaddss $dst,$tmp2,$tmp\t! add reduction2F" %} + ins_encode %{ + __ vaddss($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); + __ vaddss($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rsadd4F_reduction_reg(regF dst, regF src1, vecX src2, regF tmp, regF tmp2) %{ + predicate(UseSSE >= 1 && UseAVX == 0); + match(Set dst (AddReductionVF src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "movdqu $tmp,$src1\n\t" + "addss $tmp,$src2\n\t" + "pshufd $tmp2,$src2,0x01\n\t" + "addss $tmp,$tmp2\n\t" + "pshufd $tmp2,$src2,0x02\n\t" + "addss $tmp,$tmp2\n\t" + "pshufd $tmp2,$src2,0x03\n\t" + "addss $tmp,$tmp2\n\t" + "movdqu $dst,$tmp\t! add reduction4F" %} + ins_encode %{ + __ movdqu($tmp$$XMMRegister, $src1$$XMMRegister); + __ addss($tmp$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x01); + __ addss($tmp$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x02); + __ addss($tmp$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x03); + __ addss($tmp$$XMMRegister, $tmp2$$XMMRegister); + __ movdqu($dst$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvadd4F_reduction_reg(regF dst, regF src1, vecX src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (AddReductionVF src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "vaddss $tmp2,$src1,$src2\n\t" + "pshufd $tmp,$src2,0x01\n\t" + "vaddss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$src2,0x02\n\t" + "vaddss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$src2,0x03\n\t" + "vaddss $dst,$tmp2,$tmp\t! add reduction4F" %} + ins_encode %{ + __ vaddss($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); + __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x02); + __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x03); + __ vaddss($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct radd8F_reduction_reg(regF dst, regF src1, vecY src2, regF tmp, regF tmp2, regF tmp3) %{ + predicate(UseAVX > 0); + match(Set dst (AddReductionVF src1 src2)); + effect(TEMP tmp, TEMP tmp2, TEMP tmp3); + format %{ "vaddss $tmp2,$src1,$src2\n\t" + "pshufd $tmp,$src2,0x01\n\t" + "vaddss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$src2,0x02\n\t" + "vaddss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$src2,0x03\n\t" + "vaddss $tmp2,$tmp2,$tmp\n\t" + "vextractf128 $tmp3,$src2\n\t" + "vaddss $tmp2,$tmp2,$tmp3\n\t" + "pshufd $tmp,$tmp3,0x01\n\t" + "vaddss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$tmp3,0x02\n\t" + "vaddss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$tmp3,0x03\n\t" + "vaddss $dst,$tmp2,$tmp\t! add reduction8F" %} + ins_encode %{ + __ vaddss($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); + __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x02); + __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x03); + __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ vextractf128h($tmp3$$XMMRegister, $src2$$XMMRegister); + __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x01); + __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x02); + __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x03); + __ vaddss($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rsadd2D_reduction_reg(regD dst, regD src1, vecX src2, regD tmp) %{ + predicate(UseSSE >= 1 && UseAVX == 0); + match(Set dst (AddReductionVD src1 src2)); + effect(TEMP tmp, TEMP dst); + format %{ "movdqu $tmp,$src1\n\t" + "addsd $tmp,$src2\n\t" + "pshufd $dst,$src2,0xE\n\t" + "addsd $dst,$tmp\t! add reduction2D" %} + ins_encode %{ + __ movdqu($tmp$$XMMRegister, $src1$$XMMRegister); + __ addsd($tmp$$XMMRegister, $src2$$XMMRegister); + __ pshufd($dst$$XMMRegister, $src2$$XMMRegister, 0xE); + __ addsd($dst$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvadd2D_reduction_reg(regD dst, regD src1, vecX src2, regD tmp, regD tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (AddReductionVD src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "vaddsd $tmp2,$src1,$src2\n\t" + "pshufd $tmp,$src2,0xE\n\t" + "vaddsd $dst,$tmp2,$tmp\t! add reduction2D" %} + ins_encode %{ + __ vaddsd($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0xE); + __ vaddsd($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvadd4D_reduction_reg(regD dst, regD src1, vecY src2, regD tmp, regD tmp2, regD tmp3) %{ + predicate(UseAVX > 0); + match(Set dst (AddReductionVD src1 src2)); + effect(TEMP tmp, TEMP tmp2, TEMP tmp3); + format %{ "vaddsd $tmp2,$src1,$src2\n\t" + "pshufd $tmp,$src2,0xE\n\t" + "vaddsd $tmp2,$tmp2,$tmp\n\t" + "vextractf128 $tmp3,$src2\n\t" + "vaddsd $tmp2,$tmp2,$tmp3\n\t" + "pshufd $tmp,$tmp3,0xE\n\t" + "vaddsd $dst,$tmp2,$tmp\t! add reduction4D" %} + ins_encode %{ + __ vaddsd($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0xE); + __ vaddsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ vextractf128h($tmp3$$XMMRegister, $src2$$XMMRegister); + __ vaddsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0xE); + __ vaddsd($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rsmul2I_reduction_reg(rRegI dst, rRegI src1, vecD src2, regF tmp, regF tmp2) %{ + predicate(UseSSE > 3 && UseAVX == 0); + match(Set dst (MulReductionVI src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "pshufd $tmp2,$src2,0x1\n\t" + "pmulld $tmp2,$src2\n\t" + "movd $tmp,$src1\n\t" + "pmulld $tmp2,$tmp\n\t" + "movd $dst,$tmp2\t! mul reduction2I" %} + ins_encode %{ + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x1); + __ pmulld($tmp2$$XMMRegister, $src2$$XMMRegister); + __ movdl($tmp$$XMMRegister, $src1$$Register); + __ pmulld($tmp2$$XMMRegister, $tmp$$XMMRegister); + __ movdl($dst$$Register, $tmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvmul2I_reduction_reg(rRegI dst, rRegI src1, vecD src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (MulReductionVI src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "pshufd $tmp2,$src2,0x1\n\t" + "vpmulld $tmp,$src2,$tmp2\n\t" + "movd $tmp2,$src1\n\t" + "vpmulld $tmp2,$tmp,$tmp2\n\t" + "movd $dst,$tmp2\t! mul reduction2I" %} + ins_encode %{ + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x1); + __ vpmulld($tmp$$XMMRegister, $src2$$XMMRegister, $tmp2$$XMMRegister, false); + __ movdl($tmp2$$XMMRegister, $src1$$Register); + __ vpmulld($tmp2$$XMMRegister, $tmp$$XMMRegister, $tmp2$$XMMRegister, false); + __ movdl($dst$$Register, $tmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rsmul4I_reduction_reg(rRegI dst, rRegI src1, vecX src2, regF tmp, regF tmp2) %{ + predicate(UseSSE > 3 && UseAVX == 0); + match(Set dst (MulReductionVI src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "pshufd $tmp2,$src2,0xE\n\t" + "pmulld $tmp2,$src2\n\t" + "pshufd $tmp,$tmp2,0x1\n\t" + "pmulld $tmp2,$tmp\n\t" + "movd $tmp,$src1\n\t" + "pmulld $tmp2,$tmp\n\t" + "movd $dst,$tmp2\t! mul reduction4I" %} + ins_encode %{ + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0xE); + __ pmulld($tmp2$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x1); + __ pmulld($tmp2$$XMMRegister, $tmp$$XMMRegister); + __ movdl($tmp$$XMMRegister, $src1$$Register); + __ pmulld($tmp2$$XMMRegister, $tmp$$XMMRegister); + __ movdl($dst$$Register, $tmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvmul4I_reduction_reg(rRegI dst, rRegI src1, vecX src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (MulReductionVI src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "pshufd $tmp2,$src2,0xE\n\t" + "vpmulld $tmp,$src2,$tmp2\n\t" + "pshufd $tmp2,$tmp,0x1\n\t" + "vpmulld $tmp,$tmp,$tmp2\n\t" + "movd $tmp2,$src1\n\t" + "vpmulld $tmp2,$tmp,$tmp2\n\t" + "movd $dst,$tmp2\t! mul reduction4I" %} + ins_encode %{ + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0xE); + __ vpmulld($tmp$$XMMRegister, $src2$$XMMRegister, $tmp2$$XMMRegister, false); + __ pshufd($tmp2$$XMMRegister, $tmp$$XMMRegister, 0x1); + __ vpmulld($tmp$$XMMRegister, $tmp$$XMMRegister, $tmp2$$XMMRegister, false); + __ movdl($tmp2$$XMMRegister, $src1$$Register); + __ vpmulld($tmp2$$XMMRegister, $tmp$$XMMRegister, $tmp2$$XMMRegister, false); + __ movdl($dst$$Register, $tmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvmul8I_reduction_reg(rRegI dst, rRegI src1, vecY src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (MulReductionVI src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "vextractf128 $tmp,$src2\n\t" + "vpmulld $tmp,$tmp,$src2\n\t" + "pshufd $tmp2,$tmp,0xE\n\t" + "vpmulld $tmp,$tmp,$tmp2\n\t" + "pshufd $tmp2,$tmp,0x1\n\t" + "vpmulld $tmp,$tmp,$tmp2\n\t" + "movd $tmp2,$src1\n\t" + "vpmulld $tmp2,$tmp,$tmp2\n\t" + "movd $dst,$tmp2\t! mul reduction8I" %} + ins_encode %{ + __ vextractf128h($tmp$$XMMRegister, $src2$$XMMRegister); + __ vpmulld($tmp$$XMMRegister, $tmp$$XMMRegister, $src2$$XMMRegister, false); + __ pshufd($tmp2$$XMMRegister, $tmp$$XMMRegister, 0xE); + __ vpmulld($tmp$$XMMRegister, $tmp$$XMMRegister, $tmp2$$XMMRegister, false); + __ pshufd($tmp2$$XMMRegister, $tmp$$XMMRegister, 0x1); + __ vpmulld($tmp$$XMMRegister, $tmp$$XMMRegister, $tmp2$$XMMRegister, false); + __ movdl($tmp2$$XMMRegister, $src1$$Register); + __ vpmulld($tmp2$$XMMRegister, $tmp$$XMMRegister, $tmp2$$XMMRegister, false); + __ movdl($dst$$Register, $tmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rsmul2F_reduction_reg(regF dst, regF src1, vecD src2, regF tmp, regF tmp2) %{ + predicate(UseSSE >= 1 && UseAVX == 0); + match(Set dst (MulReductionVF src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "movdqu $tmp,$src1\n\t" + "mulss $tmp,$src2\n\t" + "pshufd $tmp2,$src2,0x01\n\t" + "mulss $tmp,$tmp2\n\t" + "movdqu $dst,$tmp\t! add reduction2F" %} + ins_encode %{ + __ movdqu($tmp$$XMMRegister, $src1$$XMMRegister); + __ mulss($tmp$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x01); + __ mulss($tmp$$XMMRegister, $tmp2$$XMMRegister); + __ movdqu($dst$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvmul2F_reduction_reg(regF dst, regF src1, vecD src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (MulReductionVF src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "vmulss $tmp2,$src1,$src2\n\t" + "pshufd $tmp,$src2,0x01\n\t" + "vmulss $dst,$tmp2,$tmp\t! add reduction2F" %} + ins_encode %{ + __ vmulss($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); + __ vmulss($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rsmul4F_reduction_reg(regF dst, regF src1, vecX src2, regF tmp, regF tmp2) %{ + predicate(UseSSE >= 1 && UseAVX == 0); + match(Set dst (MulReductionVF src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "movdqu $tmp,$src1\n\t" + "mulss $tmp,$src2\n\t" + "pshufd $tmp2,$src2,0x01\n\t" + "mulss $tmp,$tmp2\n\t" + "pshufd $tmp2,$src2,0x02\n\t" + "mulss $tmp,$tmp2\n\t" + "pshufd $tmp2,$src2,0x03\n\t" + "mulss $tmp,$tmp2\n\t" + "movdqu $dst,$tmp\t! add reduction4F" %} + ins_encode %{ + __ movdqu($tmp$$XMMRegister, $src1$$XMMRegister); + __ mulss($tmp$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x01); + __ mulss($tmp$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x02); + __ mulss($tmp$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x03); + __ mulss($tmp$$XMMRegister, $tmp2$$XMMRegister); + __ movdqu($dst$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvmul4F_reduction_reg(regF dst, regF src1, vecX src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (MulReductionVF src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "vmulss $tmp2,$src1,$src2\n\t" + "pshufd $tmp,$src2,0x01\n\t" + "vmulss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$src2,0x02\n\t" + "vmulss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$src2,0x03\n\t" + "vmulss $dst,$tmp2,$tmp\t! add reduction4F" %} + ins_encode %{ + __ vmulss($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); + __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x02); + __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x03); + __ vmulss($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvmul8F_reduction_reg(regF dst, regF src1, vecY src2, regF tmp, regF tmp2, regF tmp3) %{ + predicate(UseAVX > 0); + match(Set dst (MulReductionVF src1 src2)); + effect(TEMP tmp, TEMP tmp2, TEMP tmp3); + format %{ "vmulss $tmp2,$src1,$src2\n\t" + "pshufd $tmp,$src2,0x01\n\t" + "vmulss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$src2,0x02\n\t" + "vmulss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$src2,0x03\n\t" + "vmulss $tmp2,$tmp2,$tmp\n\t" + "vextractf128 $tmp3,$src2\n\t" + "vmulss $tmp2,$tmp2,$tmp3\n\t" + "pshufd $tmp,$tmp3,0x01\n\t" + "vmulss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$tmp3,0x02\n\t" + "vmulss $tmp2,$tmp2,$tmp\n\t" + "pshufd $tmp,$tmp3,0x03\n\t" + "vmulss $dst,$tmp2,$tmp\t! mul reduction8F" %} + ins_encode %{ + __ vmulss($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); + __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x02); + __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x03); + __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ vextractf128h($tmp3$$XMMRegister, $src2$$XMMRegister); + __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x01); + __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x02); + __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x03); + __ vmulss($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rsmul2D_reduction_reg(regD dst, regD src1, vecX src2, regD tmp) %{ + predicate(UseSSE >= 1 && UseAVX == 0); + match(Set dst (MulReductionVD src1 src2)); + effect(TEMP tmp, TEMP dst); + format %{ "movdqu $tmp,$src1\n\t" + "mulsd $tmp,$src2\n\t" + "pshufd $dst,$src2,0xE\n\t" + "mulsd $dst,$tmp\t! add reduction2D" %} + ins_encode %{ + __ movdqu($tmp$$XMMRegister, $src1$$XMMRegister); + __ mulsd($tmp$$XMMRegister, $src2$$XMMRegister); + __ pshufd($dst$$XMMRegister, $src2$$XMMRegister, 0xE); + __ mulsd($dst$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvmul2D_reduction_reg(regD dst, regD src1, vecX src2, regD tmp, regD tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (MulReductionVD src1 src2)); + effect(TEMP tmp, TEMP tmp2); + format %{ "vmulsd $tmp2,$src1,$src2\n\t" + "pshufd $tmp,$src2,0xE\n\t" + "vmulsd $dst,$tmp2,$tmp\t! mul reduction2D" %} + ins_encode %{ + __ vmulsd($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0xE); + __ vmulsd($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvmul4D_reduction_reg(regD dst, regD src1, vecY src2, regD tmp, regD tmp2, regD tmp3) %{ + predicate(UseAVX > 0); + match(Set dst (MulReductionVD src1 src2)); + effect(TEMP tmp, TEMP tmp2, TEMP tmp3); + format %{ "vmulsd $tmp2,$src1,$src2\n\t" + "pshufd $tmp,$src2,0xE\n\t" + "vmulsd $tmp2,$tmp2,$tmp\n\t" + "vextractf128 $tmp3,$src2\n\t" + "vmulsd $tmp2,$tmp2,$tmp3\n\t" + "pshufd $tmp,$tmp3,0xE\n\t" + "vmulsd $dst,$tmp2,$tmp\t! mul reduction4D" %} + ins_encode %{ + __ vmulsd($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0xE); + __ vmulsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ vextractf128h($tmp3$$XMMRegister, $src2$$XMMRegister); + __ vmulsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0xE); + __ vmulsd($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + // ====================VECTOR ARITHMETIC======================================= // --------------------------------- ADD -------------------------------------- diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/x86_32.ad --- a/hotspot/src/cpu/x86/vm/x86_32.ad Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/x86_32.ad Thu May 07 20:51:12 2015 -0700 @@ -123,50 +123,94 @@ // 2) reg_class interpreter_method_oop_reg ( /* as def'd in frame section */ ) // 3) reg_class stack_slots( /* one chunk of stack-based "registers" */ ) // +// Class for no registers (empty set). +reg_class no_reg(); + // Class for all registers -reg_class any_reg(EAX, EDX, EBP, EDI, ESI, ECX, EBX, ESP); +reg_class any_reg_with_ebp(EAX, EDX, EBP, EDI, ESI, ECX, EBX, ESP); +// Class for all registers (excluding EBP) +reg_class any_reg_no_ebp(EAX, EDX, EDI, ESI, ECX, EBX, ESP); +// Dynamic register class that selects at runtime between register classes +// any_reg and any_no_ebp_reg (depending on the value of the flag PreserveFramePointer). +// Equivalent to: return PreserveFramePointer ? any_no_ebp_reg : any_reg; +reg_class_dynamic any_reg(any_reg_no_ebp, any_reg_with_ebp, %{ PreserveFramePointer %}); + // Class for general registers -reg_class int_reg(EAX, EDX, EBP, EDI, ESI, ECX, EBX); -// Class for general registers which may be used for implicit null checks on win95 -// Also safe for use by tailjump. We don't want to allocate in rbp, -reg_class int_reg_no_rbp(EAX, EDX, EDI, ESI, ECX, EBX); +reg_class int_reg_with_ebp(EAX, EDX, EBP, EDI, ESI, ECX, EBX); +// Class for general registers (excluding EBP). +// This register class can be used for implicit null checks on win95. +// It is also safe for use by tailjumps (we don't want to allocate in ebp). +// Used also if the PreserveFramePointer flag is true. +reg_class int_reg_no_ebp(EAX, EDX, EDI, ESI, ECX, EBX); +// Dynamic register class that selects between int_reg and int_reg_no_ebp. +reg_class_dynamic int_reg(int_reg_no_ebp, int_reg_with_ebp, %{ PreserveFramePointer %}); + // Class of "X" registers reg_class int_x_reg(EBX, ECX, EDX, EAX); + // Class of registers that can appear in an address with no offset. // EBP and ESP require an extra instruction byte for zero offset. // Used in fast-unlock reg_class p_reg(EDX, EDI, ESI, EBX); -// Class for general registers not including ECX -reg_class ncx_reg(EAX, EDX, EBP, EDI, ESI, EBX); -// Class for general registers not including EAX + +// Class for general registers excluding ECX +reg_class ncx_reg_with_ebp(EAX, EDX, EBP, EDI, ESI, EBX); +// Class for general registers excluding ECX (and EBP) +reg_class ncx_reg_no_ebp(EAX, EDX, EDI, ESI, EBX); +// Dynamic register class that selects between ncx_reg and ncx_reg_no_ebp. +reg_class_dynamic ncx_reg(ncx_reg_no_ebp, ncx_reg_with_ebp, %{ PreserveFramePointer %}); + +// Class for general registers excluding EAX reg_class nax_reg(EDX, EDI, ESI, ECX, EBX); -// Class for general registers not including EAX or EBX. -reg_class nabx_reg(EDX, EDI, ESI, ECX, EBP); + +// Class for general registers excluding EAX and EBX. +reg_class nabx_reg_with_ebp(EDX, EDI, ESI, ECX, EBP); +// Class for general registers excluding EAX and EBX (and EBP) +reg_class nabx_reg_no_ebp(EDX, EDI, ESI, ECX); +// Dynamic register class that selects between nabx_reg and nabx_reg_no_ebp. +reg_class_dynamic nabx_reg(nabx_reg_no_ebp, nabx_reg_with_ebp, %{ PreserveFramePointer %}); + // Class of EAX (for multiply and divide operations) reg_class eax_reg(EAX); + // Class of EBX (for atomic add) reg_class ebx_reg(EBX); + // Class of ECX (for shift and JCXZ operations and cmpLTMask) reg_class ecx_reg(ECX); + // Class of EDX (for multiply and divide operations) reg_class edx_reg(EDX); + // Class of EDI (for synchronization) reg_class edi_reg(EDI); + // Class of ESI (for synchronization) reg_class esi_reg(ESI); -// Singleton class for interpreter's stack pointer -reg_class ebp_reg(EBP); + // Singleton class for stack pointer reg_class sp_reg(ESP); + // Singleton class for instruction pointer // reg_class ip_reg(EIP); + // Class of integer register pairs -reg_class long_reg( EAX,EDX, ECX,EBX, EBP,EDI ); +reg_class long_reg_with_ebp( EAX,EDX, ECX,EBX, EBP,EDI ); +// Class of integer register pairs (excluding EBP and EDI); +reg_class long_reg_no_ebp( EAX,EDX, ECX,EBX ); +// Dynamic register class that selects between long_reg and long_reg_no_ebp. +reg_class_dynamic long_reg(long_reg_no_ebp, long_reg_with_ebp, %{ PreserveFramePointer %}); + // Class of integer register pairs that aligns with calling convention reg_class eadx_reg( EAX,EDX ); reg_class ebcx_reg( ECX,EBX ); + // Not AX or DX, used in divides -reg_class nadx_reg( EBX,ECX,ESI,EDI,EBP ); +reg_class nadx_reg_with_ebp(EBX, ECX, ESI, EDI, EBP); +// Not AX or DX (and neither EBP), used in divides +reg_class nadx_reg_no_ebp(EBX, ECX, ESI, EDI); +// Dynamic register class that selects between nadx_reg and nadx_reg_no_ebp. +reg_class_dynamic nadx_reg(nadx_reg_no_ebp, nadx_reg_with_ebp, %{ PreserveFramePointer %}); // Floating point registers. Notice FPR0 is not a choice. // FPR0 is not ever allocated; we use clever encodings to fake @@ -240,18 +284,11 @@ return size; } -static int preserve_SP_size() { - return 2; // op, rm(reg/reg) -} - // !!!!! Special hack to get all type of calls to specify the byte offset // from the start of the call to the point where the return address // will point. int MachCallStaticJavaNode::ret_addr_offset() { - int offset = 5 + pre_call_resets_size(); // 5 bytes from start of call to where return address points - if (_method_handle_invoke) - offset += preserve_SP_size(); - return offset; + return 5 + pre_call_resets_size(); // 5 bytes from start of call to where return address points } int MachCallDynamicJavaNode::ret_addr_offset() { @@ -285,15 +322,6 @@ // The address of the call instruction needs to be 4-byte aligned to // ensure that it does not span a cache line so that it can be patched. -int CallStaticJavaHandleNode::compute_padding(int current_offset) const { - current_offset += pre_call_resets_size(); // skip fldcw, if any - current_offset += preserve_SP_size(); // skip mov rbp, rsp - current_offset += 1; // skip call opcode byte - return round_to(current_offset, alignment_required()) - current_offset; -} - -// The address of the call instruction needs to be 4-byte aligned to -// ensure that it does not span a cache line so that it can be patched. int CallDynamicJavaDirectNode::compute_padding(int current_offset) const { current_offset += pre_call_resets_size(); // skip fldcw, if any current_offset += 5; // skip MOV instruction @@ -523,6 +551,10 @@ st->print("# stack bang (%d bytes)", bangsize); st->print("\n\t"); st->print("PUSH EBP\t# Save EBP"); + if (PreserveFramePointer) { + st->print("\n\t"); + st->print("MOV EBP, ESP\t# Save the caller's SP into EBP"); + } if (framesize) { st->print("\n\t"); st->print("SUB ESP, #%d\t# Create frame",framesize); @@ -532,6 +564,10 @@ st->print("\n\t"); framesize -= wordSize; st->print("MOV [ESP + #%d], EBP\t# Save EBP",framesize); + if (PreserveFramePointer) { + st->print("\n\t"); + st->print("MOV EBP, [ESP + #%d]\t# Save the caller's SP into EBP", (framesize + wordSize)); + } } if (VerifyStackAtCalls) { @@ -1489,7 +1525,7 @@ } const RegMask Matcher::method_handle_invoke_SP_save_mask() { - return EBP_REG_mask(); + return NO_REG_mask(); } // Returns true if the high 32 bits of the value is known to be zero. @@ -3735,7 +3771,7 @@ // On windows95, EBP is not safe to use for implicit null tests. operand eRegP_no_EBP() %{ - constraint(ALLOC_IN_RC(int_reg_no_rbp)); + constraint(ALLOC_IN_RC(int_reg_no_ebp)); match(RegP); match(eAXRegP); match(eBXRegP); @@ -3824,13 +3860,6 @@ interface(REG_INTER); %} -operand eBPRegP() %{ - constraint(ALLOC_IN_RC(ebp_reg)); - match(RegP); - format %{ "EBP" %} - interface(REG_INTER); -%} - operand eRegL() %{ constraint(ALLOC_IN_RC(long_reg)); match(RegL); @@ -12615,7 +12644,6 @@ // compute_padding() functions will have to be adjusted. instruct CallStaticJavaDirect(method meth) %{ match(CallStaticJava); - predicate(! ((CallStaticJavaNode*)n)->is_method_handle_invoke()); effect(USE meth); ins_cost(300); @@ -12629,29 +12657,6 @@ ins_alignment(4); %} -// Call Java Static Instruction (method handle version) -// Note: If this code changes, the corresponding ret_addr_offset() and -// compute_padding() functions will have to be adjusted. -instruct CallStaticJavaHandle(method meth, eBPRegP ebp_mh_SP_save) %{ - match(CallStaticJava); - predicate(((CallStaticJavaNode*)n)->is_method_handle_invoke()); - effect(USE meth); - // EBP is saved by all callees (for interpreter stack correction). - // We use it here for a similar purpose, in {preserve,restore}_SP. - - ins_cost(300); - format %{ "CALL,static/MethodHandle " %} - opcode(0xE8); /* E8 cd */ - ins_encode( pre_call_resets, - preserve_SP, - Java_Static_Call( meth ), - restore_SP, - call_epilog, - post_call_FPU ); - ins_pipe( pipe_slow ); - ins_alignment(4); -%} - // Call Java Dynamic Instruction // Note: If this code changes, the corresponding ret_addr_offset() and // compute_padding() functions will have to be adjusted. diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/x86/vm/x86_64.ad --- a/hotspot/src/cpu/x86/vm/x86_64.ad Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/x86_64.ad Thu May 07 20:51:12 2015 -0700 @@ -166,42 +166,67 @@ // 3) reg_class stack_slots( /* one chunk of stack-based "registers" */ ) // -// Class for all pointer registers (including RSP) -reg_class any_reg(RAX, RAX_H, - RDX, RDX_H, - RBP, RBP_H, - RDI, RDI_H, - RSI, RSI_H, - RCX, RCX_H, - RBX, RBX_H, - RSP, RSP_H, - R8, R8_H, - R9, R9_H, - R10, R10_H, - R11, R11_H, - R12, R12_H, - R13, R13_H, - R14, R14_H, - R15, R15_H); - -// Class for all pointer registers except RSP -reg_class ptr_reg(RAX, RAX_H, - RDX, RDX_H, - RBP, RBP_H, - RDI, RDI_H, - RSI, RSI_H, - RCX, RCX_H, - RBX, RBX_H, - R8, R8_H, - R9, R9_H, - R10, R10_H, - R11, R11_H, - R13, R13_H, - R14, R14_H); - -// Class for all pointer registers except RAX and RSP -reg_class ptr_no_rax_reg(RDX, RDX_H, - RBP, RBP_H, +// Empty register class. +reg_class no_reg(); + +// Class for all pointer registers (including RSP and RBP) +reg_class any_reg_with_rbp(RAX, RAX_H, + RDX, RDX_H, + RBP, RBP_H, + RDI, RDI_H, + RSI, RSI_H, + RCX, RCX_H, + RBX, RBX_H, + RSP, RSP_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R12, R12_H, + R13, R13_H, + R14, R14_H, + R15, R15_H); + +// Class for all pointer registers (including RSP, but excluding RBP) +reg_class any_reg_no_rbp(RAX, RAX_H, + RDX, RDX_H, + RDI, RDI_H, + RSI, RSI_H, + RCX, RCX_H, + RBX, RBX_H, + RSP, RSP_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R12, R12_H, + R13, R13_H, + R14, R14_H, + R15, R15_H); + +// Dynamic register class that selects at runtime between register classes +// any_reg_no_rbp and any_reg_with_rbp (depending on the value of the flag PreserveFramePointer). +// Equivalent to: return PreserveFramePointer ? any_reg_no_rbp : any_reg_with_rbp; +reg_class_dynamic any_reg(any_reg_no_rbp, any_reg_with_rbp, %{ PreserveFramePointer %}); + +// Class for all pointer registers (excluding RSP) +reg_class ptr_reg_with_rbp(RAX, RAX_H, + RDX, RDX_H, + RBP, RBP_H, + RDI, RDI_H, + RSI, RSI_H, + RCX, RCX_H, + RBX, RBX_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R13, R13_H, + R14, R14_H); + +// Class for all pointer registers (excluding RSP and RBP) +reg_class ptr_reg_no_rbp(RAX, RAX_H, + RDX, RDX_H, RDI, RDI_H, RSI, RSI_H, RCX, RCX_H, @@ -213,31 +238,66 @@ R13, R13_H, R14, R14_H); -reg_class ptr_no_rbp_reg(RDX, RDX_H, - RAX, RAX_H, - RDI, RDI_H, - RSI, RSI_H, - RCX, RCX_H, - RBX, RBX_H, - R8, R8_H, - R9, R9_H, - R10, R10_H, - R11, R11_H, - R13, R13_H, - R14, R14_H); - -// Class for all pointer registers except RAX, RBX and RSP -reg_class ptr_no_rax_rbx_reg(RDX, RDX_H, - RBP, RBP_H, - RDI, RDI_H, - RSI, RSI_H, - RCX, RCX_H, - R8, R8_H, - R9, R9_H, - R10, R10_H, - R11, R11_H, - R13, R13_H, - R14, R14_H); +// Dynamic register class that selects between ptr_reg_no_rbp and ptr_reg_with_rbp. +reg_class_dynamic ptr_reg(ptr_reg_no_rbp, ptr_reg_with_rbp, %{ PreserveFramePointer %}); + +// Class for all pointer registers (excluding RAX and RSP) +reg_class ptr_no_rax_reg_with_rbp(RDX, RDX_H, + RBP, RBP_H, + RDI, RDI_H, + RSI, RSI_H, + RCX, RCX_H, + RBX, RBX_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R13, R13_H, + R14, R14_H); + +// Class for all pointer registers (excluding RAX, RSP, and RBP) +reg_class ptr_no_rax_reg_no_rbp(RDX, RDX_H, + RDI, RDI_H, + RSI, RSI_H, + RCX, RCX_H, + RBX, RBX_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R13, R13_H, + R14, R14_H); + +// Dynamic register class that selects between ptr_no_rax_reg_no_rbp and ptr_no_rax_reg_with_rbp. +reg_class_dynamic ptr_no_rax_reg(ptr_no_rax_reg_no_rbp, ptr_no_rax_reg_with_rbp, %{ PreserveFramePointer %}); + +// Class for all pointer registers (excluding RAX, RBX, and RSP) +reg_class ptr_no_rax_rbx_reg_with_rbp(RDX, RDX_H, + RBP, RBP_H, + RDI, RDI_H, + RSI, RSI_H, + RCX, RCX_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R13, R13_H, + R14, R14_H); + +// Class for all pointer registers (excluding RAX, RBX, RSP, and RBP) +reg_class ptr_no_rax_rbx_reg_no_rbp(RDX, RDX_H, + RDI, RDI_H, + RSI, RSI_H, + RCX, RCX_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R13, R13_H, + R14, R14_H); + +// Dynamic register class that selects between ptr_no_rax_rbx_reg_no_rbp and ptr_no_rax_rbx_reg_with_rbp. +reg_class_dynamic ptr_no_rax_rbx_reg(ptr_no_rax_rbx_reg_no_rbp, ptr_no_rax_rbx_reg_with_rbp, %{ PreserveFramePointer %}); // Singleton class for RAX pointer register reg_class ptr_rax_reg(RAX, RAX_H); @@ -251,59 +311,29 @@ // Singleton class for RDI pointer register reg_class ptr_rdi_reg(RDI, RDI_H); -// Singleton class for RBP pointer register -reg_class ptr_rbp_reg(RBP, RBP_H); - // Singleton class for stack pointer reg_class ptr_rsp_reg(RSP, RSP_H); // Singleton class for TLS pointer reg_class ptr_r15_reg(R15, R15_H); -// Class for all long registers (except RSP) -reg_class long_reg(RAX, RAX_H, - RDX, RDX_H, - RBP, RBP_H, - RDI, RDI_H, - RSI, RSI_H, - RCX, RCX_H, - RBX, RBX_H, - R8, R8_H, - R9, R9_H, - R10, R10_H, - R11, R11_H, - R13, R13_H, - R14, R14_H); - -// Class for all long registers except RAX, RDX (and RSP) -reg_class long_no_rax_rdx_reg(RBP, RBP_H, - RDI, RDI_H, - RSI, RSI_H, - RCX, RCX_H, - RBX, RBX_H, - R8, R8_H, - R9, R9_H, - R10, R10_H, - R11, R11_H, - R13, R13_H, - R14, R14_H); - -// Class for all long registers except RCX (and RSP) -reg_class long_no_rcx_reg(RBP, RBP_H, - RDI, RDI_H, - RSI, RSI_H, - RAX, RAX_H, - RDX, RDX_H, - RBX, RBX_H, - R8, R8_H, - R9, R9_H, - R10, R10_H, - R11, R11_H, - R13, R13_H, - R14, R14_H); - -// Class for all long registers except RAX (and RSP) -reg_class long_no_rax_reg(RBP, RBP_H, +// Class for all long registers (excluding RSP) +reg_class long_reg_with_rbp(RAX, RAX_H, + RDX, RDX_H, + RBP, RBP_H, + RDI, RDI_H, + RSI, RSI_H, + RCX, RCX_H, + RBX, RBX_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R13, R13_H, + R14, R14_H); + +// Class for all long registers (excluding RSP and RBP) +reg_class long_reg_no_rbp(RAX, RAX_H, RDX, RDX_H, RDI, RDI_H, RSI, RSI_H, @@ -316,6 +346,67 @@ R13, R13_H, R14, R14_H); +// Dynamic register class that selects between long_reg_no_rbp and long_reg_with_rbp. +reg_class_dynamic long_reg(long_reg_no_rbp, long_reg_with_rbp, %{ PreserveFramePointer %}); + +// Class for all long registers (excluding RAX, RDX and RSP) +reg_class long_no_rax_rdx_reg_with_rbp(RBP, RBP_H, + RDI, RDI_H, + RSI, RSI_H, + RCX, RCX_H, + RBX, RBX_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R13, R13_H, + R14, R14_H); + +// Class for all long registers (excluding RAX, RDX, RSP, and RBP) +reg_class long_no_rax_rdx_reg_no_rbp(RDI, RDI_H, + RSI, RSI_H, + RCX, RCX_H, + RBX, RBX_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R13, R13_H, + R14, R14_H); + +// Dynamic register class that selects between long_no_rax_rdx_reg_no_rbp and long_no_rax_rdx_reg_with_rbp. +reg_class_dynamic long_no_rax_rdx_reg(long_no_rax_rdx_reg_no_rbp, long_no_rax_rdx_reg_with_rbp, %{ PreserveFramePointer %}); + +// Class for all long registers (excluding RCX and RSP) +reg_class long_no_rcx_reg_with_rbp(RBP, RBP_H, + RDI, RDI_H, + RSI, RSI_H, + RAX, RAX_H, + RDX, RDX_H, + RBX, RBX_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R13, R13_H, + R14, R14_H); + +// Class for all long registers (excluding RCX, RSP, and RBP) +reg_class long_no_rcx_reg_no_rbp(RDI, RDI_H, + RSI, RSI_H, + RAX, RAX_H, + RDX, RDX_H, + RBX, RBX_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R13, R13_H, + R14, R14_H); + +// Dynamic register class that selects between long_no_rcx_reg_no_rbp and long_no_rcx_reg_with_rbp. +reg_class_dynamic long_no_rcx_reg(long_no_rcx_reg_no_rbp, long_no_rcx_reg_with_rbp, %{ PreserveFramePointer %}); + // Singleton class for RAX long register reg_class long_rax_reg(RAX, RAX_H); @@ -325,27 +416,27 @@ // Singleton class for RDX long register reg_class long_rdx_reg(RDX, RDX_H); -// Class for all int registers (except RSP) -reg_class int_reg(RAX, - RDX, - RBP, - RDI, - RSI, - RCX, - RBX, - R8, - R9, - R10, - R11, - R13, - R14); - -// Class for all int registers except RCX (and RSP) -reg_class int_no_rcx_reg(RAX, +// Class for all int registers (excluding RSP) +reg_class int_reg_with_rbp(RAX, + RDX, + RBP, + RDI, + RSI, + RCX, + RBX, + R8, + R9, + R10, + R11, + R13, + R14); + +// Class for all int registers (excluding RSP and RBP) +reg_class int_reg_no_rbp(RAX, RDX, - RBP, RDI, RSI, + RCX, RBX, R8, R9, @@ -354,18 +445,66 @@ R13, R14); -// Class for all int registers except RAX, RDX (and RSP) -reg_class int_no_rax_rdx_reg(RBP, - RDI, - RSI, - RCX, - RBX, - R8, - R9, - R10, - R11, - R13, - R14); +// Dynamic register class that selects between int_reg_no_rbp and int_reg_with_rbp. +reg_class_dynamic int_reg(int_reg_no_rbp, int_reg_with_rbp, %{ PreserveFramePointer %}); + +// Class for all int registers (excluding RCX and RSP) +reg_class int_no_rcx_reg_with_rbp(RAX, + RDX, + RBP, + RDI, + RSI, + RBX, + R8, + R9, + R10, + R11, + R13, + R14); + +// Class for all int registers (excluding RCX, RSP, and RBP) +reg_class int_no_rcx_reg_no_rbp(RAX, + RDX, + RDI, + RSI, + RBX, + R8, + R9, + R10, + R11, + R13, + R14); + +// Dynamic register class that selects between int_no_rcx_reg_no_rbp and int_no_rcx_reg_with_rbp. +reg_class_dynamic int_no_rcx_reg(int_no_rcx_reg_no_rbp, int_no_rcx_reg_with_rbp, %{ PreserveFramePointer %}); + +// Class for all int registers (excluding RAX, RDX, and RSP) +reg_class int_no_rax_rdx_reg_with_rbp(RBP, + RDI, + RSI, + RCX, + RBX, + R8, + R9, + R10, + R11, + R13, + R14); + +// Class for all int registers (excluding RAX, RDX, RSP, and RBP) +reg_class int_no_rax_rdx_reg_no_rbp(RDI, + RSI, + RCX, + RBX, + R8, + R9, + R10, + R11, + R13, + R14); + +// Dynamic register class that selects between int_no_rax_rdx_reg_no_rbp and int_no_rax_rdx_reg_with_rbp. +reg_class_dynamic int_no_rax_rdx_reg(int_no_rax_rdx_reg_no_rbp, int_no_rax_rdx_reg_with_rbp, %{ PreserveFramePointer %}); // Singleton class for RAX int register reg_class int_rax_reg(RAX); @@ -396,9 +535,6 @@ #define __ _masm. -static int preserve_SP_size() { - return 3; // rex.w, op, rm(reg/reg) -} static int clear_avx_size() { return (Compile::current()->max_vector_size() > 16) ? 3 : 0; // vzeroupper } @@ -409,9 +545,7 @@ int MachCallStaticJavaNode::ret_addr_offset() { int offset = 5; // 5 bytes from start of call to where return address points - offset += clear_avx_size(); - if (_method_handle_invoke) - offset += preserve_SP_size(); + offset += clear_avx_size(); return offset; } @@ -450,16 +584,6 @@ // The address of the call instruction needs to be 4-byte aligned to // ensure that it does not span a cache line so that it can be patched. -int CallStaticJavaHandleNode::compute_padding(int current_offset) const -{ - current_offset += preserve_SP_size(); // skip mov rbp, rsp - current_offset += clear_avx_size(); // skip vzeroupper - current_offset += 1; // skip call opcode byte - return round_to(current_offset, alignment_required()) - current_offset; -} - -// The address of the call instruction needs to be 4-byte aligned to -// ensure that it does not span a cache line so that it can be patched. int CallDynamicJavaDirectNode::compute_padding(int current_offset) const { current_offset += clear_avx_size(); // skip vzeroupper @@ -724,6 +848,10 @@ st->print("# stack bang (%d bytes)", bangsize); st->print("\n\t"); st->print("pushq rbp\t# Save rbp"); + if (PreserveFramePointer) { + st->print("\n\t"); + st->print("movq rbp, rsp\t# Save the caller's SP into rbp"); + } if (framesize) { st->print("\n\t"); st->print("subq rsp, #%d\t# Create frame",framesize); @@ -732,7 +860,11 @@ st->print("subq rsp, #%d\t# Create frame",framesize); st->print("\n\t"); framesize -= wordSize; - st->print("movq [rsp + #%d], rbp\t# Save rbp",framesize); + st->print("movq [rsp + #%d], rbp\t# Save rbp",framesize); + if (PreserveFramePointer) { + st->print("\n\t"); + st->print("movq rbp, [rsp + #%d]\t# Save the caller's SP into rbp", (framesize + wordSize)); + } } if (VerifyStackAtCalls) { @@ -1598,8 +1730,9 @@ return LONG_RDX_REG_mask(); } +// Register for saving SP into on method handle invokes. Not used on x86_64. const RegMask Matcher::method_handle_invoke_SP_save_mask() { - return PTR_RBP_REG_mask(); + return NO_REG_mask(); } %} @@ -3202,7 +3335,7 @@ // Pointer Register operand any_RegP() %{ - constraint(ALLOC_IN_RC(any_reg)); + constraint(ALLOC_IN_RC(any_reg)); match(RegP); match(rax_RegP); match(rbx_RegP); @@ -3224,8 +3357,8 @@ match(rbx_RegP); match(rdi_RegP); match(rsi_RegP); - match(rbp_RegP); - match(r15_RegP); // See Q&A below about r15_RegP. + match(rbp_RegP); // See Q&A below about + match(r15_RegP); // r15_RegP and rbp_RegP. format %{ %} interface(REG_INTER); @@ -3241,11 +3374,14 @@ // Question: Why is r15_RegP (the read-only TLS register) a match for rRegP? // Answer: Operand match rules govern the DFA as it processes instruction inputs. -// It's fine for an instruction input which expects rRegP to match a r15_RegP. +// It's fine for an instruction input that expects rRegP to match a r15_RegP. // The output of an instruction is controlled by the allocator, which respects // register class masks, not match rules. Unless an instruction mentions // r15_RegP or any_RegP explicitly as its output, r15 will not be considered // by the allocator as an input. +// The same logic applies to rbp_RegP being a match for rRegP: If PreserveFramePointer==true, +// the RBP is used as a proper frame pointer and is not included in ptr_reg. As a +// result, RBP is not included in the output of the instruction either. operand no_rax_RegP() %{ @@ -3259,9 +3395,11 @@ interface(REG_INTER); %} +// This operand is not allowed to use RBP even if +// RBP is not used to hold the frame pointer. operand no_rbp_RegP() %{ - constraint(ALLOC_IN_RC(ptr_no_rbp_reg)); + constraint(ALLOC_IN_RC(ptr_reg_no_rbp)); match(RegP); match(rbx_RegP); match(rsi_RegP); @@ -3338,16 +3476,6 @@ interface(REG_INTER); %} -operand rbp_RegP() -%{ - constraint(ALLOC_IN_RC(ptr_rbp_reg)); - match(RegP); - match(rRegP); - - format %{ %} - interface(REG_INTER); -%} - operand r15_RegP() %{ constraint(ALLOC_IN_RC(ptr_r15_reg)); @@ -3604,6 +3732,23 @@ %} %} +// Indirect Memory Plus Positive Index Register Plus Offset Operand +operand indPosIndexOffset(any_RegP reg, immL32 off, rRegI idx) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + predicate(n->in(2)->in(3)->as_Type()->type()->is_long()->_lo >= 0); + match(AddP (AddP reg (ConvI2L idx)) off); + + op_cost(10); + format %{"[$reg + $off + $idx]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($idx); + scale(0x0); + disp($off); + %} +%} + // Indirect Memory Times Scale Plus Positive Index Register Plus Offset Operand operand indPosIndexScaleOffset(any_RegP reg, immL32 off, rRegI idx, immI2 scale) %{ @@ -3755,6 +3900,23 @@ %} %} +// Indirect Memory Times Plus Positive Index Register Plus Offset Operand +operand indPosIndexOffsetNarrow(rRegN reg, immL32 off, rRegI idx) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + predicate(Universe::narrow_oop_shift() == 0 && n->in(2)->in(3)->as_Type()->type()->is_long()->_lo >= 0); + match(AddP (AddP (DecodeN reg) (ConvI2L idx)) off); + + op_cost(10); + format %{"[$reg + $off + $idx]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($idx); + scale(0x0); + disp($off); + %} +%} + // Indirect Memory Times Scale Plus Positive Index Register Plus Offset Operand operand indPosIndexScaleOffsetNarrow(rRegN reg, immL32 off, rRegI idx, immI2 scale) %{ @@ -3946,11 +4108,11 @@ // case of this is memory operands. opclass memory(indirect, indOffset8, indOffset32, indIndexOffset, indIndex, - indIndexScale, indIndexScaleOffset, indPosIndexScaleOffset, + indIndexScale, indIndexScaleOffset, indPosIndexOffset, indPosIndexScaleOffset, indCompressedOopOffset, indirectNarrow, indOffset8Narrow, indOffset32Narrow, indIndexOffsetNarrow, indIndexNarrow, indIndexScaleNarrow, - indIndexScaleOffsetNarrow, indPosIndexScaleOffsetNarrow); + indIndexScaleOffsetNarrow, indPosIndexOffsetNarrow, indPosIndexScaleOffsetNarrow); //----------PIPELINE----------------------------------------------------------- // Rules which define the behavior of the target architectures pipeline. @@ -4984,6 +5146,17 @@ ins_pipe(ialu_reg_reg_fat); %} +instruct leaPPosIdxOff(rRegP dst, indPosIndexOffset mem) +%{ + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr posidxoff" %} + opcode(0x8D); + ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem)); + ins_pipe(ialu_reg_reg_fat); +%} + instruct leaPPosIdxScaleOff(rRegP dst, indPosIndexScaleOffset mem) %{ match(Set dst mem); @@ -5068,6 +5241,18 @@ ins_pipe(ialu_reg_reg_fat); %} +instruct leaPPosIdxOffNarrow(rRegP dst, indPosIndexOffsetNarrow mem) +%{ + predicate(Universe::narrow_oop_shift() == 0); + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr posidxoffnarrow" %} + opcode(0x8D); + ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem)); + ins_pipe(ialu_reg_reg_fat); +%} + instruct leaPPosIdxScaleOffNarrow(rRegP dst, indPosIndexScaleOffsetNarrow mem) %{ predicate(Universe::narrow_oop_shift() == 0); @@ -11353,7 +11538,6 @@ // compute_padding() functions will have to be adjusted. instruct CallStaticJavaDirect(method meth) %{ match(CallStaticJava); - predicate(!((CallStaticJavaNode*) n)->is_method_handle_invoke()); effect(USE meth); ins_cost(300); @@ -11364,27 +11548,6 @@ ins_alignment(4); %} -// Call Java Static Instruction (method handle version) -// Note: If this code changes, the corresponding ret_addr_offset() and -// compute_padding() functions will have to be adjusted. -instruct CallStaticJavaHandle(method meth, rbp_RegP rbp_mh_SP_save) %{ - match(CallStaticJava); - predicate(((CallStaticJavaNode*) n)->is_method_handle_invoke()); - effect(USE meth); - // RBP is saved by all callees (for interpreter stack correction). - // We use it here for a similar purpose, in {preserve,restore}_SP. - - ins_cost(300); - format %{ "call,static/MethodHandle " %} - opcode(0xE8); /* E8 cd */ - ins_encode(clear_avx, preserve_SP, - Java_Static_Call(meth), - restore_SP, - call_epilog); - ins_pipe(pipe_slow); - ins_alignment(4); -%} - // Call Java Dynamic Instruction // Note: If this code changes, the corresponding ret_addr_offset() and // compute_padding() functions will have to be adjusted. diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp --- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -814,9 +814,9 @@ } #endif // INCLUDE_ALL_GCS - // If G1 is not enabled then attempt to go through the accessor entry point - // Reference.get is an accessor - return generate_accessor_entry(); + // If G1 is not enabled then attempt to go through the normal entry point + // Reference.get could be instrumented by jvmti + return generate_normal_entry(false); } address InterpreterGenerator::generate_native_entry(bool synchronized) { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/zero/vm/frame_zero.cpp --- a/hotspot/src/cpu/zero/vm/frame_zero.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/zero/vm/frame_zero.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -213,7 +213,7 @@ valuebuf[buflen - 1] = '\0'; // Print the result - st->print_cr(" " PTR_FORMAT ": %-21s = %s", addr, fieldbuf, valuebuf); + st->print_cr(" " PTR_FORMAT ": %-21s = %s", p2i(addr), fieldbuf, valuebuf); } } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/zero/vm/methodHandles_zero.cpp --- a/hotspot/src/cpu/zero/vm/methodHandles_zero.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/zero/vm/methodHandles_zero.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright 2009, 2010, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -27,6 +27,7 @@ #include "interpreter/interpreterGenerator.hpp" #include "interpreter/interpreter.hpp" #include "memory/allocation.inline.hpp" +#include "oops/oop.inline.hpp" #include "prims/methodHandles.hpp" void MethodHandles::invoke_target(Method* method, TRAPS) { @@ -144,6 +145,7 @@ oop recv = STACK_OBJECT(-numArgs); Klass* clazz = recv->klass(); Klass* klass_part = InstanceKlass::cast(clazz); + ResourceMark rm(THREAD); klassVtable* vtable = klass_part->vtable(); Method* vmtarget = vtable->method_at(vmindex); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/zero/vm/stubGenerator_zero.cpp --- a/hotspot/src/cpu/zero/vm/stubGenerator_zero.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/zero/vm/stubGenerator_zero.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2007, 2008, 2010 Red Hat, Inc. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2007, 2008, 2010, 2015 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,18 @@ #include "opto/runtime.hpp" #endif +// For SafeFetch we need POSIX tls and setjmp +#include +#include +static pthread_key_t g_jmpbuf_key; + +// return the currently active jump buffer for this thread +// - if there is any, NULL otherwise. Called from +// zero signal handlers. +extern sigjmp_buf* get_jmp_buf_for_continuation() { + return (sigjmp_buf*) pthread_getspecific(g_jmpbuf_key); +} + // Declaration and definition of StubGenerator (no .hpp file). // For a more detailed description of the stub routine structure // see the comment in stubRoutines.hpp @@ -177,18 +189,56 @@ } static int SafeFetch32(int *adr, int errValue) { + + // set up a jump buffer; anchor the pointer to the jump buffer in tls; then + // do the pointer access. If pointer is invalid, we crash; in signal + // handler, we retrieve pointer to jmp buffer from tls, and jump back. + // + // Note: the jump buffer itself - which can get pretty large depending on + // the architecture - lives on the stack and that is fine, because we will + // not rewind the stack: either we crash, in which case signal handler + // frame is below us, or we don't crash, in which case it does not matter. + sigjmp_buf jb; + if (sigsetjmp(jb, 1)) { + // we crashed. clean up tls and return default value. + pthread_setspecific(g_jmpbuf_key, NULL); + return errValue; + } else { + // preparation phase + pthread_setspecific(g_jmpbuf_key, &jb); + } + int value = errValue; value = *adr; + + // all went well. clean tls. + pthread_setspecific(g_jmpbuf_key, NULL); + return value; } static intptr_t SafeFetchN(intptr_t *adr, intptr_t errValue) { + + sigjmp_buf jb; + if (sigsetjmp(jb, 1)) { + // we crashed. clean up tls and return default value. + pthread_setspecific(g_jmpbuf_key, NULL); + return errValue; + } else { + // preparation phase + pthread_setspecific(g_jmpbuf_key, &jb); + } + intptr_t value = errValue; value = *adr; + + // all went well. clean tls. + pthread_setspecific(g_jmpbuf_key, NULL); + return value; + } - void generate_initial() { // Generates all stubs and initializes the entry points @@ -241,6 +291,7 @@ generate_arraycopy_stubs(); // Safefetch stubs. + pthread_key_create(&g_jmpbuf_key, NULL); StubRoutines::_safefetch32_entry = CAST_FROM_FN_PTR(address, StubGenerator::SafeFetch32); StubRoutines::_safefetch32_fault_pc = NULL; StubRoutines::_safefetch32_continuation_pc = NULL; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/zero/vm/vm_version_zero.cpp --- a/hotspot/src/cpu/zero/vm/vm_version_zero.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/zero/vm/vm_version_zero.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright 2009 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,4 +30,11 @@ #include "runtime/stubCodeGenerator.hpp" #include "vm_version_zero.hpp" -// This file is intentionally empty + +void VM_Version::initialize() { + // This machine does not allow unaligned memory accesses + if (! FLAG_IS_DEFAULT(UseUnalignedAccesses)) { + warning("Unaligned memory access is not available on this CPU"); + FLAG_SET_DEFAULT(UseUnalignedAccesses, false); + } +} diff -r a4b1c7d6317a -r febd2373771c hotspot/src/cpu/zero/vm/vm_version_zero.hpp --- a/hotspot/src/cpu/zero/vm/vm_version_zero.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/cpu/zero/vm/vm_version_zero.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright 2007 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -34,6 +34,7 @@ static const char* cpu_features() { return ""; } + static void initialize(); }; #endif // CPU_ZERO_VM_VM_VERSION_ZERO_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os/aix/vm/attachListener_aix.cpp --- a/hotspot/src/os/aix/vm/attachListener_aix.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os/aix/vm/attachListener_aix.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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 @@ -144,6 +144,10 @@ } char* next() { if (*_pos == '\0') { + if (_pos < _end) { + _pos += 1; + } + return NULL; } char* res = _pos; @@ -214,6 +218,7 @@ // bind socket struct sockaddr_un addr; + memset((void *)&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strcpy(addr.sun_path, initial_path); ::unlink(initial_path); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os/aix/vm/globals_aix.hpp --- a/hotspot/src/os/aix/vm/globals_aix.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os/aix/vm/globals_aix.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,10 @@ // #define RUNTIME_OS_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct) \ \ + /* Use 64K pages for virtual memory (shmat). */ \ + product(bool, Use64KPages, true, \ + "Use 64K pages if available.") \ + \ /* If UseLargePages == true allow or deny usage of 16M pages. 16M pages are */ \ /* a scarce resource and there may be situations where we do not want the VM */ \ /* to run with 16M pages. (Will fall back to 64K pages). */ \ @@ -55,7 +59,7 @@ // Defines Aix-specific default values. The flags are available on all // platforms, but they may have different default values on other platforms. // -define_pd_global(bool, UseLargePages, true); +define_pd_global(bool, UseLargePages, false); define_pd_global(bool, UseLargePagesIndividualAllocation, false); define_pd_global(bool, UseOSErrorReporting, false); define_pd_global(bool, UseThreadPriorities, true) ; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os/aix/vm/interfaceSupport_aix.hpp --- a/hotspot/src/os/aix/vm/interfaceSupport_aix.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os/aix/vm/interfaceSupport_aix.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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 @@ -23,8 +23,8 @@ * */ -#ifndef OS_LINUX_VM_INTERFACESUPPORT_LINUX_HPP -#define OS_LINUX_VM_INTERFACESUPPORT_LINUX_HPP +#ifndef OS_AIX_VM_INTERFACESUPPORT_AIX_HPP +#define OS_AIX_VM_INTERFACESUPPORT_AIX_HPP // Contains inlined functions for class InterfaceSupport @@ -32,4 +32,4 @@ os::write_memory_serialize_page(thread); } -#endif // OS_LINUX_VM_INTERFACESUPPORT_LINUX_HPP +#endif // OS_AIX_VM_INTERFACESUPPORT_AIX_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os/aix/vm/osThread_aix.cpp --- a/hotspot/src/os/aix/vm/osThread_aix.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os/aix/vm/osThread_aix.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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 @@ -47,7 +47,7 @@ _startThread_lock = new Monitor(Mutex::event, "startThread_lock", true, Monitor::_safepoint_check_never); - assert(_startThread_lock !=NULL, "check"); + assert(_startThread_lock != NULL, "check"); } void OSThread::pd_destroy() { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os/aix/vm/os_aix.cpp --- a/hotspot/src/os/aix/vm/os_aix.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os/aix/vm/os_aix.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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 @@ -113,6 +113,10 @@ #define RUSAGE_THREAD (1) /* only the calling thread */ #endif +// PPC port +static const uintx Use64KPagesThreshold = 1*M; +static const uintx MaxExpectedDataSegmentSize = SIZE_4G*2; + // Add missing declarations (should be in procinfo.h but isn't until AIX 6.1). #if !defined(_AIXVERSION_610) extern "C" { @@ -168,8 +172,8 @@ return -1; \ } -// query dimensions of the stack of the calling thread -static void query_stack_dimensions(address* p_stack_base, size_t* p_stack_size); +// Query dimensions of the stack of the calling thread. +static bool query_stack_dimensions(address* p_stack_base, size_t* p_stack_size); // function to check a given stack pointer against given stack limits inline bool is_valid_stackpointer(stackptr_t sp, stackptr_t stack_base, size_t stack_size) { @@ -220,9 +224,6 @@ int os::Aix::_on_pase = -1; int os::Aix::_os_version = -1; int os::Aix::_stack_page_size = -1; -size_t os::Aix::_shm_default_page_size = -1; -int os::Aix::_can_use_64K_pages = -1; -int os::Aix::_can_use_16M_pages = -1; int os::Aix::_xpg_sus_mode = -1; int os::Aix::_extshm = -1; int os::Aix::_logical_cpus = -1; @@ -238,7 +239,63 @@ static pid_t _initial_pid = 0; static int SR_signum = SIGUSR2; // Signal used to suspend/resume a thread (must be > SIGSEGV, see 4355769) static sigset_t SR_sigset; -static pthread_mutex_t dl_mutex; // Used to protect dlsym() calls. + +// This describes the state of multipage support of the underlying +// OS. Note that this is of no interest to the outsize world and +// therefore should not be defined in AIX class. +// +// AIX supports four different page sizes - 4K, 64K, 16MB, 16GB. The +// latter two (16M "large" resp. 16G "huge" pages) require special +// setup and are normally not available. +// +// AIX supports multiple page sizes per process, for: +// - Stack (of the primordial thread, so not relevant for us) +// - Data - data, bss, heap, for us also pthread stacks +// - Text - text code +// - shared memory +// +// Default page sizes can be set via linker options (-bdatapsize, -bstacksize, ...) +// and via environment variable LDR_CNTRL (DATAPSIZE, STACKPSIZE, ...). +// +// For shared memory, page size can be set dynamically via +// shmctl(). Different shared memory regions can have different page +// sizes. +// +// More information can be found at AIBM info center: +// http://publib.boulder.ibm.com/infocenter/aix/v6r1/index.jsp?topic=/com.ibm.aix.prftungd/doc/prftungd/multiple_page_size_app_support.htm +// +static struct { + size_t pagesize; // sysconf _SC_PAGESIZE (4K) + size_t datapsize; // default data page size (LDR_CNTRL DATAPSIZE) + size_t shmpsize; // default shared memory page size (LDR_CNTRL SHMPSIZE) + size_t pthr_stack_pagesize; // stack page size of pthread threads + size_t textpsize; // default text page size (LDR_CNTRL STACKPSIZE) + bool can_use_64K_pages; // True if we can alloc 64K pages dynamically with Sys V shm. + bool can_use_16M_pages; // True if we can alloc 16M pages dynamically with Sys V shm. + int error; // Error describing if something went wrong at multipage init. +} g_multipage_support = { + (size_t) -1, + (size_t) -1, + (size_t) -1, + (size_t) -1, + (size_t) -1, + false, false, + 0 +}; + +// We must not accidentally allocate memory close to the BRK - even if +// that would work - because then we prevent the BRK segment from +// growing which may result in a malloc OOM even though there is +// enough memory. The problem only arises if we shmat() or mmap() at +// a specific wish address, e.g. to place the heap in a +// compressed-oops-friendly way. +static bool is_close_to_brk(address a) { + address a1 = (address) sbrk(0); + if (a >= a1 && a < (a1 + MaxExpectedDataSegmentSize)) { + return true; + } + return false; +} julong os::available_memory() { return Aix::available_memory(); @@ -257,19 +314,6 @@ return Aix::physical_memory(); } -//////////////////////////////////////////////////////////////////////////////// -// environment support - -bool os::getenv(const char* name, char* buf, int len) { - const char* val = ::getenv(name); - if (val != NULL && strlen(val) < (size_t)len) { - strcpy(buf, val); - return true; - } - if (len > 0) buf[0] = 0; // return a null string - return false; -} - // Return true if user is running as root. bool os::have_special_privileges() { @@ -291,7 +335,7 @@ } // Maximum size 32bit disclaim() accepts. (Theoretically 4GB, but I just do not trust that.) - const unsigned int maxDisclaimSize = 0x80000000; + const unsigned int maxDisclaimSize = 0x40000000; const unsigned int numFullDisclaimsNeeded = (size / maxDisclaimSize); const unsigned int lastDisclaimSize = (size % maxDisclaimSize); @@ -368,138 +412,131 @@ case SIZE_64K: return "64K"; case SIZE_16M: return "16M"; case SIZE_16G: return "16G"; + case -1: return "not set"; default: assert(false, "surprise"); return "??"; } } -// Retrieve information about multipage size support. Will initialize -// Aix::_page_size, Aix::_stack_page_size, Aix::_can_use_64K_pages, -// Aix::_can_use_16M_pages. +// Probe OS for multipage support. +// Will fill the global g_multipage_support structure. // Must be called before calling os::large_page_init(). -void os::Aix::query_multipage_support() { - - guarantee(_page_size == -1 && - _stack_page_size == -1 && - _can_use_64K_pages == -1 && - _can_use_16M_pages == -1 && - g_multipage_error == -1, +static void query_multipage_support() { + + guarantee(g_multipage_support.pagesize == -1, "do not call twice"); - _page_size = ::sysconf(_SC_PAGESIZE); + g_multipage_support.pagesize = ::sysconf(_SC_PAGESIZE); // This really would surprise me. - assert(_page_size == SIZE_4K, "surprise!"); - + assert(g_multipage_support.pagesize == SIZE_4K, "surprise!"); // Query default data page size (default page size for C-Heap, pthread stacks and .bss). - // Default data page size is influenced either by linker options (-bdatapsize) + // Default data page size is defined either by linker options (-bdatapsize) // or by environment variable LDR_CNTRL (suboption DATAPSIZE). If none is given, // default should be 4K. - size_t data_page_size = SIZE_4K; { - void* p = os::malloc(SIZE_16M, mtInternal); - guarantee(p != NULL, "malloc failed"); - data_page_size = os::Aix::query_pagesize(p); - os::free(p); - } - - // query default shm page size (LDR_CNTRL SHMPSIZE) + void* p = ::malloc(SIZE_16M); + g_multipage_support.datapsize = os::Aix::query_pagesize(p); + ::free(p); + } + + // Query default shm page size (LDR_CNTRL SHMPSIZE). { const int shmid = ::shmget(IPC_PRIVATE, 1, IPC_CREAT | S_IRUSR | S_IWUSR); guarantee(shmid != -1, "shmget failed"); void* p = ::shmat(shmid, NULL, 0); ::shmctl(shmid, IPC_RMID, NULL); guarantee(p != (void*) -1, "shmat failed"); - _shm_default_page_size = os::Aix::query_pagesize(p); + g_multipage_support.shmpsize = os::Aix::query_pagesize(p); ::shmdt(p); } - // before querying the stack page size, make sure we are not running as primordial + // Before querying the stack page size, make sure we are not running as primordial // thread (because primordial thread's stack may have different page size than // pthread thread stacks). Running a VM on the primordial thread won't work for a - // number of reasons so we may just as well guarantee it here - guarantee(!os::Aix::is_primordial_thread(), "Must not be called for primordial thread"); - - // query stack page size + // number of reasons so we may just as well guarantee it here. + guarantee0(!os::Aix::is_primordial_thread()); + + // Query pthread stack page size. { int dummy = 0; - _stack_page_size = os::Aix::query_pagesize(&dummy); - // everything else would surprise me and should be looked into - guarantee(_stack_page_size == SIZE_4K || _stack_page_size == SIZE_64K, "Wrong page size"); - // also, just for completeness: pthread stacks are allocated from C heap, so - // stack page size should be the same as data page size - guarantee(_stack_page_size == data_page_size, "stack page size should be the same as data page size"); - } - - // EXTSHM is bad: among other things, it prevents setting pagesize dynamically - // for system V shm. - if (Aix::extshm()) { - if (Verbose) { - fprintf(stderr, "EXTSHM is active - will disable large page support.\n" - "Please make sure EXTSHM is OFF for large page support.\n"); - } - g_multipage_error = ERROR_MP_EXTSHM_ACTIVE; - _can_use_64K_pages = _can_use_16M_pages = 0; + g_multipage_support.pthr_stack_pagesize = os::Aix::query_pagesize(&dummy); + } + + // Query default text page size (LDR_CNTRL TEXTPSIZE). + /* PPC port: so far unused. + { + address any_function = + (address) resolve_function_descriptor_to_code_pointer((address)describe_pagesize); + g_multipage_support.textpsize = os::Aix::query_pagesize(any_function); + } + */ + + // Now probe for support of 64K pages and 16M pages. + + // Before OS/400 V6R1, there is no support for pages other than 4K. + if (os::Aix::on_pase_V5R4_or_older()) { + Unimplemented(); goto query_multipage_support_end; } - // now check which page sizes the OS claims it supports, and of those, which actually can be used. + // Now check which page sizes the OS claims it supports, and of those, which actually can be used. { const int MAX_PAGE_SIZES = 4; psize_t sizes[MAX_PAGE_SIZES]; const int num_psizes = ::vmgetinfo(sizes, VMINFO_GETPSIZES, MAX_PAGE_SIZES); if (num_psizes == -1) { - if (Verbose) { - fprintf(stderr, "vmgetinfo(VMINFO_GETPSIZES) failed (errno: %d)\n", errno); - fprintf(stderr, "disabling multipage support.\n"); - } - g_multipage_error = ERROR_MP_VMGETINFO_FAILED; - _can_use_64K_pages = _can_use_16M_pages = 0; + trc("vmgetinfo(VMINFO_GETPSIZES) failed (errno: %d)\n", errno); + trc("disabling multipage support.\n"); + g_multipage_support.error = ERROR_MP_VMGETINFO_FAILED; goto query_multipage_support_end; } guarantee(num_psizes > 0, "vmgetinfo(.., VMINFO_GETPSIZES, ...) failed."); assert(num_psizes <= MAX_PAGE_SIZES, "Surprise! more than 4 page sizes?"); - if (Verbose) { - fprintf(stderr, "vmgetinfo(.., VMINFO_GETPSIZES, ...) returns %d supported page sizes: ", num_psizes); - for (int i = 0; i < num_psizes; i ++) { - fprintf(stderr, " %s ", describe_pagesize(sizes[i])); - } - fprintf(stderr, " .\n"); + trcVerbose("vmgetinfo(.., VMINFO_GETPSIZES, ...) returns %d supported page sizes: ", num_psizes); + for (int i = 0; i < num_psizes; i ++) { + trcVerbose(" %s ", describe_pagesize(sizes[i])); } // Can we use 64K, 16M pages? - _can_use_64K_pages = 0; - _can_use_16M_pages = 0; for (int i = 0; i < num_psizes; i ++) { - if (sizes[i] == SIZE_64K) { - _can_use_64K_pages = 1; - } else if (sizes[i] == SIZE_16M) { - _can_use_16M_pages = 1; + const size_t pagesize = sizes[i]; + if (pagesize != SIZE_64K && pagesize != SIZE_16M) { + continue; } - } - - if (!_can_use_64K_pages) { - g_multipage_error = ERROR_MP_VMGETINFO_CLAIMS_NO_SUPPORT_FOR_64K; - } - - // Double-check for 16M pages: Even if AIX claims to be able to use 16M pages, - // there must be an actual 16M page pool, and we must run with enough rights. - if (_can_use_16M_pages) { - const int shmid = ::shmget(IPC_PRIVATE, SIZE_16M, IPC_CREAT | S_IRUSR | S_IWUSR); - guarantee(shmid != -1, "shmget failed"); + bool can_use = false; + trcVerbose("Probing support for %s pages...", describe_pagesize(pagesize)); + const int shmid = ::shmget(IPC_PRIVATE, pagesize, + IPC_CREAT | S_IRUSR | S_IWUSR); + guarantee0(shmid != -1); // Should always work. + // Try to set pagesize. struct shmid_ds shm_buf = { 0 }; - shm_buf.shm_pagesize = SIZE_16M; - const bool can_set_pagesize = ::shmctl(shmid, SHM_PAGESIZE, &shm_buf) == 0 ? true : false; - const int en = errno; - ::shmctl(shmid, IPC_RMID, NULL); - if (!can_set_pagesize) { - if (Verbose) { - fprintf(stderr, "Failed to allocate even one misely 16M page. shmctl failed with %d (%s).\n" - "Will deactivate 16M support.\n", en, strerror(en)); + shm_buf.shm_pagesize = pagesize; + if (::shmctl(shmid, SHM_PAGESIZE, &shm_buf) != 0) { + const int en = errno; + ::shmctl(shmid, IPC_RMID, NULL); // As early as possible! + // PPC port trcVerbose("shmctl(SHM_PAGESIZE) failed with %s", + // PPC port MiscUtils::describe_errno(en)); + } else { + // Attach and double check pageisze. + void* p = ::shmat(shmid, NULL, 0); + ::shmctl(shmid, IPC_RMID, NULL); // As early as possible! + guarantee0(p != (void*) -1); // Should always work. + const size_t real_pagesize = os::Aix::query_pagesize(p); + if (real_pagesize != pagesize) { + trcVerbose("real page size (0x%llX) differs.", real_pagesize); + } else { + can_use = true; } - _can_use_16M_pages = 0; + ::shmdt(p); + } + trcVerbose("Can use: %s", (can_use ? "yes" : "no")); + if (pagesize == SIZE_64K) { + g_multipage_support.can_use_64K_pages = can_use; + } else if (pagesize == SIZE_16M) { + g_multipage_support.can_use_16M_pages = can_use; } } @@ -507,23 +544,29 @@ query_multipage_support_end: - guarantee(_page_size != -1 && - _stack_page_size != -1 && - _can_use_64K_pages != -1 && - _can_use_16M_pages != -1, "Page sizes not properly initialized"); - - if (_can_use_64K_pages) { - g_multipage_error = 0; - } - - if (Verbose) { - fprintf(stderr, "Data page size (C-Heap, bss, etc): %s\n", describe_pagesize(data_page_size)); - fprintf(stderr, "Thread stack page size (pthread): %s\n", describe_pagesize(_stack_page_size)); - fprintf(stderr, "Default shared memory page size: %s\n", describe_pagesize(_shm_default_page_size)); - fprintf(stderr, "Can use 64K pages dynamically with shared meory: %s\n", (_can_use_64K_pages ? "yes" :"no")); - fprintf(stderr, "Can use 16M pages dynamically with shared memory: %s\n", (_can_use_16M_pages ? "yes" :"no")); - fprintf(stderr, "Multipage error details: %d\n", g_multipage_error); - } + trcVerbose("base page size (sysconf _SC_PAGESIZE): %s\n", + describe_pagesize(g_multipage_support.pagesize)); + trcVerbose("Data page size (C-Heap, bss, etc): %s\n", + describe_pagesize(g_multipage_support.datapsize)); + trcVerbose("Text page size: %s\n", + describe_pagesize(g_multipage_support.textpsize)); + trcVerbose("Thread stack page size (pthread): %s\n", + describe_pagesize(g_multipage_support.pthr_stack_pagesize)); + trcVerbose("Default shared memory page size: %s\n", + describe_pagesize(g_multipage_support.shmpsize)); + trcVerbose("Can use 64K pages dynamically with shared meory: %s\n", + (g_multipage_support.can_use_64K_pages ? "yes" :"no")); + trcVerbose("Can use 16M pages dynamically with shared memory: %s\n", + (g_multipage_support.can_use_16M_pages ? "yes" :"no")); + trcVerbose("Multipage error details: %d\n", + g_multipage_support.error); + + // sanity checks + assert0(g_multipage_support.pagesize == SIZE_4K); + assert0(g_multipage_support.datapsize == SIZE_4K || g_multipage_support.datapsize == SIZE_64K); + // PPC port: so far unused.assert0(g_multipage_support.textpsize == SIZE_4K || g_multipage_support.textpsize == SIZE_64K); + assert0(g_multipage_support.pthr_stack_pagesize == g_multipage_support.datapsize); + assert0(g_multipage_support.shmpsize == SIZE_4K || g_multipage_support.shmpsize == SIZE_64K); } // end os::Aix::query_multipage_support() @@ -1225,6 +1268,10 @@ // called from signal handler. Before adding something to os::abort(), make // sure it is async-safe and can handle partially initialized VM. void os::abort(bool dump_core) { + abort(dump_core, NULL, NULL); +} + +void os::abort(bool dump_core, void* siginfo, void* context) { os::shutdown(); if (dump_core) { #ifndef PRODUCT @@ -1492,13 +1539,8 @@ return NULL; } -// Glibc-2.0 libdl is not MT safe. If you are building with any glibc, -// chances are you might want to run the generated bits against glibc-2.0 -// libdl.so, so always use locking for any version of glibc. void* os::dll_lookup(void* handle, const char* name) { - pthread_mutex_lock(&dl_mutex); void* res = dlsym(handle, name); - pthread_mutex_unlock(&dl_mutex); return res; } @@ -1572,9 +1614,12 @@ st->print_cr(" default page size: %s", describe_pagesize(os::vm_page_size())); st->print_cr(" default stack page size: %s", describe_pagesize(os::vm_page_size())); - st->print_cr(" default shm page size: %s", describe_pagesize(os::Aix::shm_default_page_size())); - st->print_cr(" can use 64K pages dynamically: %s", (os::Aix::can_use_64K_pages() ? "yes" :"no")); - st->print_cr(" can use 16M pages dynamically: %s", (os::Aix::can_use_16M_pages() ? "yes" :"no")); + st->print_cr(" Default shared memory page size: %s", + describe_pagesize(g_multipage_support.shmpsize)); + st->print_cr(" Can use 64K pages dynamically with shared meory: %s", + (g_multipage_support.can_use_64K_pages ? "yes" :"no")); + st->print_cr(" Can use 16M pages dynamically with shared memory: %s", + (g_multipage_support.can_use_16M_pages ? "yes" :"no")); if (g_multipage_error != 0) { st->print_cr(" multipage error: %d", g_multipage_error); } @@ -1585,6 +1630,9 @@ const char* const extshm = ::getenv("EXTSHM"); st->print_cr(" EXTSHM=%s.", extshm ? extshm : ""); + if ( (strcmp(extshm, "on") == 0) || (strcmp(extshm, "ON") == 0) ) { + st->print_cr(" *** Unsupported! Please remove EXTSHM from your environment! ***"); + } // Call os::Aix::get_meminfo() to retrieve memory statistics. os::Aix::meminfo_t mi; @@ -1827,315 +1875,386 @@ //////////////////////////////////////////////////////////////////////////////// // Virtual Memory -// AddrRange describes an immutable address range -// -// This is a helper class for the 'shared memory bookkeeping' below. -class AddrRange { - friend class ShmBkBlock; - - char* _start; - size_t _size; - -public: - - AddrRange(char* start, size_t size) - : _start(start), _size(size) - {} - - AddrRange(const AddrRange& r) - : _start(r.start()), _size(r.size()) - {} - - char* start() const { return _start; } - size_t size() const { return _size; } - char* end() const { return _start + _size; } - bool is_empty() const { return _size == 0 ? true : false; } - - static AddrRange empty_range() { return AddrRange(NULL, 0); } - - bool contains(const char* p) const { - return start() <= p && end() > p; - } - - bool contains(const AddrRange& range) const { - return start() <= range.start() && end() >= range.end(); - } - - bool intersects(const AddrRange& range) const { - return (range.start() <= start() && range.end() > start()) || - (range.start() < end() && range.end() >= end()) || - contains(range); - } - - bool is_same_range(const AddrRange& range) const { - return start() == range.start() && size() == range.size(); - } - - // return the closest inside range consisting of whole pages - AddrRange find_closest_aligned_range(size_t pagesize) const { - if (pagesize == 0 || is_empty()) { - return empty_range(); +// We need to keep small simple bookkeeping for os::reserve_memory and friends. + +#define VMEM_MAPPED 1 +#define VMEM_SHMATED 2 + +struct vmembk_t { + int type; // 1 - mmap, 2 - shmat + char* addr; + size_t size; // Real size, may be larger than usersize. + size_t pagesize; // page size of area + vmembk_t* next; + + bool contains_addr(char* p) const { + return p >= addr && p < (addr + size); + } + + bool contains_range(char* p, size_t s) const { + return contains_addr(p) && contains_addr(p + s - 1); + } + + void print_on(outputStream* os) const { + os->print("[" PTR_FORMAT " - " PTR_FORMAT "] (" UINTX_FORMAT + " bytes, %d %s pages), %s", + addr, addr + size - 1, size, size / pagesize, describe_pagesize(pagesize), + (type == VMEM_SHMATED ? "shmat" : "mmap") + ); + } + + // Check that range is a sub range of memory block (or equal to memory block); + // also check that range is fully page aligned to the page size if the block. + void assert_is_valid_subrange(char* p, size_t s) const { + if (!contains_range(p, s)) { + fprintf(stderr, "[" PTR_FORMAT " - " PTR_FORMAT "] is not a sub " + "range of [" PTR_FORMAT " - " PTR_FORMAT "].\n", + p, p + s - 1, addr, addr + size - 1); + guarantee0(false); } - char* const from = (char*)align_size_up((intptr_t)_start, pagesize); - char* const to = (char*)align_size_down((intptr_t)end(), pagesize); - if (from > to) { - return empty_range(); + if (!is_aligned_to(p, pagesize) || !is_aligned_to(p + s, pagesize)) { + fprintf(stderr, "range [" PTR_FORMAT " - " PTR_FORMAT "] is not" + " aligned to pagesize (%s)\n", p, p + s); + guarantee0(false); } - return AddrRange(from, to - from); } }; -//////////////////////////////////////////////////////////////////////////// -// shared memory bookkeeping -// -// the os::reserve_memory() API and friends hand out different kind of memory, depending -// on need and circumstances. Memory may be allocated with mmap() or with shmget/shmat. -// -// But these memory types have to be treated differently. For example, to uncommit -// mmap-based memory, msync(MS_INVALIDATE) is needed, to uncommit shmat-based memory, -// disclaim64() is needed. -// -// Therefore we need to keep track of the allocated memory segments and their -// properties. - -// ShmBkBlock: base class for all blocks in the shared memory bookkeeping -class ShmBkBlock : public CHeapObj { - - ShmBkBlock* _next; - -protected: - - AddrRange _range; - const size_t _pagesize; - const bool _pinned; - -public: - - ShmBkBlock(AddrRange range, size_t pagesize, bool pinned) - : _range(range), _pagesize(pagesize), _pinned(pinned) , _next(NULL) { - - assert(_pagesize == SIZE_4K || _pagesize == SIZE_64K || _pagesize == SIZE_16M, "invalid page size"); - assert(!_range.is_empty(), "invalid range"); - } - - virtual void print(outputStream* st) const { - st->print("0x%p ... 0x%p (%llu) - %d %s pages - %s", - _range.start(), _range.end(), _range.size(), - _range.size() / _pagesize, describe_pagesize(_pagesize), - _pinned ? "pinned" : ""); - } - - enum Type { MMAP, SHMAT }; - virtual Type getType() = 0; - - char* base() const { return _range.start(); } - size_t size() const { return _range.size(); } - - void setAddrRange(AddrRange range) { - _range = range; - } - - bool containsAddress(const char* p) const { - return _range.contains(p); - } - - bool containsRange(const char* p, size_t size) const { - return _range.contains(AddrRange((char*)p, size)); - } - - bool isSameRange(const char* p, size_t size) const { - return _range.is_same_range(AddrRange((char*)p, size)); - } - - virtual bool disclaim(char* p, size_t size) = 0; - virtual bool release() = 0; - - // blocks live in a list. - ShmBkBlock* next() const { return _next; } - void set_next(ShmBkBlock* blk) { _next = blk; } - -}; // end: ShmBkBlock - - -// ShmBkMappedBlock: describes an block allocated with mmap() -class ShmBkMappedBlock : public ShmBkBlock { -public: - - ShmBkMappedBlock(AddrRange range) - : ShmBkBlock(range, SIZE_4K, false) {} // mmap: always 4K, never pinned - - void print(outputStream* st) const { - ShmBkBlock::print(st); - st->print_cr(" - mmap'ed"); - } - - Type getType() { - return MMAP; - } - - bool disclaim(char* p, size_t size) { - - AddrRange r(p, size); - - guarantee(_range.contains(r), "invalid disclaim"); - - // only disclaim whole ranges. - const AddrRange r2 = r.find_closest_aligned_range(_pagesize); - if (r2.is_empty()) { - return true; +static struct { + vmembk_t* first; + MiscUtils::CritSect cs; +} vmem; + +static void vmembk_add(char* addr, size_t size, size_t pagesize, int type) { + vmembk_t* p = (vmembk_t*) ::malloc(sizeof(vmembk_t)); + assert0(p); + if (p) { + MiscUtils::AutoCritSect lck(&vmem.cs); + p->addr = addr; p->size = size; + p->pagesize = pagesize; + p->type = type; + p->next = vmem.first; + vmem.first = p; + } +} + +static vmembk_t* vmembk_find(char* addr) { + MiscUtils::AutoCritSect lck(&vmem.cs); + for (vmembk_t* p = vmem.first; p; p = p->next) { + if (p->addr <= addr && (p->addr + p->size) > addr) { + return p; } - - const int rc = ::msync(r2.start(), r2.size(), MS_INVALIDATE); - - if (rc != 0) { - warning("msync(0x%p, %llu, MS_INVALIDATE) failed (%d)\n", r2.start(), r2.size(), errno); - } - - return rc == 0 ? true : false; - } - - bool release() { - // mmap'ed blocks are released using munmap - if (::munmap(_range.start(), _range.size()) != 0) { - warning("munmap(0x%p, %llu) failed (%d)\n", _range.start(), _range.size(), errno); - return false; - } - return true; - } -}; // end: ShmBkMappedBlock - -// ShmBkShmatedBlock: describes an block allocated with shmget/shmat() -class ShmBkShmatedBlock : public ShmBkBlock { -public: - - ShmBkShmatedBlock(AddrRange range, size_t pagesize, bool pinned) - : ShmBkBlock(range, pagesize, pinned) {} - - void print(outputStream* st) const { - ShmBkBlock::print(st); - st->print_cr(" - shmat'ed"); - } - - Type getType() { - return SHMAT; - } - - bool disclaim(char* p, size_t size) { - - AddrRange r(p, size); - - if (_pinned) { - return true; - } - - // shmat'ed blocks are disclaimed using disclaim64 - guarantee(_range.contains(r), "invalid disclaim"); - - // only disclaim whole ranges. - const AddrRange r2 = r.find_closest_aligned_range(_pagesize); - if (r2.is_empty()) { - return true; - } - - const bool rc = my_disclaim64(r2.start(), r2.size()); - - if (Verbose && !rc) { - warning("failed to disclaim shm %p-%p\n", r2.start(), r2.end()); - } - - return rc; - } - - bool release() { - bool rc = false; - if (::shmdt(_range.start()) != 0) { - warning("shmdt(0x%p) failed (%d)\n", _range.start(), errno); - } else { - rc = true; - } - return rc; - } - -}; // end: ShmBkShmatedBlock - -static ShmBkBlock* g_shmbk_list = NULL; -static volatile jint g_shmbk_table_lock = 0; - -// keep some usage statistics -static struct { - int nodes; // number of nodes in list - size_t bytes; // reserved - not committed - bytes. - int reserves; // how often reserve was called - int lookups; // how often a lookup was made -} g_shmbk_stats = { 0, 0, 0, 0 }; - -// add information about a shared memory segment to the bookkeeping -static void shmbk_register(ShmBkBlock* p_block) { - guarantee(p_block, "logic error"); - p_block->set_next(g_shmbk_list); - g_shmbk_list = p_block; - g_shmbk_stats.reserves ++; - g_shmbk_stats.bytes += p_block->size(); - g_shmbk_stats.nodes ++; -} - -// remove information about a shared memory segment by its starting address -static void shmbk_unregister(ShmBkBlock* p_block) { - ShmBkBlock* p = g_shmbk_list; - ShmBkBlock* prev = NULL; - while (p) { - if (p == p_block) { - if (prev) { - prev->set_next(p->next()); - } else { - g_shmbk_list = p->next(); - } - g_shmbk_stats.nodes --; - g_shmbk_stats.bytes -= p->size(); + } + return NULL; +} + +static void vmembk_remove(vmembk_t* p0) { + MiscUtils::AutoCritSect lck(&vmem.cs); + assert0(p0); + assert0(vmem.first); // List should not be empty. + for (vmembk_t** pp = &(vmem.first); *pp; pp = &((*pp)->next)) { + if (*pp == p0) { + *pp = p0->next; + ::free(p0); return; } - prev = p; - p = p->next(); - } - assert(false, "should not happen"); -} - -// given a pointer, return shared memory bookkeeping record for the segment it points into -// using the returned block info must happen under lock protection -static ShmBkBlock* shmbk_find_by_containing_address(const char* addr) { - g_shmbk_stats.lookups ++; - ShmBkBlock* p = g_shmbk_list; - while (p) { - if (p->containsAddress(addr)) { - return p; + } + assert0(false); // Not found? +} + +static void vmembk_print_on(outputStream* os) { + MiscUtils::AutoCritSect lck(&vmem.cs); + for (vmembk_t* vmi = vmem.first; vmi; vmi = vmi->next) { + vmi->print_on(os); + os->cr(); + } +} + +// Reserve and attach a section of System V memory. +// If is not NULL, function will attempt to attach the memory at the given +// address. Failing that, it will attach the memory anywhere. +// If is NULL, function will attach the memory anywhere. +// +// is being ignored by this function. It is very probable however that the +// alignment requirements are met anyway, because shmat() attaches at 256M boundaries. +// Should this be not enogh, we can put more work into it. +static char* reserve_shmated_memory ( + size_t bytes, + char* requested_addr, + size_t alignment_hint) { + + trcVerbose("reserve_shmated_memory " UINTX_FORMAT " bytes, wishaddress " + PTR_FORMAT ", alignment_hint " UINTX_FORMAT "...", + bytes, requested_addr, alignment_hint); + + // Either give me wish address or wish alignment but not both. + assert0(!(requested_addr != NULL && alignment_hint != 0)); + + // We must prevent anyone from attaching too close to the + // BRK because that may cause malloc OOM. + if (requested_addr != NULL && is_close_to_brk((address)requested_addr)) { + trcVerbose("Wish address " PTR_FORMAT " is too close to the BRK segment. " + "Will attach anywhere.", requested_addr); + // Act like the OS refused to attach there. + requested_addr = NULL; + } + + // For old AS/400's (V5R4 and older) we should not even be here - System V shared memory is not + // really supported (max size 4GB), so reserve_mmapped_memory should have been used instead. + if (os::Aix::on_pase_V5R4_or_older()) { + ShouldNotReachHere(); + } + + // Align size of shm up to 64K to avoid errors if we later try to change the page size. + const size_t size = align_size_up(bytes, SIZE_64K); + + // Reserve the shared segment. + int shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | S_IRUSR | S_IWUSR); + if (shmid == -1) { + trc("shmget(.., " UINTX_FORMAT ", ..) failed (errno: %d).", size, errno); + return NULL; + } + + // Important note: + // It is very important that we, upon leaving this function, do not leave a shm segment alive. + // We must right after attaching it remove it from the system. System V shm segments are global and + // survive the process. + // So, from here on: Do not assert, do not return, until we have called shmctl(IPC_RMID) (A). + + struct shmid_ds shmbuf; + memset(&shmbuf, 0, sizeof(shmbuf)); + shmbuf.shm_pagesize = SIZE_64K; + if (shmctl(shmid, SHM_PAGESIZE, &shmbuf) != 0) { + trcVerbose("Failed to set page size (need " UINTX_FORMAT " 64K pages) - shmctl failed with %d.", + size / SIZE_64K, errno); + // I want to know if this ever happens. + assert(false, "failed to set page size for shmat"); + } + + // Now attach the shared segment. + // Note that I attach with SHM_RND - which means that the requested address is rounded down, if + // needed, to the next lowest segment boundary. Otherwise the attach would fail if the address + // were not a segment boundary. + char* const addr = (char*) shmat(shmid, requested_addr, SHM_RND); + const int errno_shmat = errno; + + // (A) Right after shmat and before handing shmat errors delete the shm segment. + if (::shmctl(shmid, IPC_RMID, NULL) == -1) { + trc("shmctl(%u, IPC_RMID) failed (%d)\n", shmid, errno); + assert(false, "failed to remove shared memory segment!"); + } + + // Handle shmat error. If we failed to attach, just return. + if (addr == (char*)-1) { + trcVerbose("Failed to attach segment at " PTR_FORMAT " (%d).", requested_addr, errno_shmat); + return NULL; + } + + // Just for info: query the real page size. In case setting the page size did not + // work (see above), the system may have given us something other then 4K (LDR_CNTRL). + const size_t real_pagesize = os::Aix::query_pagesize(addr); + if (real_pagesize != shmbuf.shm_pagesize) { + trcVerbose("pagesize is, surprisingly, %h.", real_pagesize); + } + + if (addr) { + trcVerbose("shm-allocated " PTR_FORMAT " .. " PTR_FORMAT " (" UINTX_FORMAT " bytes, " UINTX_FORMAT " %s pages)", + addr, addr + size - 1, size, size/real_pagesize, describe_pagesize(real_pagesize)); + } else { + if (requested_addr != NULL) { + trcVerbose("failed to shm-allocate " UINTX_FORMAT " bytes at with address " PTR_FORMAT ".", size, requested_addr); + } else { + trcVerbose("failed to shm-allocate " UINTX_FORMAT " bytes at any address.", size); } - p = p->next(); - } - return NULL; -} - -// dump all information about all memory segments allocated with os::reserve_memory() -void shmbk_dump_info() { - tty->print_cr("-- shared mem bookkeeping (alive: %d segments, %llu bytes, " - "total reserves: %d total lookups: %d)", - g_shmbk_stats.nodes, g_shmbk_stats.bytes, g_shmbk_stats.reserves, g_shmbk_stats.lookups); - const ShmBkBlock* p = g_shmbk_list; - int i = 0; - while (p) { - p->print(tty); - p = p->next(); - i ++; - } -} - -#define LOCK_SHMBK { ThreadCritical _LOCK_SHMBK; -#define UNLOCK_SHMBK } + } + + // book-keeping + vmembk_add(addr, size, real_pagesize, VMEM_SHMATED); + assert0(is_aligned_to(addr, os::vm_page_size())); + + return addr; +} + +static bool release_shmated_memory(char* addr, size_t size) { + + trcVerbose("release_shmated_memory [" PTR_FORMAT " - " PTR_FORMAT "].", + addr, addr + size - 1); + + bool rc = false; + + // TODO: is there a way to verify shm size without doing bookkeeping? + if (::shmdt(addr) != 0) { + trcVerbose("error (%d).", errno); + } else { + trcVerbose("ok."); + rc = true; + } + return rc; +} + +static bool uncommit_shmated_memory(char* addr, size_t size) { + trcVerbose("uncommit_shmated_memory [" PTR_FORMAT " - " PTR_FORMAT "].", + addr, addr + size - 1); + + const bool rc = my_disclaim64(addr, size); + + if (!rc) { + trcVerbose("my_disclaim64(" PTR_FORMAT ", " UINTX_FORMAT ") failed.\n", addr, size); + return false; + } + return true; +} + +// Reserve memory via mmap. +// If is given, an attempt is made to attach at the given address. +// Failing that, memory is allocated at any address. +// If is given and is NULL, an attempt is made to +// allocate at an address aligned with the given alignment. Failing that, memory +// is aligned anywhere. +static char* reserve_mmaped_memory(size_t bytes, char* requested_addr, size_t alignment_hint) { + trcVerbose("reserve_mmaped_memory " UINTX_FORMAT " bytes, wishaddress " PTR_FORMAT ", " + "alignment_hint " UINTX_FORMAT "...", + bytes, requested_addr, alignment_hint); + + // If a wish address is given, but not aligned to 4K page boundary, mmap will fail. + if (requested_addr && !is_aligned_to(requested_addr, os::vm_page_size()) != 0) { + trcVerbose("Wish address " PTR_FORMAT " not aligned to page boundary.", requested_addr); + return NULL; + } + + // We must prevent anyone from attaching too close to the + // BRK because that may cause malloc OOM. + if (requested_addr != NULL && is_close_to_brk((address)requested_addr)) { + trcVerbose("Wish address " PTR_FORMAT " is too close to the BRK segment. " + "Will attach anywhere.", requested_addr); + // Act like the OS refused to attach there. + requested_addr = NULL; + } + + // Specify one or the other but not both. + assert0(!(requested_addr != NULL && alignment_hint > 0)); + + // In 64K mode, we claim the global page size (os::vm_page_size()) + // is 64K. This is one of the few points where that illusion may + // break, because mmap() will always return memory aligned to 4K. So + // we must ensure we only ever return memory aligned to 64k. + if (alignment_hint) { + alignment_hint = lcm(alignment_hint, os::vm_page_size()); + } else { + alignment_hint = os::vm_page_size(); + } + + // Size shall always be a multiple of os::vm_page_size (esp. in 64K mode). + const size_t size = align_size_up(bytes, os::vm_page_size()); + + // alignment: Allocate memory large enough to include an aligned range of the right size and + // cut off the leading and trailing waste pages. + assert0(alignment_hint != 0 && is_aligned_to(alignment_hint, os::vm_page_size())); // see above + const size_t extra_size = size + alignment_hint; + + // Note: MAP_SHARED (instead of MAP_PRIVATE) needed to be able to + // later use msync(MS_INVALIDATE) (see os::uncommit_memory). + int flags = MAP_ANONYMOUS | MAP_SHARED; + + // MAP_FIXED is needed to enforce requested_addr - manpage is vague about what + // it means if wishaddress is given but MAP_FIXED is not set. + // + // Important! Behaviour differs depending on whether SPEC1170 mode is active or not. + // SPEC1170 mode active: behaviour like POSIX, MAP_FIXED will clobber existing mappings. + // SPEC1170 mode not active: behaviour, unlike POSIX, is that no existing mappings will + // get clobbered. + if (requested_addr != NULL) { + if (!os::Aix::xpg_sus_mode()) { // not SPEC1170 Behaviour + flags |= MAP_FIXED; + } + } + + char* addr = (char*)::mmap(requested_addr, extra_size, + PROT_READ|PROT_WRITE|PROT_EXEC, flags, -1, 0); + + if (addr == MAP_FAILED) { + trcVerbose("mmap(" PTR_FORMAT ", " UINTX_FORMAT ", ..) failed (%d)", requested_addr, size, errno); + return NULL; + } + + // Handle alignment. + char* const addr_aligned = (char *)align_ptr_up(addr, alignment_hint); + const size_t waste_pre = addr_aligned - addr; + char* const addr_aligned_end = addr_aligned + size; + const size_t waste_post = extra_size - waste_pre - size; + if (waste_pre > 0) { + ::munmap(addr, waste_pre); + } + if (waste_post > 0) { + ::munmap(addr_aligned_end, waste_post); + } + addr = addr_aligned; + + if (addr) { + trcVerbose("mmap-allocated " PTR_FORMAT " .. " PTR_FORMAT " (" UINTX_FORMAT " bytes)", + addr, addr + bytes, bytes); + } else { + if (requested_addr != NULL) { + trcVerbose("failed to mmap-allocate " UINTX_FORMAT " bytes at wish address " PTR_FORMAT ".", bytes, requested_addr); + } else { + trcVerbose("failed to mmap-allocate " UINTX_FORMAT " bytes at any address.", bytes); + } + } + + // bookkeeping + vmembk_add(addr, size, SIZE_4K, VMEM_MAPPED); + + // Test alignment, see above. + assert0(is_aligned_to(addr, os::vm_page_size())); + + return addr; +} + +static bool release_mmaped_memory(char* addr, size_t size) { + assert0(is_aligned_to(addr, os::vm_page_size())); + assert0(is_aligned_to(size, os::vm_page_size())); + + trcVerbose("release_mmaped_memory [" PTR_FORMAT " - " PTR_FORMAT "].", + addr, addr + size - 1); + bool rc = false; + + if (::munmap(addr, size) != 0) { + trcVerbose("failed (%d)\n", errno); + rc = false; + } else { + trcVerbose("ok."); + rc = true; + } + + return rc; +} + +static bool uncommit_mmaped_memory(char* addr, size_t size) { + + assert0(is_aligned_to(addr, os::vm_page_size())); + assert0(is_aligned_to(size, os::vm_page_size())); + + trcVerbose("uncommit_mmaped_memory [" PTR_FORMAT " - " PTR_FORMAT "].", + addr, addr + size - 1); + bool rc = false; + + // Uncommit mmap memory with msync MS_INVALIDATE. + if (::msync(addr, size, MS_INVALIDATE) != 0) { + trcVerbose("failed (%d)\n", errno); + rc = false; + } else { + trcVerbose("ok."); + rc = true; + } + + return rc; +} // End: shared memory bookkeeping //////////////////////////////////////////////////////////////////////////////////////////////////// int os::vm_page_size() { - // Seems redundant as all get out + // Seems redundant as all get out. assert(os::Aix::page_size() != -1, "must call os::init"); return os::Aix::page_size(); } @@ -2146,91 +2265,76 @@ return os::Aix::page_size(); } -int os::Aix::commit_memory_impl(char* addr, size_t size, bool exec) { - - // Commit is a noop. There is no explicit commit - // needed on AIX. Memory is committed when touched. - // - // Debug : check address range for validity -#ifdef ASSERT - LOCK_SHMBK - ShmBkBlock* const block = shmbk_find_by_containing_address(addr); - if (!block) { - fprintf(stderr, "invalid pointer: " INTPTR_FORMAT "\n", addr); - shmbk_dump_info(); - assert(false, "invalid pointer"); - return false; - } else if (!block->containsRange(addr, size)) { - fprintf(stderr, "invalid range: " INTPTR_FORMAT " .. " INTPTR_FORMAT "\n", addr, addr + size); - shmbk_dump_info(); - assert(false, "invalid range"); - return false; - } - UNLOCK_SHMBK -#endif // ASSERT - - return 0; -} - -bool os::pd_commit_memory(char* addr, size_t size, bool exec) { - return os::Aix::commit_memory_impl(addr, size, exec) == 0; -} +#ifdef PRODUCT +static void warn_fail_commit_memory(char* addr, size_t size, bool exec, + int err) { + warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT + ", %d) failed; error='%s' (errno=%d)", addr, size, exec, + strerror(err), err); +} +#endif void os::pd_commit_memory_or_exit(char* addr, size_t size, bool exec, const char* mesg) { assert(mesg != NULL, "mesg must be specified"); - os::Aix::commit_memory_impl(addr, size, exec); -} - -int os::Aix::commit_memory_impl(char* addr, size_t size, - size_t alignment_hint, bool exec) { - return os::Aix::commit_memory_impl(addr, size, exec); -} - -bool os::pd_commit_memory(char* addr, size_t size, size_t alignment_hint, - bool exec) { - return os::Aix::commit_memory_impl(addr, size, alignment_hint, exec) == 0; + if (!pd_commit_memory(addr, size, exec)) { + // Add extra info in product mode for vm_exit_out_of_memory(): + PRODUCT_ONLY(warn_fail_commit_memory(addr, size, exec, errno);) + vm_exit_out_of_memory(size, OOM_MMAP_ERROR, mesg); + } +} + +bool os::pd_commit_memory(char* addr, size_t size, bool exec) { + + assert0(is_aligned_to(addr, os::vm_page_size())); + assert0(is_aligned_to(size, os::vm_page_size())); + + vmembk_t* const vmi = vmembk_find(addr); + assert0(vmi); + vmi->assert_is_valid_subrange(addr, size); + + trcVerbose("commit_memory [" PTR_FORMAT " - " PTR_FORMAT "].", addr, addr + size - 1); + + return true; +} + +bool os::pd_commit_memory(char* addr, size_t size, size_t alignment_hint, bool exec) { + return pd_commit_memory(addr, size, exec); } void os::pd_commit_memory_or_exit(char* addr, size_t size, size_t alignment_hint, bool exec, const char* mesg) { - os::Aix::commit_memory_impl(addr, size, alignment_hint, exec); + // Alignment_hint is ignored on this OS. + pd_commit_memory_or_exit(addr, size, exec, mesg); } bool os::pd_uncommit_memory(char* addr, size_t size) { - - // Delegate to ShmBkBlock class which knows how to uncommit its memory. - - bool rc = false; - LOCK_SHMBK - ShmBkBlock* const block = shmbk_find_by_containing_address(addr); - if (!block) { - fprintf(stderr, "invalid pointer: 0x%p.\n", addr); - shmbk_dump_info(); - assert(false, "invalid pointer"); - return false; - } else if (!block->containsRange(addr, size)) { - fprintf(stderr, "invalid range: 0x%p .. 0x%p.\n", addr, addr + size); - shmbk_dump_info(); - assert(false, "invalid range"); - return false; - } - rc = block->disclaim(addr, size); - UNLOCK_SHMBK - - if (Verbose && !rc) { - warning("failed to disclaim 0x%p .. 0x%p (0x%llX bytes).", addr, addr + size, size); - } - return rc; + assert0(is_aligned_to(addr, os::vm_page_size())); + assert0(is_aligned_to(size, os::vm_page_size())); + + // Dynamically do different things for mmap/shmat. + const vmembk_t* const vmi = vmembk_find(addr); + assert0(vmi); + vmi->assert_is_valid_subrange(addr, size); + + if (vmi->type == VMEM_SHMATED) { + return uncommit_shmated_memory(addr, size); + } else { + return uncommit_mmaped_memory(addr, size); + } } bool os::pd_create_stack_guard_pages(char* addr, size_t size) { - return os::guard_memory(addr, size); + // Do not call this; no need to commit stack pages on AIX. + ShouldNotReachHere(); + return true; } bool os::remove_stack_guard_pages(char* addr, size_t size) { - return os::unguard_memory(addr, size); + // Do not call this; no need to commit stack pages on AIX. + ShouldNotReachHere(); + return true; } void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) { @@ -2273,355 +2377,75 @@ return end; } -// Flags for reserve_shmatted_memory: -#define RESSHM_WISHADDR_OR_FAIL 1 -#define RESSHM_TRY_16M_PAGES 2 -#define RESSHM_16M_PAGES_OR_FAIL 4 - -// Result of reserve_shmatted_memory: -struct shmatted_memory_info_t { - char* addr; - size_t pagesize; - bool pinned; -}; - -// Reserve a section of shmatted memory. -// params: -// bytes [in]: size of memory, in bytes -// requested_addr [in]: wish address. -// NULL = no wish. -// If RESSHM_WISHADDR_OR_FAIL is set in flags and wish address cannot -// be obtained, function will fail. Otherwise wish address is treated as hint and -// another pointer is returned. -// flags [in]: some flags. Valid flags are: -// RESSHM_WISHADDR_OR_FAIL - fail if wish address is given and cannot be obtained. -// RESSHM_TRY_16M_PAGES - try to allocate from 16M page pool -// (requires UseLargePages and Use16MPages) -// RESSHM_16M_PAGES_OR_FAIL - if you cannot allocate from 16M page pool, fail. -// Otherwise any other page size will do. -// p_info [out] : holds information about the created shared memory segment. -static bool reserve_shmatted_memory(size_t bytes, char* requested_addr, int flags, shmatted_memory_info_t* p_info) { - - assert(p_info, "parameter error"); - - // init output struct. - p_info->addr = NULL; - - // neither should we be here for EXTSHM=ON. - if (os::Aix::extshm()) { - ShouldNotReachHere(); - } - - // extract flags. sanity checks. - const bool wishaddr_or_fail = - flags & RESSHM_WISHADDR_OR_FAIL; - const bool try_16M_pages = - flags & RESSHM_TRY_16M_PAGES; - const bool f16M_pages_or_fail = - flags & RESSHM_16M_PAGES_OR_FAIL; - - // first check: if a wish address is given and it is mandatory, but not aligned to segment boundary, - // shmat will fail anyway, so save some cycles by failing right away - if (requested_addr && ((uintptr_t)requested_addr % SIZE_256M == 0)) { - if (wishaddr_or_fail) { - return false; - } else { - requested_addr = NULL; - } - } - - char* addr = NULL; - - // Align size of shm up to the largest possible page size, to avoid errors later on when we try to change - // pagesize dynamically. - const size_t size = align_size_up(bytes, SIZE_16M); - - // reserve the shared segment - int shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | S_IRUSR | S_IWUSR); - if (shmid == -1) { - warning("shmget(.., %lld, ..) failed (errno: %d).", size, errno); - return false; - } - - // Important note: - // It is very important that we, upon leaving this function, do not leave a shm segment alive. - // We must right after attaching it remove it from the system. System V shm segments are global and - // survive the process. - // So, from here on: Do not assert. Do not return. Always do a "goto cleanup_shm". - - // try forcing the page size - size_t pagesize = -1; // unknown so far - - if (UseLargePages) { - - struct shmid_ds shmbuf; - memset(&shmbuf, 0, sizeof(shmbuf)); - - // First, try to take from 16M page pool if... - if (os::Aix::can_use_16M_pages() // we can ... - && Use16MPages // we are not explicitly forbidden to do so (-XX:-Use16MPages).. - && try_16M_pages) { // caller wants us to. - shmbuf.shm_pagesize = SIZE_16M; - if (shmctl(shmid, SHM_PAGESIZE, &shmbuf) == 0) { - pagesize = SIZE_16M; - } else { - warning("Failed to allocate %d 16M pages. 16M page pool might be exhausted. (shmctl failed with %d)", - size / SIZE_16M, errno); - if (f16M_pages_or_fail) { - goto cleanup_shm; - } - } - } - - // Nothing yet? Try setting 64K pages. Note that I never saw this fail, but in theory it might, - // because the 64K page pool may also be exhausted. - if (pagesize == -1) { - shmbuf.shm_pagesize = SIZE_64K; - if (shmctl(shmid, SHM_PAGESIZE, &shmbuf) == 0) { - pagesize = SIZE_64K; - } else { - warning("Failed to allocate %d 64K pages. (shmctl failed with %d)", - size / SIZE_64K, errno); - // here I give up. leave page_size -1 - later, after attaching, we will query the - // real page size of the attached memory. (in theory, it may be something different - // from 4K if LDR_CNTRL SHM_PSIZE is set) - } - } - } - - // sanity point - assert(pagesize == -1 || pagesize == SIZE_16M || pagesize == SIZE_64K, "wrong page size"); - - // Now attach the shared segment. - addr = (char*) shmat(shmid, requested_addr, 0); - if (addr == (char*)-1) { - // How to handle attach failure: - // If it failed for a specific wish address, tolerate this: in that case, if wish address was - // mandatory, fail, if not, retry anywhere. - // If it failed for any other reason, treat that as fatal error. - addr = NULL; - if (requested_addr) { - if (wishaddr_or_fail) { - goto cleanup_shm; - } else { - addr = (char*) shmat(shmid, NULL, 0); - if (addr == (char*)-1) { // fatal - addr = NULL; - warning("shmat failed (errno: %d)", errno); - goto cleanup_shm; - } - } - } else { // fatal - addr = NULL; - warning("shmat failed (errno: %d)", errno); - goto cleanup_shm; - } - } - - // sanity point - assert(addr && addr != (char*) -1, "wrong address"); - - // after successful Attach remove the segment - right away. - if (::shmctl(shmid, IPC_RMID, NULL) == -1) { - warning("shmctl(%u, IPC_RMID) failed (%d)\n", shmid, errno); - guarantee(false, "failed to remove shared memory segment!"); - } - shmid = -1; - - // query the real page size. In case setting the page size did not work (see above), the system - // may have given us something other then 4K (LDR_CNTRL) - { - const size_t real_pagesize = os::Aix::query_pagesize(addr); - if (pagesize != -1) { - assert(pagesize == real_pagesize, "unexpected pagesize after shmat"); - } else { - pagesize = real_pagesize; - } - } - - // Now register the reserved block with internal book keeping. - LOCK_SHMBK - const bool pinned = pagesize >= SIZE_16M ? true : false; - ShmBkShmatedBlock* const p_block = new ShmBkShmatedBlock(AddrRange(addr, size), pagesize, pinned); - assert(p_block, ""); - shmbk_register(p_block); - UNLOCK_SHMBK - -cleanup_shm: - - // if we have not done so yet, remove the shared memory segment. This is very important. - if (shmid != -1) { - if (::shmctl(shmid, IPC_RMID, NULL) == -1) { - warning("shmctl(%u, IPC_RMID) failed (%d)\n", shmid, errno); - guarantee(false, "failed to remove shared memory segment!"); - } - shmid = -1; - } - - // trace - if (Verbose && !addr) { - if (requested_addr != NULL) { - warning("failed to shm-allocate 0x%llX bytes at wish address 0x%p.", size, requested_addr); - } else { - warning("failed to shm-allocate 0x%llX bytes at any address.", size); - } - } - - // hand info to caller - if (addr) { - p_info->addr = addr; - p_info->pagesize = pagesize; - p_info->pinned = pagesize == SIZE_16M ? true : false; - } - - // sanity test: - if (requested_addr && addr && wishaddr_or_fail) { - guarantee(addr == requested_addr, "shmat error"); - } - - // just one more test to really make sure we have no dangling shm segments. - guarantee(shmid == -1, "dangling shm segments"); - - return addr ? true : false; - -} // end: reserve_shmatted_memory - -// Reserve memory using mmap. Behaves the same as reserve_shmatted_memory(): -// will return NULL in case of an error. -static char* reserve_mmaped_memory(size_t bytes, char* requested_addr) { - - // if a wish address is given, but not aligned to 4K page boundary, mmap will fail. - if (requested_addr && ((uintptr_t)requested_addr % os::vm_page_size() != 0)) { - warning("Wish address 0x%p not aligned to page boundary.", requested_addr); - return NULL; - } - - const size_t size = align_size_up(bytes, SIZE_4K); - - // Note: MAP_SHARED (instead of MAP_PRIVATE) needed to be able to - // msync(MS_INVALIDATE) (see os::uncommit_memory) - int flags = MAP_ANONYMOUS | MAP_SHARED; - - // MAP_FIXED is needed to enforce requested_addr - manpage is vague about what - // it means if wishaddress is given but MAP_FIXED is not set. - // - // Note however that this changes semantics in SPEC1170 mode insofar as MAP_FIXED - // clobbers the address range, which is probably not what the caller wants. That's - // why I assert here (again) that the SPEC1170 compat mode is off. - // If we want to be able to run under SPEC1170, we have to do some porting and - // testing. - if (requested_addr != NULL) { - assert(!os::Aix::xpg_sus_mode(), "SPEC1170 mode not allowed."); - flags |= MAP_FIXED; - } - - char* addr = (char*)::mmap(requested_addr, size, PROT_READ|PROT_WRITE|PROT_EXEC, flags, -1, 0); - - if (addr == MAP_FAILED) { - // attach failed: tolerate for specific wish addresses. Not being able to attach - // anywhere is a fatal error. - if (requested_addr == NULL) { - // It's ok to fail here if the machine has not enough memory. - warning("mmap(NULL, 0x%llX, ..) failed (%d)", size, errno); - } - addr = NULL; - goto cleanup_mmap; - } - - // If we did request a specific address and that address was not available, fail. - if (addr && requested_addr) { - guarantee(addr == requested_addr, "unexpected"); - } - - // register this mmap'ed segment with book keeping - LOCK_SHMBK - ShmBkMappedBlock* const p_block = new ShmBkMappedBlock(AddrRange(addr, size)); - assert(p_block, ""); - shmbk_register(p_block); - UNLOCK_SHMBK - -cleanup_mmap: - - // trace - if (Verbose) { - if (addr) { - fprintf(stderr, "mmap-allocated 0x%p .. 0x%p (0x%llX bytes)\n", addr, addr + bytes, bytes); - } - else { - if (requested_addr != NULL) { - warning("failed to mmap-allocate 0x%llX bytes at wish address 0x%p.", bytes, requested_addr); - } else { - warning("failed to mmap-allocate 0x%llX bytes at any address.", bytes); - } - } - } - - return addr; - -} // end: reserve_mmaped_memory - // Reserves and attaches a shared memory segment. // Will assert if a wish address is given and could not be obtained. char* os::pd_reserve_memory(size_t bytes, char* requested_addr, size_t alignment_hint) { - return os::attempt_reserve_memory_at(bytes, requested_addr); + + // All other Unices do a mmap(MAP_FIXED) if the addr is given, + // thereby clobbering old mappings at that place. That is probably + // not intended, never used and almost certainly an error were it + // ever be used this way (to try attaching at a specified address + // without clobbering old mappings an alternate API exists, + // os::attempt_reserve_memory_at()). + // Instead of mimicking the dangerous coding of the other platforms, here I + // just ignore the request address (release) or assert(debug). + assert0(requested_addr == NULL); + + // Always round to os::vm_page_size(), which may be larger than 4K. + bytes = align_size_up(bytes, os::vm_page_size()); + const size_t alignment_hint0 = + alignment_hint ? align_size_up(alignment_hint, os::vm_page_size()) : 0; + + // In 4K mode always use mmap. + // In 64K mode allocate small sizes with mmap, large ones with 64K shmatted. + if (os::vm_page_size() == SIZE_4K) { + return reserve_mmaped_memory(bytes, requested_addr, alignment_hint); + } else { + if (bytes >= Use64KPagesThreshold) { + return reserve_shmated_memory(bytes, requested_addr, alignment_hint); + } else { + return reserve_mmaped_memory(bytes, requested_addr, alignment_hint); + } + } } bool os::pd_release_memory(char* addr, size_t size) { - // delegate to ShmBkBlock class which knows how to uncommit its memory. + // Dynamically do different things for mmap/shmat. + vmembk_t* const vmi = vmembk_find(addr); + assert0(vmi); + + // Always round to os::vm_page_size(), which may be larger than 4K. + size = align_size_up(size, os::vm_page_size()); + addr = (char *)align_ptr_up(addr, os::vm_page_size()); bool rc = false; - LOCK_SHMBK - ShmBkBlock* const block = shmbk_find_by_containing_address(addr); - if (!block) { - fprintf(stderr, "invalid pointer: 0x%p.\n", addr); - shmbk_dump_info(); - assert(false, "invalid pointer"); - return false; + bool remove_bookkeeping = false; + if (vmi->type == VMEM_SHMATED) { + // For shmatted memory, we do: + // - If user wants to release the whole range, release the memory (shmdt). + // - If user only wants to release a partial range, uncommit (disclaim) that + // range. That way, at least, we do not use memory anymore (bust still page + // table space). + vmi->assert_is_valid_subrange(addr, size); + if (addr == vmi->addr && size == vmi->size) { + rc = release_shmated_memory(addr, size); + remove_bookkeeping = true; + } else { + rc = uncommit_shmated_memory(addr, size); } - else if (!block->isSameRange(addr, size)) { - if (block->getType() == ShmBkBlock::MMAP) { - // Release only the same range or a the beginning or the end of a range. - if (block->base() == addr && size < block->size()) { - ShmBkMappedBlock* const b = new ShmBkMappedBlock(AddrRange(block->base() + size, block->size() - size)); - assert(b, ""); - shmbk_register(b); - block->setAddrRange(AddrRange(addr, size)); - } - else if (addr > block->base() && addr + size == block->base() + block->size()) { - ShmBkMappedBlock* const b = new ShmBkMappedBlock(AddrRange(block->base(), block->size() - size)); - assert(b, ""); - shmbk_register(b); - block->setAddrRange(AddrRange(addr, size)); - } - else { - fprintf(stderr, "invalid mmap range: 0x%p .. 0x%p.\n", addr, addr + size); - shmbk_dump_info(); - assert(false, "invalid mmap range"); - return false; - } - } - else { - // Release only the same range. No partial release allowed. - // Soften the requirement a bit, because the user may think he owns a smaller size - // than the block is due to alignment etc. - if (block->base() != addr || block->size() < size) { - fprintf(stderr, "invalid shmget range: 0x%p .. 0x%p.\n", addr, addr + size); - shmbk_dump_info(); - assert(false, "invalid shmget range"); - return false; - } - } - } - rc = block->release(); - assert(rc, "release failed"); - // remove block from bookkeeping - shmbk_unregister(block); - delete block; - UNLOCK_SHMBK - - if (!rc) { - warning("failed to released %lu bytes at 0x%p", size, addr); + } else { + // User may unmap partial regions but region has to be fully contained. +#ifdef ASSERT + vmi->assert_is_valid_subrange(addr, size); +#endif + rc = release_mmaped_memory(addr, size); + remove_bookkeeping = true; + } + + // update bookkeeping + if (rc && remove_bookkeeping) { + vmembk_remove(vmi); } return rc; @@ -2654,7 +2478,7 @@ // if (!os::Aix::xpg_sus_mode()) { - if (StubRoutines::SafeFetch32_stub()) { + if (CanUseSafeFetch32()) { const bool read_protected = (SafeFetch32((int*)addr, 0x12345678) == 0x12345678 && @@ -2702,46 +2526,8 @@ // Enable large page support if OS allows that. void os::large_page_init() { - - // Note: os::Aix::query_multipage_support must run first. - - if (!UseLargePages) { - return; - } - - if (!Aix::can_use_64K_pages()) { - assert(!Aix::can_use_16M_pages(), "64K is a precondition for 16M."); - UseLargePages = false; - return; - } - - if (!Aix::can_use_16M_pages() && Use16MPages) { - fprintf(stderr, "Cannot use 16M pages. Please ensure that there is a 16M page pool " - " and that the VM runs with CAP_BYPASS_RAC_VMM and CAP_PROPAGATE capabilities.\n"); - } - - // Do not report 16M page alignment as part of os::_page_sizes if we are - // explicitly forbidden from using 16M pages. Doing so would increase the - // alignment the garbage collector calculates with, slightly increasing - // heap usage. We should only pay for 16M alignment if we really want to - // use 16M pages. - if (Use16MPages && Aix::can_use_16M_pages()) { - _large_page_size = SIZE_16M; - _page_sizes[0] = SIZE_16M; - _page_sizes[1] = SIZE_64K; - _page_sizes[2] = SIZE_4K; - _page_sizes[3] = 0; - } else if (Aix::can_use_64K_pages()) { - _large_page_size = SIZE_64K; - _page_sizes[0] = SIZE_64K; - _page_sizes[1] = SIZE_4K; - _page_sizes[2] = 0; - } - - if (Verbose) { - ("Default large page size is 0x%llX.", _large_page_size); - } -} // end: os::large_page_init() + return; // Nothing to do. See query_multipage_support and friends. +} char* os::reserve_memory_special(size_t bytes, size_t alignment, char* req_addr, bool exec) { // "exec" is passed in but not used. Creating the shared image for @@ -2751,7 +2537,7 @@ } bool os::release_memory_special(char* base, size_t bytes) { - // detaching the SHM segment will also delete it, see reserve_memory_special() + // Detaching the SHM segment will also delete it, see reserve_memory_special(). Unimplemented(); return false; } @@ -2761,40 +2547,32 @@ } bool os::can_commit_large_page_memory() { - // Well, sadly we cannot commit anything at all (see comment in - // os::commit_memory) but we claim to so we can make use of large pages - return true; + // Does not matter, we do not support huge pages. + return false; } bool os::can_execute_large_page_memory() { - // We can do that - return true; + // Does not matter, we do not support huge pages. + return false; } // Reserve memory at an arbitrary address, only if that area is // available (and not reserved for something else). char* os::pd_attempt_reserve_memory_at(size_t bytes, char* requested_addr) { - - bool use_mmap = false; - - // mmap: smaller graining, no large page support - // shm: large graining (256M), large page support, limited number of shm segments - // - // Prefer mmap wherever we either do not need large page support or have OS limits - - if (!UseLargePages || bytes < SIZE_16M) { - use_mmap = true; - } - char* addr = NULL; - if (use_mmap) { - addr = reserve_mmaped_memory(bytes, requested_addr); + + // Always round to os::vm_page_size(), which may be larger than 4K. + bytes = align_size_up(bytes, os::vm_page_size()); + + // In 4K mode always use mmap. + // In 64K mode allocate small sizes with mmap, large ones with 64K shmatted. + if (os::vm_page_size() == SIZE_4K) { + return reserve_mmaped_memory(bytes, requested_addr, 0); } else { - // shmat: wish address is mandatory, and do not try 16M pages here. - shmatted_memory_info_t info; - const int flags = RESSHM_WISHADDR_OR_FAIL; - if (reserve_shmatted_memory(bytes, requested_addr, flags, &info)) { - addr = info.addr; + if (bytes >= Use64KPagesThreshold) { + return reserve_shmated_memory(bytes, requested_addr, 0); + } else { + return reserve_mmaped_memory(bytes, requested_addr, 0); } } @@ -3629,18 +3407,89 @@ // This is called _before_ the most of global arguments have been parsed. void os::init(void) { // This is basic, we want to know if that ever changes. - // (shared memory boundary is supposed to be a 256M aligned) + // (Shared memory boundary is supposed to be a 256M aligned.) assert(SHMLBA == ((uint64_t)0x10000000ULL)/*256M*/, "unexpected"); // First off, we need to know whether we run on AIX or PASE, and // the OS level we run on. os::Aix::initialize_os_info(); - // Scan environment (SPEC1170 behaviour, etc) + // Scan environment (SPEC1170 behaviour, etc). os::Aix::scan_environment(); // Check which pages are supported by AIX. - os::Aix::query_multipage_support(); + query_multipage_support(); + + // Act like we only have one page size by eliminating corner cases which + // we did not support very well anyway. + // We have two input conditions: + // 1) Data segment page size. This is controlled by linker setting (datapsize) on the + // launcher, and/or by LDR_CNTRL environment variable. The latter overrules the linker + // setting. + // Data segment page size is important for us because it defines the thread stack page + // size, which is needed for guard page handling, stack banging etc. + // 2) The ability to allocate 64k pages dynamically. If this is a given, java heap can + // and should be allocated with 64k pages. + // + // So, we do the following: + // LDR_CNTRL can_use_64K_pages_dynamically what we do remarks + // 4K no 4K old systems (aix 5.2, as/400 v5r4) or new systems with AME activated + // 4k yes 64k (treat 4k stacks as 64k) different loader than java and standard settings + // 64k no --- AIX 5.2 ? --- + // 64k yes 64k new systems and standard java loader (we set datapsize=64k when linking) + + // We explicitly leave no option to change page size, because only upgrading would work, + // not downgrading (if stack page size is 64k you cannot pretend its 4k). + + if (g_multipage_support.datapsize == SIZE_4K) { + // datapsize = 4K. Data segment, thread stacks are 4K paged. + if (g_multipage_support.can_use_64K_pages) { + // .. but we are able to use 64K pages dynamically. + // This would be typical for java launchers which are not linked + // with datapsize=64K (like, any other launcher but our own). + // + // In this case it would be smart to allocate the java heap with 64K + // to get the performance benefit, and to fake 64k pages for the + // data segment (when dealing with thread stacks). + // + // However, leave a possibility to downgrade to 4K, using + // -XX:-Use64KPages. + if (Use64KPages) { + trcVerbose("64K page mode (faked for data segment)"); + Aix::_page_size = SIZE_64K; + } else { + trcVerbose("4K page mode (Use64KPages=off)"); + Aix::_page_size = SIZE_4K; + } + } else { + // .. and not able to allocate 64k pages dynamically. Here, just + // fall back to 4K paged mode and use mmap for everything. + trcVerbose("4K page mode"); + Aix::_page_size = SIZE_4K; + FLAG_SET_ERGO(bool, Use64KPages, false); + } + } else { + // datapsize = 64k. Data segment, thread stacks are 64k paged. + // This normally means that we can allocate 64k pages dynamically. + // (There is one special case where this may be false: EXTSHM=on. + // but we decided to not support that mode). + assert0(g_multipage_support.can_use_64K_pages); + Aix::_page_size = SIZE_64K; + trcVerbose("64K page mode"); + FLAG_SET_ERGO(bool, Use64KPages, true); + } + + // Short-wire stack page size to base page size; if that works, we just remove + // that stack page size altogether. + Aix::_stack_page_size = Aix::_page_size; + + // For now UseLargePages is just ignored. + FLAG_SET_ERGO(bool, UseLargePages, false); + _page_sizes[0] = 0; + _large_page_size = -1; + + // debug trace + trcVerbose("os::vm_page_size %s\n", describe_pagesize(os::vm_page_size())); // Next, we need to initialize libo4 and libperfstat libraries. if (os::Aix::on_pase()) { @@ -3658,34 +3507,6 @@ // need libperfstat etc. os::Aix::initialize_system_info(); - // Initialize large page support. - if (UseLargePages) { - os::large_page_init(); - if (!UseLargePages) { - // initialize os::_page_sizes - _page_sizes[0] = Aix::page_size(); - _page_sizes[1] = 0; - if (Verbose) { - fprintf(stderr, "Large Page initialization failed: setting UseLargePages=0.\n"); - } - } - } else { - // initialize os::_page_sizes - _page_sizes[0] = Aix::page_size(); - _page_sizes[1] = 0; - } - - // debug trace - if (Verbose) { - fprintf(stderr, "os::vm_page_size 0x%llX\n", os::vm_page_size()); - fprintf(stderr, "os::large_page_size 0x%llX\n", os::large_page_size()); - fprintf(stderr, "os::_page_sizes = ( "); - for (int i = 0; _page_sizes[i]; i ++) { - fprintf(stderr, " %s ", describe_pagesize(_page_sizes[i])); - } - fprintf(stderr, ")\n"); - } - _initial_pid = getpid(); clock_tics_per_sec = sysconf(_SC_CLK_TCK); @@ -3698,7 +3519,15 @@ Aix::_main_thread = pthread_self(); initial_time_count = os::elapsed_counter(); - pthread_mutex_init(&dl_mutex, NULL); + + // If the pagesize of the VM is greater than 8K determine the appropriate + // number of initial guard pages. The user can change this with the + // command line arguments, if needed. + if (vm_page_size() > (int)Aix::vm_default_page_size()) { + StackYellowPages = 1; + StackRedPages = 1; + StackShadowPages = round_to((StackShadowPages*Aix::vm_default_page_size()), vm_page_size()) / vm_page_size(); + } } // This is called _after_ the global arguments have been parsed. @@ -3717,7 +3546,7 @@ const int prot = PROT_READ; const int flags = MAP_PRIVATE|MAP_ANONYMOUS; - // use optimized addresses for the polling page, + // Use optimized addresses for the polling page, // e.g. map it to a special 32-bit address. if (OptimizePollingPageLocation) { // architecture-specific list of address wishes: @@ -3739,7 +3568,7 @@ // iterate over the list of address wishes: for (int i=0; iprint("[Memory Serialize Page address: " INTPTR_FORMAT "]\n", (intptr_t)mem_serialize_page); + } #endif } @@ -3797,16 +3627,18 @@ // Add in 2*BytesPerWord times page size to account for VM stack during // class initialization depending on 32 or 64 bit VM. os::Aix::min_stack_allowed = MAX2(os::Aix::min_stack_allowed, - (size_t)(StackYellowPages+StackRedPages+StackShadowPages + - 2*BytesPerWord COMPILER2_PRESENT(+1)) * Aix::page_size()); + (size_t)(StackYellowPages+StackRedPages+StackShadowPages) * Aix::page_size() + + (2*BytesPerWord COMPILER2_PRESENT(+1)) * Aix::vm_default_page_size()); + + os::Aix::min_stack_allowed = align_size_up(os::Aix::min_stack_allowed, os::Aix::page_size()); size_t threadStackSizeInBytes = ThreadStackSize * K; if (threadStackSizeInBytes != 0 && threadStackSizeInBytes < os::Aix::min_stack_allowed) { - tty->print_cr("\nThe stack size specified is too small, " - "Specify at least %dk", - os::Aix::min_stack_allowed / K); - return JNI_ERR; + tty->print_cr("\nThe stack size specified is too small, " + "Specify at least %dk", + os::Aix::min_stack_allowed / K); + return JNI_ERR; } // Make the stack size a multiple of the page size so that @@ -3817,7 +3649,7 @@ Aix::libpthread_init(); if (MaxFDLimit) { - // set the number of file descriptors to max. print out error + // Set the number of file descriptors to max. print out error // if getrlimit/setrlimit fails but continue regardless. struct rlimit nbr_files; int status = getrlimit(RLIMIT_NOFILE, &nbr_files); @@ -3835,12 +3667,12 @@ } if (PerfAllowAtExitRegistration) { - // only register atexit functions if PerfAllowAtExitRegistration is set. - // atexit functions can be delayed until process exit time, which + // Only register atexit functions if PerfAllowAtExitRegistration is set. + // Atexit functions can be delayed until process exit time, which // can be problematic for embedded VM situations. Embedded VMs should // call DestroyJavaVM() to assure that VM resources are released. - // note: perfMemory_exit_helper atexit function may be removed in + // Note: perfMemory_exit_helper atexit function may be removed in // the future if the appropriate cleanup code can be added to the // VM_Exit VMOperation's doit method. if (atexit(perfMemory_exit_helper) != 0) { @@ -4162,8 +3994,10 @@ if (read_only) { prot = PROT_READ; + flags = MAP_SHARED; } else { prot = PROT_READ | PROT_WRITE; + flags = MAP_PRIVATE; } if (allow_exec) { @@ -4174,7 +4008,12 @@ flags |= MAP_FIXED; } - char* mapped_address = (char*)mmap(addr, (size_t)bytes, prot, flags, + // Allow anonymous mappings if 'fd' is -1. + if (fd == -1) { + flags |= MAP_ANONYMOUS; + } + + char* mapped_address = (char*)::mmap(addr, (size_t)bytes, prot, flags, fd, file_offset); if (mapped_address == MAP_FAILED) { return NULL; @@ -4432,7 +4271,7 @@ if (Verbose) { fprintf(stderr, "EXTSHM=%s.\n", p ? p : ""); } - if (p && strcmp(p, "ON") == 0) { + if (p && strcasecmp(p, "ON") == 0) { fprintf(stderr, "Unsupported setting: EXTSHM=ON. Large Page support will be disabled.\n"); _extshm = 1; } else { @@ -4493,16 +4332,13 @@ ///////////////////////////////////////////////////////////////////////////// // thread stack -// function to query the current stack size using pthread_getthrds_np -// -// ! do not change anything here unless you know what you are doing ! -static void query_stack_dimensions(address* p_stack_base, size_t* p_stack_size) { - +// Function to query the current stack size using pthread_getthrds_np. +static bool query_stack_dimensions(address* p_stack_base, size_t* p_stack_size) { // This only works when invoked on a pthread. As we agreed not to use - // primordial threads anyway, I assert here + // primordial threads anyway, I assert here. guarantee(!os::Aix::is_primordial_thread(), "not allowed on the primordial thread"); - // information about this api can be found (a) in the pthread.h header and + // Information about this api can be found (a) in the pthread.h header and // (b) in http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.basetechref/doc/basetrf1/pthread_getthrds_np.htm // // The use of this API to find out the current stack is kind of undefined. @@ -4513,57 +4349,72 @@ pthread_t tid = pthread_self(); struct __pthrdsinfo pinfo; - char dummy[1]; // we only need this to satisfy the api and to not get E + char dummy[1]; // We only need this to satisfy the api and to not get E. int dummy_size = sizeof(dummy); memset(&pinfo, 0, sizeof(pinfo)); - const int rc = pthread_getthrds_np (&tid, PTHRDSINFO_QUERY_ALL, &pinfo, - sizeof(pinfo), dummy, &dummy_size); + const int rc = pthread_getthrds_np(&tid, PTHRDSINFO_QUERY_ALL, &pinfo, + sizeof(pinfo), dummy, &dummy_size); if (rc != 0) { - fprintf(stderr, "pthread_getthrds_np failed (%d)\n", rc); - guarantee(0, "pthread_getthrds_np failed"); - } - - guarantee(pinfo.__pi_stackend, "returned stack base invalid"); - - // the following can happen when invoking pthread_getthrds_np on a pthread running on a user provided stack - // (when handing down a stack to pthread create, see pthread_attr_setstackaddr). + assert0(false); + trcVerbose("pthread_getthrds_np failed (%d)", rc); + return false; + } + guarantee0(pinfo.__pi_stackend); + + // The following can happen when invoking pthread_getthrds_np on a pthread running + // on a user provided stack (when handing down a stack to pthread create, see + // pthread_attr_setstackaddr). // Not sure what to do here - I feel inclined to forbid this use case completely. - guarantee(pinfo.__pi_stacksize, "returned stack size invalid"); - - // On AIX, stacks are not necessarily page aligned so round the base and size accordingly + guarantee0(pinfo.__pi_stacksize); + + // Note: the pthread stack on AIX seems to look like this: + // + // --------------------- real base ? at page border ? + // + // pthread internal data, like ~2K, see also + // http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.prftungd/doc/prftungd/thread_supp_tun_params.htm + // + // --------------------- __pi_stackend - not page aligned, (xxxxF890) + // + // stack + // .... + // + // stack + // + // --------------------- __pi_stackend - __pi_stacksize + // + // padding due to AIX guard pages (?) see AIXTHREAD_GUARDPAGES + // --------------------- __pi_stackaddr (page aligned if AIXTHREAD_GUARDPAGES > 0) + // + // AIX guard pages (?) + // + + // So, the safe thing to do is to use the area from __pi_stackend to __pi_stackaddr; + // __pi_stackend however is almost never page aligned. + // + if (p_stack_base) { - (*p_stack_base) = (address) align_size_up((intptr_t)pinfo.__pi_stackend, os::Aix::stack_page_size()); + (*p_stack_base) = (address) (pinfo.__pi_stackend); } if (p_stack_size) { - (*p_stack_size) = pinfo.__pi_stacksize - os::Aix::stack_page_size(); - } - -#ifndef PRODUCT - if (Verbose) { - fprintf(stderr, - "query_stack_dimensions() -> real stack_base=" INTPTR_FORMAT ", real stack_addr=" INTPTR_FORMAT - ", real stack_size=" INTPTR_FORMAT - ", stack_base=" INTPTR_FORMAT ", stack_size=" INTPTR_FORMAT "\n", - (intptr_t)pinfo.__pi_stackend, (intptr_t)pinfo.__pi_stackaddr, pinfo.__pi_stacksize, - (intptr_t)align_size_up((intptr_t)pinfo.__pi_stackend, os::Aix::stack_page_size()), - pinfo.__pi_stacksize - os::Aix::stack_page_size()); - } -#endif - -} // end query_stack_dimensions - -// get the current stack base from the OS (actually, the pthread library) + (*p_stack_size) = pinfo.__pi_stackend - pinfo.__pi_stackaddr; + } + + return true; +} + +// Get the current stack base from the OS (actually, the pthread library). address os::current_stack_base() { address p; query_stack_dimensions(&p, 0); return p; } -// get the current stack size from the OS (actually, the pthread library) +// Get the current stack size from the OS (actually, the pthread library). size_t os::current_stack_size() { size_t s; query_stack_dimensions(0, &s); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os/aix/vm/os_aix.hpp --- a/hotspot/src/os/aix/vm/os_aix.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os/aix/vm/os_aix.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2013 SAP AG. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013, 2015 SAP AG. 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 @@ -35,9 +35,9 @@ friend class os; // For signal-chaining - // highest so far (AIX 5.2) is SIGSAK (63) + // highest so far (AIX 5.2 - 6.1) is SIGSAK (63) #define MAXSIGNUM 63 - // length of strings included in the libperfstat structures + // Length of strings included in the libperfstat structures. #define IDENTIFIER_LENGTH 64 static struct sigaction sigact[MAXSIGNUM]; // saved preinstalled sigactions @@ -111,22 +111,6 @@ // (should be LDR_CNTRL DATAPSIZE because stack is allocated on heap by pthread lib) static int _stack_page_size; - // Default shm page size. Read: what page size shared memory will be backed - // with if no page size was set explicitly using shmctl(SHM_PAGESIZE). - // Should be LDR_CNTRL SHMPSIZE. - static size_t _shm_default_page_size; - - // True if sys V shm can be used with 64K pages dynamically. - // (via shmctl(.. SHM_PAGESIZE..). Should be true for AIX 53 and - // newer / PASE V6R1 and newer. (0 or 1, -1 if not initialized) - static int _can_use_64K_pages; - - // True if sys V shm can be used with 16M pages dynamically. - // (via shmctl(.. SHM_PAGESIZE..). Only true on AIX 5.3 and - // newer, if the system was set up to use 16M pages and the - // jvm has enough user rights. (0 or 1, -1 if not initialized) - static int _can_use_16M_pages; - static julong available_memory(); static julong physical_memory() { return _physical_memory; } static void initialize_system_info(); @@ -135,10 +119,6 @@ // one of Aix::on_pase(), Aix::os_version(). static void initialize_os_info(); - static int commit_memory_impl(char* addr, size_t bytes, bool exec); - static int commit_memory_impl(char* addr, size_t bytes, - size_t alignment_hint, bool exec); - // Scan environment for important settings which might effect the // VM. Trace out settings. Warn about invalid settings and/or // correct them. @@ -146,10 +126,6 @@ // Must run after os::Aix::initialue_os_info(). static void scan_environment(); - // Retrieve information about multipage size support. Will initialize - // _page_size, _stack_page_size, _can_use_64K_pages/_can_use_16M_pages - static void query_multipage_support(); - // Initialize libo4 (on PASE) and libperfstat (on AIX). Call this // before relying on functions from either lib, e.g. Aix::get_meminfo(). static void initialize_libo4(); @@ -187,27 +163,8 @@ return _stack_page_size; } - // default shm page size. Read: what page size shared memory - // will be backed with if no page size was set explicitly using shmctl(SHM_PAGESIZE). - // Should be LDR_CNTRL SHMPSIZE. - static int shm_default_page_size(void) { - assert(_shm_default_page_size != -1, "not initialized"); - return _shm_default_page_size; - } - - // Return true if sys V shm can be used with 64K pages dynamically - // (via shmctl(.. SHM_PAGESIZE..). - static bool can_use_64K_pages () { - assert(_can_use_64K_pages != -1, "not initialized"); - return _can_use_64K_pages == 1 ? true : false; - } - - // Return true if sys V shm can be used with 16M pages dynamically. - // (via shmctl(.. SHM_PAGESIZE..). - static bool can_use_16M_pages () { - assert(_can_use_16M_pages != -1, "not initialized"); - return _can_use_16M_pages == 1 ? true : false; - } + // This is used to scale stack space (guard pages etc.). The name is somehow misleading. + static int vm_default_page_size(void ) { return 8*K; } static address ucontext_get_pc(const ucontext_t* uc); static intptr_t* ucontext_get_sp(ucontext_t* uc); @@ -269,6 +226,11 @@ return _os_version; } + // Convenience method: returns true if running on PASE V5R4 or older. + static bool on_pase_V5R4_or_older() { + return on_pase() && os_version() <= 0x0504; + } + // Convenience method: returns true if running on AIX 5.3 or older. static bool on_aix_53_or_older() { return on_aix() && os_version() <= 0x0503; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os/aix/vm/os_aix.inline.hpp --- a/hotspot/src/os/aix/vm/os_aix.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os/aix/vm/os_aix.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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 @@ -40,7 +40,7 @@ return pthread_getspecific((pthread_key_t)index); } -// File names are case-sensitive on windows only +// File names are case-sensitive on windows only. inline int os::file_name_strcmp(const char* s1, const char* s2) { return strcmp(s1, s2); } @@ -53,18 +53,19 @@ return true; } +// Whether or not calling code should/can commit/uncommit stack pages +// before guarding them. Answer for AIX is definitly no, because memory +// is automatically committed on touch. inline bool os::allocate_stack_guard_pages() { assert(uses_stack_guard_pages(), "sanity check"); - return true; + return false; } - // On Aix, reservations are made on a page by page basis, nothing to do. inline void os::pd_split_reserved_memory(char *base, size_t size, size_t split, bool realloc) { } - // Bang the shadow pages if they need to be touched to be mapped. inline void os::bang_stack_shadow_pages() { } @@ -75,15 +76,13 @@ inline const int os::default_file_open_flags() { return 0;} -inline DIR* os::opendir(const char* dirname) -{ +inline DIR* os::opendir(const char* dirname) { assert(dirname != NULL, "just checking"); return ::opendir(dirname); } -inline int os::readdir_buf_size(const char *path) -{ - // according to aix sys/limits, NAME_MAX must be retrieved at runtime. */ +inline int os::readdir_buf_size(const char *path) { + // According to aix sys/limits, NAME_MAX must be retrieved at runtime. const long my_NAME_MAX = pathconf(path, _PC_NAME_MAX); return my_NAME_MAX + sizeof(dirent) + 1; } @@ -104,8 +103,7 @@ return ::ftruncate64(fd, length); } -inline struct dirent* os::readdir(DIR* dirp, dirent *dbuf) -{ +inline struct dirent* os::readdir(DIR* dirp, dirent *dbuf) { dirent* p; int status; assert(dirp != NULL, "just checking"); @@ -174,11 +172,11 @@ RESTARTABLE_RETURN_INT(::send(fd, buf, nBytes, flags)); } -inline int os::raw_send(int fd, char* buf, size_t nBytes, uint flags) { +inline int os::raw_send(int fd, char *buf, size_t nBytes, uint flags) { return os::send(fd, buf, nBytes, flags); } -inline int os::connect(int fd, struct sockaddr* him, socklen_t len) { +inline int os::connect(int fd, struct sockaddr *him, socklen_t len) { RESTARTABLE_RETURN_INT(::connect(fd, him, len)); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os/aix/vm/perfMemory_aix.cpp --- a/hotspot/src/os/aix/vm/perfMemory_aix.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os/aix/vm/perfMemory_aix.cpp Thu May 07 20:51:12 2015 -0700 @@ -797,7 +797,7 @@ // Close the directory and reset the current working directory. close_directory_secure_cwd(dirp, saved_cwd_fd); - FREE_C_HEAP_ARRAY(char, dbuf, mtInternal); + FREE_C_HEAP_ARRAY(char, dbuf); } // Make the user specific temporary directory. Returns true if @@ -1164,9 +1164,9 @@ // store file, we don't follow them when attaching either. // if (!is_directory_secure(dirname)) { - FREE_C_HEAP_ARRAY(char, dirname, mtInternal); + FREE_C_HEAP_ARRAY(char, dirname); if (luser != user) { - FREE_C_HEAP_ARRAY(char, luser, mtInternal); + FREE_C_HEAP_ARRAY(char, luser); } THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Process not found"); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os/aix/vm/porting_aix.hpp --- a/hotspot/src/os/aix/vm/porting_aix.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os/aix/vm/porting_aix.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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 @@ -22,8 +22,18 @@ * */ +#ifndef OS_AIX_VM_PORTING_AIX_HPP +#define OS_AIX_VM_PORTING_AIX_HPP + #include +// PPC port only: +#define assert0(b) assert( (b), "" ) +#define guarantee0(b) assert( (b), "" ) +template bool is_aligned_to(T1 what, T2 alignment) { + return ( ((uintx)(what)) & (((uintx)(alignment)) - 1) ) == 0 ? true : false; +} + // Header file to contain porting-relevant code which does not have a // home anywhere else and which can not go into os_.h because // that header is included inside the os class definition, hence all @@ -79,3 +89,62 @@ const struct tbtable** p_tb, // [out] optional: ptr to traceback table to get further information char* p_errmsg, size_t errmsglen // [out] optional: user provided buffer for error messages ); + +// ------------------------------------------------------------------------- + +// A simple critical section which shall be based upon OS critical +// sections (CRITICAL_SECTION resp. Posix Mutex) and nothing else. + +#include + +namespace MiscUtils { + typedef pthread_mutex_t critsect_t; + + inline void init_critsect(MiscUtils::critsect_t* cs) { + pthread_mutex_init(cs, NULL); + } + inline void free_critsect(MiscUtils::critsect_t* cs) { + pthread_mutex_destroy(cs); + } + inline void enter_critsect(MiscUtils::critsect_t* cs) { + pthread_mutex_lock(cs); + } + inline void leave_critsect(MiscUtils::critsect_t* cs) { + pthread_mutex_unlock(cs); + } + + // Need to wrap this in an object because we need to dynamically initialize + // critical section (because of windows, where there is no way to initialize + // a CRITICAL_SECTION statically. On Unix, we could use + // PTHREAD_MUTEX_INITIALIZER) + + // Note: The critical section does NOT get cleaned up in the destructor. That is + // by design: the CritSect class is only ever used as global objects whose + // lifetime spans the whole VM life; in that context we don't want the lock to + // be cleaned up when global C++ objects are destroyed, but to continue to work + // correctly right to the very end of the process life. + class CritSect { + critsect_t _cs; + public: + CritSect() { init_critsect(&_cs); } + //~CritSect() { free_critsect(&_cs); } + void enter() { enter_critsect(&_cs); } + void leave() { leave_critsect(&_cs); } + }; + + class AutoCritSect { + CritSect* const _pcsobj; + public: + AutoCritSect(CritSect* pcsobj) + : _pcsobj(pcsobj) + { + _pcsobj->enter(); + } + ~AutoCritSect() { + _pcsobj->leave(); + } + }; + +} + +#endif // OS_AIX_VM_PORTING_AIX_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os/bsd/dtrace/generateJvmOffsets.cpp --- a/hotspot/src/os/bsd/dtrace/generateJvmOffsets.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os/bsd/dtrace/generateJvmOffsets.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,12 +45,12 @@ #include "memory/heap.hpp" #include "memory/memRegion.hpp" #include "memory/universe.hpp" +#include "memory/virtualspace.hpp" #include "oops/constMethod.hpp" #include "oops/klass.hpp" #include "oops/method.hpp" #include "oops/oop.hpp" #include "oops/symbol.hpp" -#include "runtime/virtualspace.hpp" #include "runtime/vmStructs.hpp" #include "utilities/accessFlags.hpp" #include "utilities/globalDefinitions.hpp" diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os/bsd/dtrace/libjvm_db.c --- a/hotspot/src/os/bsd/dtrace/libjvm_db.c Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os/bsd/dtrace/libjvm_db.c Thu May 07 20:51:12 2015 -0700 @@ -582,13 +582,14 @@ CHECK_FAIL(err); result[0] = '\0'; - strncat(result, klassString, size); - size -= strlen(klassString); - strncat(result, ".", size); - size -= 1; - strncat(result, nameString, size); - size -= strlen(nameString); - strncat(result, signatureString, size); + if (snprintf(result, size, + "%s.%s%s", + klassString, + nameString, + signatureString) >= size) { + // truncation + goto fail; + } if (nameString != NULL) free(nameString); if (klassString != NULL) free(klassString); @@ -1095,9 +1096,9 @@ CHECK_FAIL(err); } if (deoptimized) { - strncat(result + 1, " [deoptimized frame]; ", size-1); + strncat(result, " [deoptimized frame]; ", size - strlen(result) - 1); } else { - strncat(result + 1, " [compiled] ", size-1); + strncat(result, " [compiled] ", size - strlen(result) - 1); } if (debug) fprintf(stderr, "name_for_nmethod: END: method name: %s, vf_cnt: %d\n\n", diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os/bsd/vm/decoder_machO.cpp --- a/hotspot/src/os/bsd/vm/decoder_machO.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os/bsd/vm/decoder_machO.cpp Thu May 07 20:51:12 2015 -0700 @@ -97,6 +97,7 @@ char * symname = mach_find_in_stringtable((char*) ((uintptr_t)mach_base + stroff), strsize, found_strx); if (symname) { strncpy(buf, symname, buflen); + buf[buflen - 1] = '\0'; return true; } DEBUG_ONLY(tty->print_cr("no string or null string found.")); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os/bsd/vm/os_bsd.cpp --- a/hotspot/src/os/bsd/vm/os_bsd.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp Thu May 07 20:51:12 2015 -0700 @@ -190,20 +190,6 @@ return Bsd::physical_memory(); } -//////////////////////////////////////////////////////////////////////////////// -// environment support - -bool os::getenv(const char* name, char* buf, int len) { - const char* val = ::getenv(name); - if (val != NULL && strlen(val) < (size_t)len) { - strcpy(buf, val); - return true; - } - if (len > 0) buf[0] = 0; // return a null string - return false; -} - - // Return true if user is running as root. bool os::have_special_privileges() { @@ -1146,6 +1132,10 @@ // called from signal handler. Before adding something to os::abort(), make // sure it is async-safe and can handle partially initialized VM. void os::abort(bool dump_core) { + abort(dump_core, NULL, NULL); +} + +void os::abort(bool dump_core, void* siginfo, void* context) { os::shutdown(); if (dump_core) { #ifndef PRODUCT @@ -1195,12 +1185,18 @@ guarantee(retval != 0, "just checking"); return retval; -#elif __FreeBSD__ +#else + #ifdef __FreeBSD__ retval = syscall(SYS_thr_self); -#elif __OpenBSD__ + #else + #ifdef __OpenBSD__ retval = syscall(SYS_getthrid); -#elif __NetBSD__ + #else + #ifdef __NetBSD__ retval = (pid_t) syscall(SYS__lwp_self); + #endif + #endif + #endif #endif if (retval == -1) { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os/linux/vm/os_linux.cpp --- a/hotspot/src/os/linux/vm/os_linux.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os/linux/vm/os_linux.cpp Thu May 07 20:51:12 2015 -0700 @@ -158,9 +158,6 @@ static int SR_signum = SIGUSR2; sigset_t SR_sigset; -// Used to protect dlsym() calls -static pthread_mutex_t dl_mutex; - // Declarations static void unpackTime(timespec* absTime, bool isAbsolute, jlong time); @@ -184,20 +181,6 @@ return Linux::physical_memory(); } -//////////////////////////////////////////////////////////////////////////////// -// environment support - -bool os::getenv(const char* name, char* buf, int len) { - const char* val = ::getenv(name); - if (val != NULL && strlen(val) < (size_t)len) { - strcpy(buf, val); - return true; - } - if (len > 0) buf[0] = 0; // return a null string - return false; -} - - // Return true if user is running as root. bool os::have_special_privileges() { @@ -215,14 +198,20 @@ // i386: 224, ia64: 1105, amd64: 186, sparc 143 #ifdef __ia64__ #define SYS_gettid 1105 - #elif __i386__ - #define SYS_gettid 224 - #elif __amd64__ - #define SYS_gettid 186 - #elif __sparc__ - #define SYS_gettid 143 #else - #error define gettid for the arch + #ifdef __i386__ + #define SYS_gettid 224 + #else + #ifdef __amd64__ + #define SYS_gettid 186 + #else + #ifdef __sparc__ + #define SYS_gettid 143 + #else + #error define gettid for the arch + #endif + #endif + #endif #endif #endif @@ -1490,6 +1479,10 @@ // called from signal handler. Before adding something to os::abort(), make // sure it is async-safe and can handle partially initialized VM. void os::abort(bool dump_core) { + abort(dump_core, NULL, NULL); +} + +void os::abort(bool dump_core, void* siginfo, void* context) { os::shutdown(); if (dump_core) { #ifndef PRODUCT @@ -2039,14 +2032,8 @@ return result; } -// glibc-2.0 libdl is not MT safe. If you are building with any glibc, -// chances are you might want to run the generated bits against glibc-2.0 -// libdl.so, so always use locking for any version of glibc. -// void* os::dll_lookup(void* handle, const char* name) { - pthread_mutex_lock(&dl_mutex); void* res = dlsym(handle, name); - pthread_mutex_unlock(&dl_mutex); return res; } @@ -4655,8 +4642,6 @@ } // else it defaults to CLOCK_REALTIME - pthread_mutex_init(&dl_mutex, NULL); - // If the pagesize of the VM is greater than 8K determine the appropriate // number of initial guard pages. The user can change this with the // command line arguments, if needed. diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os/posix/vm/os_posix.cpp --- a/hotspot/src/os/posix/vm/os_posix.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os/posix/vm/os_posix.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ #define IS_VALID_PID(p) (p > 0 && p < MAX_PID) // Check core dump limit and report possible place where core can be found -void os::check_or_create_dump(void* exceptionRecord, void* contextRecord, char* buffer, size_t bufferSize) { +void os::check_dump_limit(char* buffer, size_t bufferSize) { int n; struct rlimit rlim; bool success; @@ -82,7 +82,7 @@ } } - VMError::report_coredump_status(buffer, success); + VMError::record_coredump_status(buffer, success); } int os::get_native_stack(address* stack, int frames, int toSkip) { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os/solaris/dtrace/generateJvmOffsets.cpp --- a/hotspot/src/os/solaris/dtrace/generateJvmOffsets.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os/solaris/dtrace/generateJvmOffsets.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,12 +45,12 @@ #include "memory/heap.hpp" #include "memory/memRegion.hpp" #include "memory/universe.hpp" +#include "memory/virtualspace.hpp" #include "oops/constMethod.hpp" #include "oops/klass.hpp" #include "oops/method.hpp" #include "oops/oop.hpp" #include "oops/symbol.hpp" -#include "runtime/virtualspace.hpp" #include "runtime/vmStructs.hpp" #include "utilities/accessFlags.hpp" #include "utilities/globalDefinitions.hpp" diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os/solaris/dtrace/libjvm_db.c --- a/hotspot/src/os/solaris/dtrace/libjvm_db.c Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os/solaris/dtrace/libjvm_db.c Thu May 07 20:51:12 2015 -0700 @@ -582,13 +582,14 @@ CHECK_FAIL(err); result[0] = '\0'; - strncat(result, klassString, size); - size -= strlen(klassString); - strncat(result, ".", size); - size -= 1; - strncat(result, nameString, size); - size -= strlen(nameString); - strncat(result, signatureString, size); + if (snprintf(result, size, + "%s.%s%s", + klassString, + nameString, + signatureString) >= size) { + // truncation + goto fail; + } if (nameString != NULL) free(nameString); if (klassString != NULL) free(klassString); @@ -1095,9 +1096,9 @@ CHECK_FAIL(err); } if (deoptimized) { - strncat(result + 1, " [deoptimized frame]; ", size-1); + strncat(result, " [deoptimized frame]; ", size - strlen(result) - 1); } else { - strncat(result + 1, " [compiled] ", size-1); + strncat(result, " [compiled] ", size - strlen(result) - 1); } if (debug) fprintf(stderr, "name_for_nmethod: END: method name: %s, vf_cnt: %d\n\n", diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os/solaris/vm/os_solaris.cpp --- a/hotspot/src/os/solaris/vm/os_solaris.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Thu May 07 20:51:12 2015 -0700 @@ -555,17 +555,6 @@ return (bind_result == 0); } -bool os::getenv(const char* name, char* buffer, int len) { - char* val = ::getenv(name); - if (val == NULL || strlen(val) + 1 > len) { - if (len > 0) buffer[0] = 0; // return a null string - return false; - } - strcpy(buffer, val); - return true; -} - - // Return true if user is running as root. bool os::have_special_privileges() { @@ -1532,6 +1521,10 @@ // called from signal handler. Before adding something to os::abort(), make // sure it is async-safe and can handle partially initialized VM. void os::abort(bool dump_core) { + abort(dump_core, NULL, NULL); +} + +void os::abort(bool dump_core, void* siginfo, void* context) { os::shutdown(); if (dump_core) { #ifndef PRODUCT diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os/windows/vm/os_windows.cpp --- a/hotspot/src/os/windows/vm/os_windows.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os/windows/vm/os_windows.cpp Thu May 07 20:51:12 2015 -0700 @@ -114,10 +114,12 @@ #ifdef _M_IA64 #define __CPU__ ia64 -#elif _M_AMD64 - #define __CPU__ amd64 #else - #define __CPU__ i486 + #ifdef _M_AMD64 + #define __CPU__ amd64 + #else + #define __CPU__ i486 + #endif #endif // save DLL module handle, used by GetModuleFileName @@ -153,11 +155,6 @@ // Implementation of os -bool os::getenv(const char* name, char* buffer, int len) { - int result = GetEnvironmentVariable(name, buffer, len); - return result > 0 && result < len; -} - bool os::unsetenv(const char* name) { assert(name != NULL, "Null pointer"); return (SetEnvironmentVariable(name, NULL) == TRUE); @@ -188,9 +185,13 @@ char *dll_path; char *pslash; char *bin = "\\bin"; - char home_dir[MAX_PATH]; - - if (!getenv("_ALT_JAVA_HOME_DIR", home_dir, MAX_PATH)) { + char home_dir[MAX_PATH + 1]; + char *alt_home_dir = ::getenv("_ALT_JAVA_HOME_DIR"); + + if (alt_home_dir != NULL) { + strncpy(home_dir, alt_home_dir, MAX_PATH + 1); + home_dir[MAX_PATH] = '\0'; + } else { os::jvm_path(home_dir, sizeof(home_dir)); // Found the full path to jvm.dll. // Now cut the path to /jre if we can. @@ -988,7 +989,34 @@ PMINIDUMP_USER_STREAM_INFORMATION, PMINIDUMP_CALLBACK_INFORMATION); -void os::check_or_create_dump(void* exceptionRecord, void* contextRecord, char* buffer, size_t bufferSize) { +static HANDLE dumpFile = NULL; + +// Check if dump file can be created. +void os::check_dump_limit(char* buffer, size_t buffsz) { + bool status = true; + if (!FLAG_IS_DEFAULT(CreateCoredumpOnCrash) && !CreateCoredumpOnCrash) { + jio_snprintf(buffer, buffsz, "CreateCoredumpOnCrash is disabled from command line"); + status = false; + } else { + const char* cwd = get_current_directory(NULL, 0); + int pid = current_process_id(); + if (cwd != NULL) { + jio_snprintf(buffer, buffsz, "%s\\hs_err_pid%u.mdmp", cwd, pid); + } else { + jio_snprintf(buffer, buffsz, ".\\hs_err_pid%u.mdmp", pid); + } + + if (dumpFile == NULL && + (dumpFile = CreateFile(buffer, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) + == INVALID_HANDLE_VALUE) { + jio_snprintf(buffer, buffsz, "Failed to create minidump file (0x%x).", GetLastError()); + status = false; + } + } + VMError::record_coredump_status(buffer, status); +} + +void os::abort(bool dump_core, void* siginfo, void* context) { HINSTANCE dbghelp; EXCEPTION_POINTERS ep; MINIDUMP_EXCEPTION_INFORMATION mei; @@ -996,33 +1024,22 @@ HANDLE hProcess = GetCurrentProcess(); DWORD processId = GetCurrentProcessId(); - HANDLE dumpFile; MINIDUMP_TYPE dumpType; - static const char* cwd; - -// Default is to always create dump for debug builds, on product builds only dump on server versions of Windows. -#ifndef ASSERT - // If running on a client version of Windows and user has not explicitly enabled dumping - if (!os::win32::is_windows_server() && !CreateMinidumpOnCrash) { - VMError::report_coredump_status("Minidumps are not enabled by default on client versions of Windows", false); - return; - // If running on a server version of Windows and user has explictly disabled dumping - } else if (os::win32::is_windows_server() && !FLAG_IS_DEFAULT(CreateMinidumpOnCrash) && !CreateMinidumpOnCrash) { - VMError::report_coredump_status("Minidump has been disabled from the command line", false); - return; - } -#else - if (!FLAG_IS_DEFAULT(CreateMinidumpOnCrash) && !CreateMinidumpOnCrash) { - VMError::report_coredump_status("Minidump has been disabled from the command line", false); - return; - } -#endif + + shutdown(); + if (!dump_core || dumpFile == NULL) { + if (dumpFile != NULL) { + CloseHandle(dumpFile); + } + win32::exit_process_or_thread(win32::EPT_PROCESS, 1); + } dbghelp = os::win32::load_Windows_dll("DBGHELP.DLL", NULL, 0); if (dbghelp == NULL) { - VMError::report_coredump_status("Failed to load dbghelp.dll", false); - return; + jio_fprintf(stderr, "Failed to load dbghelp.dll\n"); + CloseHandle(dumpFile); + win32::exit_process_or_thread(win32::EPT_PROCESS, 1); } _MiniDumpWriteDump = @@ -1034,30 +1051,23 @@ "MiniDumpWriteDump")); if (_MiniDumpWriteDump == NULL) { - VMError::report_coredump_status("Failed to find MiniDumpWriteDump() in module dbghelp.dll", false); - return; + jio_fprintf(stderr, "Failed to find MiniDumpWriteDump() in module dbghelp.dll.\n"); + CloseHandle(dumpFile); + win32::exit_process_or_thread(win32::EPT_PROCESS, 1); } dumpType = (MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithHandleData); -// Older versions of dbghelp.h doesn't contain all the dumptypes we want, dbghelp.h with -// API_VERSION_NUMBER 11 or higher contains the ones we want though + // Older versions of dbghelp.h do not contain all the dumptypes we want, dbghelp.h with + // API_VERSION_NUMBER 11 or higher contains the ones we want though #if API_VERSION_NUMBER >= 11 dumpType = (MINIDUMP_TYPE)(dumpType | MiniDumpWithFullMemoryInfo | MiniDumpWithThreadInfo | MiniDumpWithUnloadedModules); #endif - cwd = get_current_directory(NULL, 0); - jio_snprintf(buffer, bufferSize, "%s\\hs_err_pid%u.mdmp", cwd, current_process_id()); - dumpFile = CreateFile(buffer, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - - if (dumpFile == INVALID_HANDLE_VALUE) { - VMError::report_coredump_status("Failed to create file for dumping", false); - return; - } - if (exceptionRecord != NULL && contextRecord != NULL) { - ep.ContextRecord = (PCONTEXT) contextRecord; - ep.ExceptionRecord = (PEXCEPTION_RECORD) exceptionRecord; + if (siginfo != NULL && context != NULL) { + ep.ContextRecord = (PCONTEXT) context; + ep.ExceptionRecord = (PEXCEPTION_RECORD) siginfo; mei.ThreadId = GetCurrentThreadId(); mei.ExceptionPointers = &ep; @@ -1066,38 +1076,18 @@ pmei = NULL; } - // Older versions of dbghelp.dll (the one shipped with Win2003 for example) may not support all // the dump types we really want. If first call fails, lets fall back to just use MiniDumpWithFullMemory then. if (_MiniDumpWriteDump(hProcess, processId, dumpFile, dumpType, pmei, NULL, NULL) == false && _MiniDumpWriteDump(hProcess, processId, dumpFile, (MINIDUMP_TYPE)MiniDumpWithFullMemory, pmei, NULL, NULL) == false) { - DWORD error = GetLastError(); - LPTSTR msgbuf = NULL; - - if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, error, 0, (LPTSTR)&msgbuf, 0, NULL) != 0) { - - jio_snprintf(buffer, bufferSize, "Call to MiniDumpWriteDump() failed (Error 0x%x: %s)", error, msgbuf); - LocalFree(msgbuf); - } else { - // Call to FormatMessage failed, just include the result from GetLastError - jio_snprintf(buffer, bufferSize, "Call to MiniDumpWriteDump() failed (Error 0x%x)", error); - } - VMError::report_coredump_status(buffer, false); - } else { - VMError::report_coredump_status(buffer, true); - } - + jio_fprintf(stderr, "Call to MiniDumpWriteDump() failed (Error 0x%x)\n", GetLastError()); + } CloseHandle(dumpFile); -} - + win32::exit_process_or_thread(win32::EPT_PROCESS, 1); +} void os::abort(bool dump_core) { - os::shutdown(); - // no core dump on Windows - win32::exit_process_or_thread(win32::EPT_PROCESS, 1); + abort(dump_core, NULL, NULL); } // Die immediately, no exit hook, no abort hook, no cleanup. @@ -2102,20 +2092,22 @@ // at the beginning of the target bundle. exceptionInfo->ContextRecord->StIPSR &= 0xFFFFF9FFFFFFFFFF; assert(((DWORD64)handler & 0xF) == 0, "Target address must point to the beginning of a bundle!"); -#elif _M_AMD64 +#else + #ifdef _M_AMD64 // Do not blow up if no thread info available. if (thread) { thread->set_saved_exception_pc((address)(DWORD_PTR)exceptionInfo->ContextRecord->Rip); } // Set pc to handler exceptionInfo->ContextRecord->Rip = (DWORD64)handler; -#else + #else // Do not blow up if no thread info available. if (thread) { thread->set_saved_exception_pc((address)(DWORD_PTR)exceptionInfo->ContextRecord->Eip); } // Set pc to handler exceptionInfo->ContextRecord->Eip = (DWORD)(DWORD_PTR)handler; + #endif #endif // Continue the execution @@ -2214,7 +2206,8 @@ // (division by zero is handled explicitly) #ifdef _M_IA64 assert(0, "Fix Handle_IDiv_Exception"); -#elif _M_AMD64 +#else + #ifdef _M_AMD64 PCONTEXT ctx = exceptionInfo->ContextRecord; address pc = (address)ctx->Rip; assert(pc[0] == 0xF7, "not an idiv opcode"); @@ -2225,7 +2218,7 @@ ctx->Rax = (DWORD)min_jint; // result ctx->Rdx = (DWORD)0; // remainder // Continue the execution -#else + #else PCONTEXT ctx = exceptionInfo->ContextRecord; address pc = (address)ctx->Eip; assert(pc[0] == 0xF7, "not an idiv opcode"); @@ -2236,6 +2229,7 @@ ctx->Eax = (DWORD)min_jint; // result ctx->Edx = (DWORD)0; // remainder // Continue the execution + #endif #endif return EXCEPTION_CONTINUE_EXECUTION; } @@ -2308,10 +2302,12 @@ // This is needed for IA64 because "relocation" / "implicit null check" / "poll instruction" // information is saved in the Unix format. address pc_unix_format = (address) ((((uint64_t)pc) & 0xFFFFFFFFFFFFFFF0) | ((((uint64_t)pc) & 0xF) >> 2)); -#elif _M_AMD64 +#else + #ifdef _M_AMD64 address pc = (address) exceptionInfo->ContextRecord->Rip; -#else + #else address pc = (address) exceptionInfo->ContextRecord->Eip; + #endif #endif Thread* t = ThreadLocalStorage::get_thread_slow(); // slow & steady @@ -2696,17 +2692,6 @@ } #endif -void os::win32::call_test_func_with_wrapper(void (*funcPtr)(void)) { - // Install a win32 structured exception handler around the test - // function call so the VM can generate an error dump if needed. - __try { - (*funcPtr)(); - } __except(topLevelExceptionFilter( - (_EXCEPTION_POINTERS*)_exception_info())) { - // Nothing to do. - } -} - // Virtual Memory int os::vm_page_size() { return os::win32::vm_page_size(); } @@ -5930,4 +5915,3 @@ UseNUMAInterleaving = old_use_numa_interleaving; } #endif // PRODUCT - diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os/windows/vm/os_windows.hpp --- a/hotspot/src/os/windows/vm/os_windows.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os/windows/vm/os_windows.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -115,8 +115,6 @@ static address fast_jni_accessor_wrapper(BasicType); #endif - static void call_test_func_with_wrapper(void (*funcPtr)(void)); - // filter function to ignore faults on serializations page static LONG WINAPI serialize_fault_filter(struct _EXCEPTION_POINTERS* e); }; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os/windows/vm/os_windows.inline.hpp --- a/hotspot/src/os/windows/vm/os_windows.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os/windows/vm/os_windows.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -104,7 +104,4 @@ win32::exit_process_or_thread(win32::EPT_PROCESS, num); } -#define CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(f) \ - os::win32::call_test_func_with_wrapper(f) - #endif // OS_WINDOWS_VM_OS_WINDOWS_INLINE_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp --- a/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp Thu May 07 20:51:12 2015 -0700 @@ -59,6 +59,10 @@ #include "utilities/events.hpp" #include "utilities/vmError.hpp" +// See stubGenerator_zero.cpp +#include +extern sigjmp_buf* get_jmp_buf_for_continuation(); + address os::current_stack_pointer() { address dummy = (address) &dummy; return dummy; @@ -134,6 +138,14 @@ SignalHandlerMark shm(t); + // handle SafeFetch faults + if (sig == SIGSEGV || sig == SIGBUS) { + sigjmp_buf* const pjb = get_jmp_buf_for_continuation(); + if (pjb) { + siglongjmp(*pjb, 1); + } + } + // Note: it's not uncommon that JNI code uses signal/sigset to // install then restore certain signal handler (e.g. to temporarily // block SIGPIPE, or have a SIGILL handler when detecting CPU diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp --- a/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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 @@ -298,6 +298,7 @@ goto report_and_die; } + CodeBlob *cb = NULL; // Handle signal from NativeJump::patch_verified_entry(). if (( TrapBasedNotEntrantChecks && sig == SIGTRAP && nativeInstruction_at(pc)->is_sigtrap_zombie_not_entrant()) || (!TrapBasedNotEntrantChecks && sig == SIGILL && nativeInstruction_at(pc)->is_sigill_zombie_not_entrant())) { @@ -313,7 +314,10 @@ // especially when we try to read from the safepoint polling page. So the check // (address)info->si_addr == os::get_standard_polling_page() // doesn't work for us. We use: - ((NativeInstruction*)pc)->is_safepoint_poll()) { + ((NativeInstruction*)pc)->is_safepoint_poll() && + CodeCache::contains((void*) pc) && + ((cb = CodeCache::find_blob(pc)) != NULL) && + cb->is_nmethod()) { if (TraceTraps) { tty->print_cr("trap: safepoint_poll at " INTPTR_FORMAT " (SIGSEGV)", p2i(pc)); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp --- a/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Thu May 07 20:51:12 2015 -0700 @@ -54,6 +54,10 @@ #include "utilities/events.hpp" #include "utilities/vmError.hpp" +// See stubGenerator_zero.cpp +#include +extern sigjmp_buf* get_jmp_buf_for_continuation(); + address os::current_stack_pointer() { address dummy = (address) &dummy; return dummy; @@ -125,6 +129,14 @@ SignalHandlerMark shm(t); + // handle SafeFetch faults + if (sig == SIGSEGV || sig == SIGBUS) { + sigjmp_buf* const pjb = get_jmp_buf_for_continuation(); + if (pjb) { + siglongjmp(*pjb, 1); + } + } + // Note: it's not uncommon that JNI code uses signal/sigset to // install then restore certain signal handler (e.g. to temporarily // block SIGPIPE, or have a SIGILL handler when detecting CPU diff -r a4b1c7d6317a -r febd2373771c hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp --- a/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Thu May 07 20:51:12 2015 -0700 @@ -129,7 +129,7 @@ bool is_inconsistent() { return _state == INCONSISTENT; } void set_inconsistent() { _state = INCONSISTENT; } - void visit(picl_nodehdl_t nodeh, const char* name) { + bool visit(picl_nodehdl_t nodeh, const char* name) { assert(!is_inconsistent(), "Precondition"); int curr; if (_picl->get_int_property(nodeh, name, &curr) == PICL_SUCCESS) { @@ -138,7 +138,9 @@ } else if (curr != value()) { // following iterations set_inconsistent(); } + return true; } + return false; } }; @@ -155,8 +157,19 @@ if (!l1_visitor->is_inconsistent()) { l1_visitor->visit(nodeh, "l1-dcache-line-size"); } - if (!l2_visitor->is_inconsistent()) { - l2_visitor->visit(nodeh, "l2-cache-line-size"); + static const char* l2_data_cache_line_property_name = NULL; + // On the first visit determine the name of the l2 cache line size property and memoize it. + if (l2_data_cache_line_property_name == NULL) { + assert(!l2_visitor->is_inconsistent(), "First iteration cannot be inconsistent"); + l2_data_cache_line_property_name = "l2-cache-line-size"; + if (!l2_visitor->visit(nodeh, l2_data_cache_line_property_name)) { + l2_data_cache_line_property_name = "l2-dcache-line-size"; + l2_visitor->visit(nodeh, l2_data_cache_line_property_name); + } + } else { + if (!l2_visitor->is_inconsistent()) { + l2_visitor->visit(nodeh, l2_data_cache_line_property_name); + } } if (l1_visitor->is_inconsistent() && l2_visitor->is_inconsistent()) { @@ -172,13 +185,13 @@ UniqueValueVisitor* l2_visitor() { return &_l2_visitor; } }; int _L1_data_cache_line_size; - int _L2_cache_line_size; + int _L2_data_cache_line_size; public: static int visit_cpu(picl_nodehdl_t nodeh, void *state) { return CPUVisitor::visit(nodeh, state); } - PICL(bool is_fujitsu) : _L1_data_cache_line_size(0), _L2_cache_line_size(0), _dl_handle(NULL) { + PICL(bool is_fujitsu) : _L1_data_cache_line_size(0), _L2_data_cache_line_size(0), _dl_handle(NULL) { if (!open_library()) { return; } @@ -196,7 +209,7 @@ _L1_data_cache_line_size = cpu_visitor.l1_visitor()->value(); } if (cpu_visitor.l2_visitor()->is_assigned()) { - _L2_cache_line_size = cpu_visitor.l2_visitor()->value(); + _L2_data_cache_line_size = cpu_visitor.l2_visitor()->value(); } } _picl_shutdown(); @@ -205,7 +218,7 @@ } unsigned int L1_data_cache_line_size() const { return _L1_data_cache_line_size; } - unsigned int L2_cache_line_size() const { return _L2_cache_line_size; } + unsigned int L2_data_cache_line_size() const { return _L2_data_cache_line_size; } }; @@ -431,7 +444,7 @@ // Figure out cache line sizes using PICL PICL picl((features & sparc64_family_m) != 0); _L1_data_cache_line_size = picl.L1_data_cache_line_size(); - _L2_cache_line_size = picl.L2_cache_line_size(); + _L2_data_cache_line_size = picl.L2_data_cache_line_size(); return features; } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/tools/hsdis/hsdis.c --- a/hotspot/src/share/tools/hsdis/hsdis.c Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/tools/hsdis/hsdis.c Thu May 07 20:51:12 2015 -0700 @@ -410,6 +410,7 @@ } p = q; } + *iop = '\0'; } static void print_help(struct hsdis_app_data* app_data, diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/adlc/adlparse.cpp --- a/hotspot/src/share/vm/adlc/adlparse.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/adlc/adlparse.cpp Thu May 07 20:51:12 2015 -0700 @@ -800,6 +800,7 @@ } if (strcmp(token,"reg_def")==0) { reg_def_parse(); } else if (strcmp(token,"reg_class")==0) { reg_class_parse(); } + else if (strcmp(token, "reg_class_dynamic") == 0) { reg_class_dynamic_parse(); } else if (strcmp(token,"alloc_class")==0) { alloc_class_parse(); } else if (strcmp(token,"#define")==0) { preproc_define(); } else { parse_err(SYNERR, "bad token %s inside register block.\n", token); break; } @@ -2323,11 +2324,12 @@ // Debug Stuff if (_AD._adl_debug >1) fprintf(stderr,"Register Class: %s\n", cname); - RegClass *reg_class = _AD._register->addRegClass(cname); - - // Collect registers in class skipws(); if (_curchar == '(') { + // A register list is defined for the register class. + // Collect registers into a generic RegClass register class. + RegClass* reg_class = _AD._register->addRegClass(cname); + next_char(); // Skip '(' skipws(); while (_curchar != ')') { @@ -2352,12 +2354,15 @@ } next_char(); // Skip closing ')' } else if (_curchar == '%') { + // A code snippet is defined for the register class. + // Collect the code snippet into a CodeSnippetRegClass register class. + CodeSnippetRegClass* reg_class = _AD._register->addRegClass(cname); char *code = find_cpp_block("reg class"); if (code == NULL) { parse_err(SYNERR, "missing code declaration for reg class.\n"); return; } - reg_class->_user_defined = code; + reg_class->set_code_snippet(code); return; } @@ -2374,6 +2379,87 @@ return; } +//------------------------------reg_class_dynamic_parse------------------------ +void ADLParser::reg_class_dynamic_parse(void) { + char *cname; // Name of dynamic register class being defined + + // Get register class name + skipws(); + cname = get_ident(); + if (cname == NULL) { + parse_err(SYNERR, "missing dynamic register class name after 'reg_class_dynamic'\n"); + return; + } + + if (_AD._adl_debug > 1) { + fprintf(stdout, "Dynamic Register Class: %s\n", cname); + } + + skipws(); + if (_curchar != '(') { + parse_err(SYNERR, "missing '(' at the beginning of reg_class_dynamic definition\n"); + return; + } + next_char(); + skipws(); + + // Collect two register classes and the C++ code representing the condition code used to + // select between the two classes into a ConditionalRegClass register class. + ConditionalRegClass* reg_class = _AD._register->addRegClass(cname); + int i; + for (i = 0; i < 2; i++) { + char* name = get_ident(); + if (name == NULL) { + parse_err(SYNERR, "missing class identifier inside reg_class_dynamic list.\n"); + return; + } + RegClass* rc = _AD._register->getRegClass(name); + if (rc == NULL) { + parse_err(SEMERR, "unknown identifier %s inside reg_class_dynamic list.\n", name); + } else { + reg_class->set_rclass_at_index(i, rc); + } + + skipws(); + if (_curchar == ',') { + next_char(); + skipws(); + } else { + parse_err(SYNERR, "missing separator ',' inside reg_class_dynamic list.\n"); + } + } + + // Collect the condition code. + skipws(); + if (_curchar == '%') { + char* code = find_cpp_block("reg class dynamic"); + if (code == NULL) { + parse_err(SYNERR, "missing code declaration for reg_class_dynamic.\n"); + return; + } + reg_class->set_condition_code(code); + } else { + parse_err(SYNERR, "missing %% at the beginning of code block in reg_class_dynamic definition\n"); + return; + } + + skipws(); + if (_curchar != ')') { + parse_err(SYNERR, "missing ')' at the end of reg_class_dynamic definition\n"); + return; + } + next_char(); + + skipws(); + if (_curchar != ';') { + parse_err(SYNERR, "missing ';' at the end of reg_class_dynamic definition.\n"); + return; + } + next_char(); // Skip trailing ';' + + return; +} + //------------------------------alloc_class_parse------------------------------ void ADLParser::alloc_class_parse(void) { char *name; // Name of allocation class being defined diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/adlc/adlparse.hpp --- a/hotspot/src/share/vm/adlc/adlparse.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/adlc/adlparse.hpp Thu May 07 20:51:12 2015 -0700 @@ -53,6 +53,8 @@ // ***** Register Section ***** class RegDef; class RegClass; +class CodeSnippetRegClass; +class ConditionalRegClass; class AllocClass; class ResourceForm; // ***** Pipeline Section ***** @@ -125,6 +127,7 @@ // Parse components of the register section void reg_def_parse(void); // Parse register definition void reg_class_parse(void); // Parse register class definition + void reg_class_dynamic_parse(void); // Parse dynamic register class definition void alloc_class_parse(void); // Parse allocation class definition // Parse components of the definition section diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/adlc/archDesc.cpp --- a/hotspot/src/share/vm/adlc/archDesc.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/adlc/archDesc.cpp Thu May 07 20:51:12 2015 -0700 @@ -908,7 +908,7 @@ void ArchDesc::set_stack_or_reg(const char *reg_class_name) { if( _register ) { RegClass *reg_class = _register->getRegClass(reg_class_name); - reg_class->_stack_or_reg = true; + reg_class->set_stack_version(true); } } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/adlc/forms.hpp --- a/hotspot/src/share/vm/adlc/forms.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/adlc/forms.hpp Thu May 07 20:51:12 2015 -0700 @@ -68,6 +68,8 @@ class InsEncode; class RegDef; class RegClass; +class CodeSnippetRegClass; +class ConditionalRegClass; class AllocClass; class ResourceForm; class PipeClassForm; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/adlc/formsopt.cpp --- a/hotspot/src/share/vm/adlc/formsopt.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/adlc/formsopt.cpp Thu May 07 20:51:12 2015 -0700 @@ -47,13 +47,19 @@ } // record a new register class -RegClass *RegisterForm::addRegClass(const char *className) { - RegClass *regClass = new RegClass(className); +template +T* RegisterForm::addRegClass(const char* className) { + T* regClass = new T(className); _rclasses.addName(className); - _regClass.Insert(className,regClass); + _regClass.Insert(className, regClass); return regClass; } +// Explicit instantiation for all supported register classes. +template RegClass* RegisterForm::addRegClass(const char* className); +template CodeSnippetRegClass* RegisterForm::addRegClass(const char* className); +template ConditionalRegClass* RegisterForm::addRegClass(const char* className); + // record a new register class AllocClass *RegisterForm::addAllocClass(char *className) { AllocClass *allocClass = new AllocClass(className); @@ -67,9 +73,9 @@ void RegisterForm::addSpillRegClass() { // Stack slots start at the next available even register number. _reg_ctr = (_reg_ctr+7) & ~7; - const char *rc_name = "stack_slots"; - RegClass *reg_class = new RegClass(rc_name); - reg_class->_stack_or_reg = true; + const char *rc_name = "stack_slots"; + RegClass* reg_class = new RegClass(rc_name); + reg_class->set_stack_version(true); _rclasses.addName(rc_name); _regClass.Insert(rc_name,reg_class); } @@ -224,9 +230,11 @@ //------------------------------RegClass--------------------------------------- // Construct a register class into which registers will be inserted -RegClass::RegClass(const char *classid) : _stack_or_reg(false), _classid(classid), _regDef(cmpstr,hashstr, Form::arena), - _user_defined(NULL) -{ +RegClass::RegClass(const char* classid) : _stack_or_reg(false), _classid(classid), _regDef(cmpstr, hashstr, Form::arena) { +} + +RegClass::~RegClass() { + delete _classid; } // record a register in this class @@ -305,6 +313,91 @@ fprintf(fp,"--- done with entries for reg_class %s\n\n",_classid); } +void RegClass::declare_register_masks(FILE* fp) { + const char* prefix = ""; + const char* rc_name_to_upper = toUpper(_classid); + fprintf(fp, "extern const RegMask _%s%s_mask;\n", prefix, rc_name_to_upper); + fprintf(fp, "inline const RegMask &%s%s_mask() { return _%s%s_mask; }\n", prefix, rc_name_to_upper, prefix, rc_name_to_upper); + if (_stack_or_reg) { + fprintf(fp, "extern const RegMask _%sSTACK_OR_%s_mask;\n", prefix, rc_name_to_upper); + fprintf(fp, "inline const RegMask &%sSTACK_OR_%s_mask() { return _%sSTACK_OR_%s_mask; }\n", prefix, rc_name_to_upper, prefix, rc_name_to_upper); + } + delete[] rc_name_to_upper; +} + +void RegClass::build_register_masks(FILE* fp) { + int len = RegisterForm::RegMask_Size(); + const char *prefix = ""; + const char* rc_name_to_upper = toUpper(_classid); + fprintf(fp, "const RegMask _%s%s_mask(", prefix, rc_name_to_upper); + + int i; + for(i = 0; i < len - 1; i++) { + fprintf(fp," 0x%x,", regs_in_word(i, false)); + } + fprintf(fp," 0x%x );\n", regs_in_word(i, false)); + + if (_stack_or_reg) { + fprintf(fp, "const RegMask _%sSTACK_OR_%s_mask(", prefix, rc_name_to_upper); + for(i = 0; i < len - 1; i++) { + fprintf(fp," 0x%x,", regs_in_word(i, true)); + } + fprintf(fp," 0x%x );\n", regs_in_word(i, true)); + } + delete[] rc_name_to_upper; +} + +//------------------------------CodeSnippetRegClass--------------------------- +CodeSnippetRegClass::CodeSnippetRegClass(const char* classid) : RegClass(classid), _code_snippet(NULL) { +} + +CodeSnippetRegClass::~CodeSnippetRegClass() { + delete _code_snippet; +} + +void CodeSnippetRegClass::declare_register_masks(FILE* fp) { + const char* prefix = ""; + const char* rc_name_to_upper = toUpper(_classid); + fprintf(fp, "inline const RegMask &%s%s_mask() { %s }\n", prefix, rc_name_to_upper, _code_snippet); + delete[] rc_name_to_upper; +} + +//------------------------------ConditionalRegClass--------------------------- +ConditionalRegClass::ConditionalRegClass(const char *classid) : RegClass(classid), _condition_code(NULL) { +} + +ConditionalRegClass::~ConditionalRegClass() { + delete _condition_code; +} + +void ConditionalRegClass::declare_register_masks(FILE* fp) { + const char* prefix = ""; + const char* rc_name_to_upper = toUpper(_classid); + const char* rclass_0_to_upper = toUpper(_rclasses[0]->_classid); + const char* rclass_1_to_upper = toUpper(_rclasses[1]->_classid); + fprintf(fp, "inline const RegMask &%s%s_mask() {" + " return (%s) ?" + " %s%s_mask() :" + " %s%s_mask(); }\n", + prefix, rc_name_to_upper, + _condition_code, + prefix, rclass_0_to_upper, + prefix, rclass_1_to_upper); + if (_stack_or_reg) { + fprintf(fp, "inline const RegMask &%sSTACK_OR_%s_mask() {" + " return (%s) ?" + " %sSTACK_OR_%s_mask() :" + " %sSTACK_OR_%s_mask(); }\n", + prefix, rc_name_to_upper, + _condition_code, + prefix, rclass_0_to_upper, + prefix, rclass_1_to_upper); + } + delete[] rc_name_to_upper; + delete[] rclass_0_to_upper; + delete[] rclass_1_to_upper; + return; +} //------------------------------AllocClass------------------------------------- AllocClass::AllocClass(char *classid) : _classid(classid), _regDef(cmpstr,hashstr, Form::arena) { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/adlc/formsopt.hpp --- a/hotspot/src/share/vm/adlc/formsopt.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/adlc/formsopt.hpp Thu May 07 20:51:12 2015 -0700 @@ -60,6 +60,8 @@ class InsEncode; class RegDef; class RegClass; +class CodeSnippetRegClass; +class ConditionalRegClass; class AllocClass; class ResourceForm; class PipeClassForm; @@ -98,7 +100,8 @@ void addRegDef(char *regName, char *callingConv, char *c_conv, char * idealtype, char *encoding, char* concreteName); - RegClass *addRegClass(const char *className); + template T* addRegClass(const char* className); + AllocClass *addAllocClass(char *allocName); void addSpillRegClass(); @@ -154,17 +157,28 @@ }; //------------------------------RegClass--------------------------------------- +// Generic register class. This register class is the internal representation +// for the following .ad file format: +// +// reg_class ptr(RAX, RBX, ...); +// +// where ptr is the name of the register class, RAX and RBX are registers. +// +// This register class allows registers to be spilled onto the stack. Spilling +// is allowed is field _stack_or_reg is true. class RegClass : public Form { public: // Public Data const char *_classid; // Name of class NameList _regDefs; // List of registers in class Dict _regDef; // Dictionary of registers in class +protected: bool _stack_or_reg; // Allowed on any stack slot - char* _user_defined; +public: // Public Methods RegClass(const char *classid);// Constructor + virtual ~RegClass(); void addReg(RegDef *regDef); // Add a register to this class @@ -183,6 +197,115 @@ void dump(); // Debug printer void output(FILE *fp); // Write info to output files + + virtual bool has_stack_version() { + return _stack_or_reg; + } + virtual void set_stack_version(bool flag) { + _stack_or_reg = flag; + } + + virtual void declare_register_masks(FILE* fp); + virtual void build_register_masks(FILE* fp); +}; + +//------------------------------CodeSnippetRegClass---------------------------- +// Register class that has an user-defined C++ code snippet attached to it +// to determine at runtime which register class to use. This register class is +// the internal representation for the following .ad file format: +// +// reg_class actual_dflt_reg %{ +// if (VM_Version::has_vfp3_32()) { +// return DFLT_REG_mask(); +// } else { +// return DFLT_LOW_REG_mask(); +// } +// %} +// +// where DFLT_REG_mask() and DFLT_LOW_REG_mask() are the internal names of the +// masks of register classes dflt_reg and dflt_low_reg. +// +// The attached code snippet can select also between more than two register classes. +// This register class can be, however, used only if the register class is not +// cisc-spillable (i.e., the registers of this class are not allowed on the stack, +// which is equivalent with _stack_or_reg being false). +class CodeSnippetRegClass : public RegClass { +protected: + char* _code_snippet; +public: + CodeSnippetRegClass(const char* classid);// Constructor + ~CodeSnippetRegClass(); + + void set_code_snippet(char* code) { + _code_snippet = code; + } + char* code_snippet() { + return _code_snippet; + } + void set_stack_version(bool flag) { + assert(false, "User defined register classes are not allowed to spill to the stack."); + } + void declare_register_masks(FILE* fp); + void build_register_masks(FILE* fp) { + // We do not need to generate register masks because we select at runtime + // between register masks generated for other register classes. + return; + } +}; + +//------------------------------ConditionalRegClass---------------------------- +// Register class that has two register classes and a runtime condition attached +// to it. The condition is evaluated at runtime and either one of the register +// attached register classes is selected. This register class is the internal +// representation for the following .ad format: +// +// reg_class_dynamic actual_dflt_reg(dflt_reg, low_reg, +// %{ VM_Version::has_vfp3_32() }% +// ); +// +// This example is equivalent to the example used with the CodeSnippetRegClass +// register class. A ConditionalRegClass works also if a register class is cisc-spillable +// (i.e., _stack_or_reg is true), but if can select only between two register classes. +class ConditionalRegClass : public RegClass { +protected: + // reference to condition code + char* _condition_code; // C++ condition code to dynamically determine which register class to use. + + // Example syntax (equivalent to previous example): + // + // reg_class actual_dflt_reg(dflt_reg, low_reg, + // %{ VM_Version::has_vfp3_32() }% + // ); + // reference to conditional register classes + RegClass* _rclasses[2]; // 0 is the register class selected if the condition code returns true + // 1 is the register class selected if the condition code returns false +public: + ConditionalRegClass(const char* classid);// Constructor + ~ConditionalRegClass(); + + virtual void set_stack_version(bool flag) { + RegClass::set_stack_version(flag); + assert((_rclasses[0] != NULL), "Register class NULL for condition code == true"); + assert((_rclasses[1] != NULL), "Register class NULL for condition code == false"); + _rclasses[0]->set_stack_version(flag); + _rclasses[1]->set_stack_version(flag); + } + void declare_register_masks(FILE* fp); + void build_register_masks(FILE* fp) { + // We do not need to generate register masks because we select at runtime + // between register masks generated for other register classes. + return; + } + void set_rclass_at_index(int index, RegClass* rclass) { + assert((0 <= index && index < 2), "Condition code can select only between two register classes"); + _rclasses[index] = rclass; + } + void set_condition_code(char* code) { + _condition_code = code; + } + char* condition_code() { + return _condition_code; + } }; //------------------------------AllocClass------------------------------------- diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/adlc/formssel.cpp --- a/hotspot/src/share/vm/adlc/formssel.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/adlc/formssel.cpp Thu May 07 20:51:12 2015 -0700 @@ -3392,7 +3392,7 @@ // Count occurrences of operands names in the leaves of the instruction // match rule. void MatchNode::count_instr_names( Dict &names ) { - if( !this ) return; + if( this == NULL ) return; if( _lChild ) _lChild->count_instr_names(names); if( _rChild ) _rChild->count_instr_names(names); if( !_lChild && !_rChild ) { @@ -4043,6 +4043,13 @@ strcmp(opType,"ReplicateL")==0 || strcmp(opType,"ReplicateF")==0 || strcmp(opType,"ReplicateD")==0 || + strcmp(opType,"AddReductionVI")==0 || + strcmp(opType,"AddReductionVL")==0 || + strcmp(opType,"AddReductionVF")==0 || + strcmp(opType,"AddReductionVD")==0 || + strcmp(opType,"MulReductionVI")==0 || + strcmp(opType,"MulReductionVF")==0 || + strcmp(opType,"MulReductionVD")==0 || 0 /* 0 to line up columns nicely */ ) return 1; } @@ -4135,6 +4142,10 @@ "MulVS","MulVI","MulVF","MulVD", "DivVF","DivVD", "AndV" ,"XorV" ,"OrV", + "AddReductionVI", "AddReductionVL", + "AddReductionVF", "AddReductionVD", + "MulReductionVI", + "MulReductionVF", "MulReductionVD", "LShiftCntV","RShiftCntV", "LShiftVB","LShiftVS","LShiftVI","LShiftVL", "RShiftVB","RShiftVS","RShiftVI","RShiftVL", diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/adlc/formssel.hpp --- a/hotspot/src/share/vm/adlc/formssel.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/adlc/formssel.hpp Thu May 07 20:51:12 2015 -0700 @@ -59,6 +59,8 @@ class InsEncode; class RegDef; class RegClass; +class CodeSnippetRegClass; +class ConditionalRegClass; class AllocClass; class ResourceForm; class PipeDesc; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/adlc/output_c.cpp --- a/hotspot/src/share/vm/adlc/output_c.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/adlc/output_c.cpp Thu May 07 20:51:12 2015 -0700 @@ -138,26 +138,9 @@ fprintf(fp_hpp,"// Register masks, one for each register class.\n"); _register->_rclasses.reset(); for (rc_name = NULL; (rc_name = _register->_rclasses.iter()) != NULL;) { - const char *prefix = ""; RegClass *reg_class = _register->getRegClass(rc_name); assert(reg_class, "Using an undefined register class"); - - const char* rc_name_to_upper = toUpper(rc_name); - - if (reg_class->_user_defined == NULL) { - fprintf(fp_hpp, "extern const RegMask _%s%s_mask;\n", prefix, rc_name_to_upper); - fprintf(fp_hpp, "inline const RegMask &%s%s_mask() { return _%s%s_mask; }\n", prefix, rc_name_to_upper, prefix, rc_name_to_upper); - } else { - fprintf(fp_hpp, "inline const RegMask &%s%s_mask() { %s }\n", prefix, rc_name_to_upper, reg_class->_user_defined); - } - - if (reg_class->_stack_or_reg) { - assert(reg_class->_user_defined == NULL, "no user defined reg class here"); - fprintf(fp_hpp, "extern const RegMask _%sSTACK_OR_%s_mask;\n", prefix, rc_name_to_upper); - fprintf(fp_hpp, "inline const RegMask &%sSTACK_OR_%s_mask() { return _%sSTACK_OR_%s_mask; }\n", prefix, rc_name_to_upper, prefix, rc_name_to_upper); - } - delete[] rc_name_to_upper; - + reg_class->declare_register_masks(fp_hpp); } } } @@ -173,35 +156,9 @@ fprintf(fp_cpp,"// Register masks, one for each register class.\n"); _register->_rclasses.reset(); for (rc_name = NULL; (rc_name = _register->_rclasses.iter()) != NULL;) { - const char *prefix = ""; RegClass *reg_class = _register->getRegClass(rc_name); assert(reg_class, "Using an undefined register class"); - - if (reg_class->_user_defined != NULL) { - continue; - } - - int len = RegisterForm::RegMask_Size(); - const char* rc_name_to_upper = toUpper(rc_name); - fprintf(fp_cpp, "const RegMask _%s%s_mask(", prefix, rc_name_to_upper); - - { - int i; - for(i = 0; i < len - 1; i++) { - fprintf(fp_cpp," 0x%x,", reg_class->regs_in_word(i, false)); - } - fprintf(fp_cpp," 0x%x );\n", reg_class->regs_in_word(i, false)); - } - - if (reg_class->_stack_or_reg) { - int i; - fprintf(fp_cpp, "const RegMask _%sSTACK_OR_%s_mask(", prefix, rc_name_to_upper); - for(i = 0; i < len - 1; i++) { - fprintf(fp_cpp," 0x%x,",reg_class->regs_in_word(i, true)); - } - fprintf(fp_cpp," 0x%x );\n",reg_class->regs_in_word(i, true)); - } - delete[] rc_name_to_upper; + reg_class->build_register_masks(fp_cpp); } } } @@ -1548,8 +1505,8 @@ // Iterate over the instructions 'node' expands into ExpandRule *expand = node->_exprule; NameAndList *expand_instr = NULL; - for(expand->reset_instructions(); - (expand_instr = expand->iter_instructions()) != NULL; cnt++) { + for (expand->reset_instructions(); + (expand_instr = expand->iter_instructions()) != NULL; cnt++) { new_id = expand_instr->name(); InstructForm* expand_instruction = (InstructForm*)globalAD->globalNames()[new_id]; @@ -1560,30 +1517,25 @@ continue; } - if (expand_instruction->has_temps()) { - globalAD->syntax_err(node->_linenum, "In %s: expand rules using instructs with TEMPs aren't supported: %s", - node->_ident, new_id); - } - // Build the node for the instruction fprintf(fp,"\n %sNode *n%d = new %sNode();\n", new_id, cnt, new_id); // Add control edge for this node fprintf(fp," n%d->add_req(_in[0]);\n", cnt); // Build the operand for the value this node defines. Form *form = (Form*)_globalNames[new_id]; - assert( form, "'new_id' must be a defined form name"); + assert(form, "'new_id' must be a defined form name"); // Grab the InstructForm for the new instruction new_inst = form->is_instruction(); - assert( new_inst, "'new_id' must be an instruction name"); - if( node->is_ideal_if() && new_inst->is_ideal_if() ) { - fprintf(fp, " ((MachIfNode*)n%d)->_prob = _prob;\n",cnt); - fprintf(fp, " ((MachIfNode*)n%d)->_fcnt = _fcnt;\n",cnt); + assert(new_inst, "'new_id' must be an instruction name"); + if (node->is_ideal_if() && new_inst->is_ideal_if()) { + fprintf(fp, " ((MachIfNode*)n%d)->_prob = _prob;\n", cnt); + fprintf(fp, " ((MachIfNode*)n%d)->_fcnt = _fcnt;\n", cnt); } - if( node->is_ideal_fastlock() && new_inst->is_ideal_fastlock() ) { - fprintf(fp, " ((MachFastLockNode*)n%d)->_counters = _counters;\n",cnt); - fprintf(fp, " ((MachFastLockNode*)n%d)->_rtm_counters = _rtm_counters;\n",cnt); - fprintf(fp, " ((MachFastLockNode*)n%d)->_stack_rtm_counters = _stack_rtm_counters;\n",cnt); + if (node->is_ideal_fastlock() && new_inst->is_ideal_fastlock()) { + fprintf(fp, " ((MachFastLockNode*)n%d)->_counters = _counters;\n", cnt); + fprintf(fp, " ((MachFastLockNode*)n%d)->_rtm_counters = _rtm_counters;\n", cnt); + fprintf(fp, " ((MachFastLockNode*)n%d)->_stack_rtm_counters = _stack_rtm_counters;\n", cnt); } // Fill in the bottom_type where requested diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/c1/c1_GraphBuilder.cpp --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Thu May 07 20:51:12 2015 -0700 @@ -3462,6 +3462,24 @@ case vmIntrinsics::_putFloat : return append_unsafe_put_obj(callee, T_FLOAT, false); case vmIntrinsics::_putDouble : return append_unsafe_put_obj(callee, T_DOUBLE, false); + case vmIntrinsics::_getShortUnaligned : + return UseUnalignedAccesses ? append_unsafe_get_obj(callee, T_SHORT, false) : false; + case vmIntrinsics::_getCharUnaligned : + return UseUnalignedAccesses ? append_unsafe_get_obj(callee, T_CHAR, false) : false; + case vmIntrinsics::_getIntUnaligned : + return UseUnalignedAccesses ? append_unsafe_get_obj(callee, T_INT, false) : false; + case vmIntrinsics::_getLongUnaligned : + return UseUnalignedAccesses ? append_unsafe_get_obj(callee, T_LONG, false) : false; + + case vmIntrinsics::_putShortUnaligned : + return UseUnalignedAccesses ? append_unsafe_put_obj(callee, T_SHORT, false) : false; + case vmIntrinsics::_putCharUnaligned : + return UseUnalignedAccesses ? append_unsafe_put_obj(callee, T_CHAR, false) : false; + case vmIntrinsics::_putIntUnaligned : + return UseUnalignedAccesses ? append_unsafe_put_obj(callee, T_INT, false) : false; + case vmIntrinsics::_putLongUnaligned : + return UseUnalignedAccesses ? append_unsafe_put_obj(callee, T_LONG, false) : false; + case vmIntrinsics::_getObjectVolatile : return append_unsafe_get_obj(callee, T_OBJECT, true); case vmIntrinsics::_getBooleanVolatile: return append_unsafe_get_obj(callee, T_BOOLEAN, true); case vmIntrinsics::_getByteVolatile : return append_unsafe_get_obj(callee, T_BYTE, true); @@ -4065,7 +4083,7 @@ ValueType* type = apop()->type(); if (type->is_constant()) { ciMethod* target = type->as_ObjectType()->constant_value()->as_member_name()->get_vmtarget(); - // If the target is another method handle invoke try recursivly to get + // If the target is another method handle invoke, try to recursively get // a better target. if (target->is_method_handle_intrinsic()) { if (try_method_handle_inline(target)) { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/c1/c1_LIR.cpp --- a/hotspot/src/share/vm/c1/c1_LIR.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/c1/c1_LIR.cpp Thu May 07 20:51:12 2015 -0700 @@ -458,7 +458,7 @@ //-------------------visits-------------------------- // complete rework of LIR instruction visitor. -// The virtual calls for each instruction type is replaced by a big +// The virtual call for each instruction type is replaced by a big // switch that adds the operands for each instruction void LIR_OpVisitState::visit(LIR_Op* op) { @@ -825,7 +825,8 @@ } if (opJavaCall->_info) do_info(opJavaCall->_info); - if (opJavaCall->is_method_handle_invoke()) { + if (FrameMap::method_handle_invoke_SP_save_opr() != LIR_OprFact::illegalOpr && + opJavaCall->is_method_handle_invoke()) { opJavaCall->_method_handle_invoke_SP_save_opr = FrameMap::method_handle_invoke_SP_save_opr(); do_temp(opJavaCall->_method_handle_invoke_SP_save_opr); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/c1/c1_LIR.hpp --- a/hotspot/src/share/vm/c1/c1_LIR.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/c1/c1_LIR.hpp Thu May 07 20:51:12 2015 -0700 @@ -1219,10 +1219,8 @@ // JSR 292 support. bool is_invokedynamic() const { return code() == lir_dynamic_call; } bool is_method_handle_invoke() const { - return - method()->is_compiled_lambda_form() // Java-generated adapter - || - method()->is_method_handle_intrinsic(); // JVM-generated MH intrinsic + return method()->is_compiled_lambda_form() || // Java-generated lambda form + method()->is_method_handle_intrinsic(); // JVM-generated MH intrinsic } intptr_t vtable_offset() const { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/c1/c1_LIRGenerator.cpp --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Thu May 07 20:51:12 2015 -0700 @@ -1606,13 +1606,26 @@ } else { __ unsigned_shift_right(addr, CardTableModRefBS::card_shift, tmp); } + + LIR_Address* card_addr; if (can_inline_as_constant(card_table_base)) { - __ move(LIR_OprFact::intConst(0), - new LIR_Address(tmp, card_table_base->as_jint(), T_BYTE)); + card_addr = new LIR_Address(tmp, card_table_base->as_jint(), T_BYTE); } else { - __ move(LIR_OprFact::intConst(0), - new LIR_Address(tmp, load_constant(card_table_base), - T_BYTE)); + card_addr = new LIR_Address(tmp, load_constant(card_table_base), T_BYTE); + } + + LIR_Opr dirty = LIR_OprFact::intConst(CardTableModRefBS::dirty_card_val()); + if (UseCondCardMark) { + LIR_Opr cur_value = new_register(T_INT); + __ move(card_addr, cur_value); + + LabelObj* L_already_dirty = new LabelObj(); + __ cmp(lir_cond_equal, cur_value, dirty); + __ branch(lir_cond_equal, T_BYTE, L_already_dirty->label()); + __ move(dirty, card_addr); + __ branch_destination(L_already_dirty->label()); + } else { + __ move(dirty, card_addr); } #endif } @@ -2862,7 +2875,7 @@ // g) lock result registers and emit call operation // // Before issuing a call, we must spill-save all values on stack -// that are in caller-save register. "spill-save" moves thos registers +// that are in caller-save register. "spill-save" moves those registers // either in a free callee-save register or spills them if no free // callee save register is available. // @@ -2870,7 +2883,7 @@ // - if invoked between e) and f), we may lock callee save // register in "spill-save" that destroys the receiver register // before f) is executed -// - if we rearange the f) to be earlier, by loading %o0, it +// - if we rearrange f) to be earlier (by loading %o0) it // may destroy a value on the stack that is currently in %o0 // and is waiting to be spilled // - if we keep the receiver locked while doing spill-save, @@ -2903,14 +2916,16 @@ assert(receiver->is_illegal() || receiver->is_equal(LIR_Assembler::receiverOpr()), "must match"); // JSR 292 - // Preserve the SP over MethodHandle call sites. + // Preserve the SP over MethodHandle call sites, if needed. ciMethod* target = x->target(); bool is_method_handle_invoke = (// %%% FIXME: Are both of these relevant? target->is_method_handle_intrinsic() || target->is_compiled_lambda_form()); if (is_method_handle_invoke) { info->set_is_method_handle_invoke(true); - __ move(FrameMap::stack_pointer(), FrameMap::method_handle_invoke_SP_save_opr()); + if(FrameMap::method_handle_invoke_SP_save_opr() != LIR_OprFact::illegalOpr) { + __ move(FrameMap::stack_pointer(), FrameMap::method_handle_invoke_SP_save_opr()); + } } switch (x->code()) { @@ -2950,8 +2965,9 @@ } // JSR 292 - // Restore the SP after MethodHandle call sites. - if (is_method_handle_invoke) { + // Restore the SP after MethodHandle call sites, if needed. + if (is_method_handle_invoke + && FrameMap::method_handle_invoke_SP_save_opr() != LIR_OprFact::illegalOpr) { __ move(FrameMap::method_handle_invoke_SP_save_opr(), FrameMap::stack_pointer()); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/ci/ciCallSite.cpp --- a/hotspot/src/share/vm/ci/ciCallSite.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/ci/ciCallSite.cpp Thu May 07 20:51:12 2015 -0700 @@ -50,6 +50,25 @@ } // ------------------------------------------------------------------ +// ciCallSite::get_context +// +// Return the target MethodHandle of this CallSite. +ciKlass* ciCallSite::get_context() { + assert(!is_constant_call_site(), ""); + + VM_ENTRY_MARK; + oop call_site_oop = get_oop(); + InstanceKlass* ctxk = MethodHandles::get_call_site_context(call_site_oop); + if (ctxk == NULL) { + // The call site doesn't have a context associated. Set it to the default context. + oop def_context_oop = java_lang_invoke_CallSite::default_context(); + java_lang_invoke_CallSite::set_context_cas(call_site_oop, def_context_oop, /*expected=*/NULL); + ctxk = MethodHandles::get_call_site_context(call_site_oop); + } + return (CURRENT_ENV->get_metadata(ctxk))->as_klass(); +} + +// ------------------------------------------------------------------ // ciCallSite::print // // Print debugging information about the CallSite. diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/ci/ciCallSite.hpp --- a/hotspot/src/share/vm/ci/ciCallSite.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/ci/ciCallSite.hpp Thu May 07 20:51:12 2015 -0700 @@ -43,6 +43,7 @@ // Return the target MethodHandle of this CallSite. ciMethodHandle* get_target() const; + ciKlass* get_context(); void print(); }; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/ci/ciMethod.cpp --- a/hotspot/src/share/vm/ci/ciMethod.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/ci/ciMethod.cpp Thu May 07 20:51:12 2015 -0700 @@ -688,7 +688,8 @@ // via assert_unique_concrete_method or assert_leaf_type. ciMethod* ciMethod::find_monomorphic_target(ciInstanceKlass* caller, ciInstanceKlass* callee_holder, - ciInstanceKlass* actual_recv) { + ciInstanceKlass* actual_recv, + bool check_access) { check_is_loaded(); if (actual_recv->is_interface()) { @@ -696,7 +697,7 @@ return NULL; } - ciMethod* root_m = resolve_invoke(caller, actual_recv); + ciMethod* root_m = resolve_invoke(caller, actual_recv, check_access); if (root_m == NULL) { // Something went wrong looking up the actual receiver method. return NULL; @@ -775,7 +776,7 @@ // // Given a known receiver klass, find the target for the call. // Return NULL if the call has no target or the target is abstract. -ciMethod* ciMethod::resolve_invoke(ciKlass* caller, ciKlass* exact_receiver) { +ciMethod* ciMethod::resolve_invoke(ciKlass* caller, ciKlass* exact_receiver, bool check_access) { check_is_loaded(); VM_ENTRY_MARK; @@ -792,9 +793,9 @@ || InstanceKlass::cast(h_recv())->is_linked() && !exact_receiver->is_interface()) { if (holder()->is_interface()) { - m = LinkResolver::resolve_interface_call_or_null(h_recv, h_resolved, h_name, h_signature, caller_klass); + m = LinkResolver::resolve_interface_call_or_null(h_recv, h_resolved, h_name, h_signature, caller_klass, check_access); } else { - m = LinkResolver::resolve_virtual_call_or_null(h_recv, h_resolved, h_name, h_signature, caller_klass); + m = LinkResolver::resolve_virtual_call_or_null(h_recv, h_resolved, h_name, h_signature, caller_klass, check_access); } } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/ci/ciMethod.hpp --- a/hotspot/src/share/vm/ci/ciMethod.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/ci/ciMethod.hpp Thu May 07 20:51:12 2015 -0700 @@ -255,11 +255,12 @@ // its calling environment. ciMethod* find_monomorphic_target(ciInstanceKlass* caller, ciInstanceKlass* callee_holder, - ciInstanceKlass* actual_receiver); + ciInstanceKlass* actual_receiver, + bool check_access = true); // Given a known receiver klass, find the target for the call. // Return NULL if the call has no target or is abstract. - ciMethod* resolve_invoke(ciKlass* caller, ciKlass* exact_receiver); + ciMethod* resolve_invoke(ciKlass* caller, ciKlass* exact_receiver, bool check_access = true); // Find the proper vtable index to invoke this method. int resolve_vtable_index(ciKlass* caller, ciKlass* receiver); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/classfile/classFileParser.cpp --- a/hotspot/src/share/vm/classfile/classFileParser.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Thu May 07 20:51:12 2015 -0700 @@ -4838,20 +4838,21 @@ } } } else { // not interface - if (is_initializer) { - if (is_static || is_final || is_synchronized || is_native || - is_abstract || (major_gte_15 && is_bridge)) { - is_illegal = true; - } - } else { // not initializer - if (is_abstract) { - if ((is_final || is_native || is_private || is_static || - (major_gte_15 && (is_synchronized || is_strict)))) { + if (has_illegal_visibility(flags)) { + is_illegal = true; + } else { + if (is_initializer) { + if (is_static || is_final || is_synchronized || is_native || + is_abstract || (major_gte_15 && is_bridge)) { is_illegal = true; } - } - if (has_illegal_visibility(flags)) { - is_illegal = true; + } else { // not initializer + if (is_abstract) { + if ((is_final || is_native || is_private || is_static || + (major_gte_15 && (is_synchronized || is_strict)))) { + is_illegal = true; + } + } } } } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/classfile/javaClasses.cpp --- a/hotspot/src/share/vm/classfile/javaClasses.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Thu May 07 20:51:12 2015 -0700 @@ -102,21 +102,22 @@ static bool find_field(InstanceKlass* ik, Symbol* name_symbol, Symbol* signature_symbol, fieldDescriptor* fd, - bool allow_super = false) { - if (allow_super) - return ik->find_field(name_symbol, signature_symbol, fd) != NULL; - else + bool is_static = false, bool allow_super = false) { + if (allow_super || is_static) { + return ik->find_field(name_symbol, signature_symbol, is_static, fd) != NULL; + } else { return ik->find_local_field(name_symbol, signature_symbol, fd); + } } // Helpful routine for computing field offsets at run time rather than hardcoding them static void compute_offset(int &dest_offset, Klass* klass_oop, Symbol* name_symbol, Symbol* signature_symbol, - bool allow_super = false) { + bool is_static = false, bool allow_super = false) { fieldDescriptor fd; InstanceKlass* ik = InstanceKlass::cast(klass_oop); - if (!find_field(ik, name_symbol, signature_symbol, &fd, allow_super)) { + if (!find_field(ik, name_symbol, signature_symbol, &fd, is_static, allow_super)) { ResourceMark rm; tty->print_cr("Invalid layout of %s at %s", ik->external_name(), name_symbol->as_C_string()); #ifndef PRODUCT @@ -126,7 +127,7 @@ tty->print_cr(" name: %s, sig: %s, flags: %08x", fs.name()->as_C_string(), fs.signature()->as_C_string(), fs.access_flags().as_int()); } #endif //PRODUCT - fatal("Invalid layout of preloaded class"); + vm_exit_during_initialization("Invalid layout of preloaded class: use -XX:+TraceClassLoading to see the origin of the problem class"); } dest_offset = fd.offset(); } @@ -1313,7 +1314,8 @@ } static inline bool version_matches(Method* method, int version) { - return (method->constants()->version() == version && version < MAX_VERSION); + assert(version < MAX_VERSION, "version is too big"); + return method != NULL && (method->constants()->version() == version); } static inline int get_line_number(Method* method, int bci) { @@ -1343,6 +1345,7 @@ typeArrayOop _methods; typeArrayOop _bcis; objArrayOop _mirrors; + typeArrayOop _cprefs; // needed to insulate method name against redefinition int _index; No_Safepoint_Verifier _nsv; @@ -1350,8 +1353,9 @@ enum { trace_methods_offset = java_lang_Throwable::trace_methods_offset, - trace_bcis_offset = java_lang_Throwable::trace_bcis_offset, + trace_bcis_offset = java_lang_Throwable::trace_bcis_offset, trace_mirrors_offset = java_lang_Throwable::trace_mirrors_offset, + trace_cprefs_offset = java_lang_Throwable::trace_cprefs_offset, trace_next_offset = java_lang_Throwable::trace_next_offset, trace_size = java_lang_Throwable::trace_size, trace_chunk_size = java_lang_Throwable::trace_chunk_size @@ -1373,9 +1377,14 @@ assert(mirrors != NULL, "mirror array should be initialized in backtrace"); return mirrors; } + static typeArrayOop get_cprefs(objArrayHandle chunk) { + typeArrayOop cprefs = typeArrayOop(chunk->obj_at(trace_cprefs_offset)); + assert(cprefs != NULL, "cprefs array should be initialized in backtrace"); + return cprefs; + } // constructor for new backtrace - BacktraceBuilder(TRAPS): _methods(NULL), _bcis(NULL), _head(NULL), _mirrors(NULL) { + BacktraceBuilder(TRAPS): _methods(NULL), _bcis(NULL), _head(NULL), _mirrors(NULL), _cprefs(NULL) { expand(CHECK); _backtrace = _head; _index = 0; @@ -1385,6 +1394,7 @@ _methods = get_methods(backtrace); _bcis = get_bcis(backtrace); _mirrors = get_mirrors(backtrace); + _cprefs = get_cprefs(backtrace); assert(_methods->length() == _bcis->length() && _methods->length() == _mirrors->length(), "method and source information arrays should match"); @@ -1410,17 +1420,22 @@ objArrayOop mirrors = oopFactory::new_objectArray(trace_chunk_size, CHECK); objArrayHandle new_mirrors(THREAD, mirrors); + typeArrayOop cprefs = oopFactory::new_shortArray(trace_chunk_size, CHECK); + typeArrayHandle new_cprefs(THREAD, cprefs); + if (!old_head.is_null()) { old_head->obj_at_put(trace_next_offset, new_head()); } new_head->obj_at_put(trace_methods_offset, new_methods()); new_head->obj_at_put(trace_bcis_offset, new_bcis()); new_head->obj_at_put(trace_mirrors_offset, new_mirrors()); + new_head->obj_at_put(trace_cprefs_offset, new_cprefs()); _head = new_head(); _methods = new_methods(); _bcis = new_bcis(); _mirrors = new_mirrors(); + _cprefs = new_cprefs(); _index = 0; } @@ -1440,8 +1455,9 @@ method = mhandle(); } - _methods->short_at_put(_index, method->method_idnum()); + _methods->short_at_put(_index, method->orig_method_idnum()); _bcis->int_at_put(_index, merge_bci_and_version(bci, method->constants()->version())); + _cprefs->short_at_put(_index, method->name_index()); // We need to save the mirrors in the backtrace to keep the class // from being unloaded while we still have this stack trace. @@ -1454,27 +1470,26 @@ // Print stack trace element to resource allocated buffer char* java_lang_Throwable::print_stack_element_to_buffer(Handle mirror, - int method_id, int version, int bci) { + int method_id, int version, int bci, int cpref) { // Get strings and string lengths InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror())); const char* klass_name = holder->external_name(); int buf_len = (int)strlen(klass_name); - // The method id may point to an obsolete method, can't get more stack information - Method* method = holder->method_with_idnum(method_id); - if (method == NULL) { - char* buf = NEW_RESOURCE_ARRAY(char, buf_len + 64); - // This is what the java code prints in this case - added Redefined - sprintf(buf, "\tat %s.null (Redefined)", klass_name); - return buf; - } - - char* method_name = method->name()->as_C_string(); + Method* method = holder->method_with_orig_idnum(method_id, version); + + // The method can be NULL if the requested class version is gone + Symbol* sym = (method != NULL) ? method->name() : holder->constants()->symbol_at(cpref); + char* method_name = sym->as_C_string(); buf_len += (int)strlen(method_name); + // Use specific ik version as a holder since the mirror might + // refer to version that is now obsolete and no longer accessible + // via the previous versions list. + holder = holder->get_klass_version(version); char* source_file_name = NULL; - if (version_matches(method, version)) { + if (holder != NULL) { Symbol* source = holder->source_file_name(); if (source != NULL) { source_file_name = source->as_C_string(); @@ -1516,17 +1531,18 @@ } void java_lang_Throwable::print_stack_element(outputStream *st, Handle mirror, - int method_id, int version, int bci) { + int method_id, int version, int bci, int cpref) { ResourceMark rm; - char* buf = print_stack_element_to_buffer(mirror, method_id, version, bci); + char* buf = print_stack_element_to_buffer(mirror, method_id, version, bci, cpref); st->print_cr("%s", buf); } void java_lang_Throwable::print_stack_element(outputStream *st, methodHandle method, int bci) { Handle mirror = method->method_holder()->java_mirror(); - int method_id = method->method_idnum(); + int method_id = method->orig_method_idnum(); int version = method->constants()->version(); - print_stack_element(st, mirror, method_id, version, bci); + int cpref = method->name_index(); + print_stack_element(st, mirror, method_id, version, bci, cpref); } const char* java_lang_Throwable::no_stack_trace_message() { @@ -1551,6 +1567,7 @@ typeArrayHandle methods (THREAD, BacktraceBuilder::get_methods(result)); typeArrayHandle bcis (THREAD, BacktraceBuilder::get_bcis(result)); objArrayHandle mirrors (THREAD, BacktraceBuilder::get_mirrors(result)); + typeArrayHandle cprefs (THREAD, BacktraceBuilder::get_cprefs(result)); int length = methods()->length(); for (int index = 0; index < length; index++) { @@ -1560,7 +1577,8 @@ int method = methods->short_at(index); int version = version_at(bcis->int_at(index)); int bci = bci_at(bcis->int_at(index)); - print_stack_element(st, mirror, method, version, bci); + int cpref = cprefs->short_at(index); + print_stack_element(st, mirror, method, version, bci, cpref); } result = objArrayHandle(THREAD, objArrayOop(result->obj_at(trace_next_offset))); } @@ -1837,29 +1855,30 @@ if (chunk == NULL) { THROW_(vmSymbols::java_lang_IndexOutOfBoundsException(), NULL); } - // Get method id, bci, version and mirror from chunk + // Get method id, bci, version, mirror and cpref from chunk typeArrayOop methods = BacktraceBuilder::get_methods(chunk); typeArrayOop bcis = BacktraceBuilder::get_bcis(chunk); objArrayOop mirrors = BacktraceBuilder::get_mirrors(chunk); + typeArrayOop cprefs = BacktraceBuilder::get_cprefs(chunk); assert(methods != NULL && bcis != NULL && mirrors != NULL, "sanity check"); int method = methods->short_at(chunk_index); int version = version_at(bcis->int_at(chunk_index)); int bci = bci_at(bcis->int_at(chunk_index)); + int cpref = cprefs->short_at(chunk_index); Handle mirror(THREAD, mirrors->obj_at(chunk_index)); // Chunk can be partial full if (mirror.is_null()) { THROW_(vmSymbols::java_lang_IndexOutOfBoundsException(), NULL); } - - oop element = java_lang_StackTraceElement::create(mirror, method, version, bci, CHECK_0); + oop element = java_lang_StackTraceElement::create(mirror, method, version, bci, cpref, CHECK_0); return element; } oop java_lang_StackTraceElement::create(Handle mirror, int method_id, - int version, int bci, TRAPS) { + int version, int bci, int cpref, TRAPS) { // Allocate java.lang.StackTraceElement instance Klass* k = SystemDictionary::StackTraceElement_klass(); assert(k != NULL, "must be loaded in 1.4+"); @@ -1876,17 +1895,13 @@ oop classname = StringTable::intern((char*) str, CHECK_0); java_lang_StackTraceElement::set_declaringClass(element(), classname); - Method* method = holder->method_with_idnum(method_id); - // Method on stack may be obsolete because it was redefined so cannot be - // found by idnum. - if (method == NULL) { - // leave name and fileName null - java_lang_StackTraceElement::set_lineNumber(element(), -1); - return element(); - } + Method* method = holder->method_with_orig_idnum(method_id, version); + + // The method can be NULL if the requested class version is gone + Symbol* sym = (method != NULL) ? method->name() : holder->constants()->symbol_at(cpref); // Fill in method name - oop methodname = StringTable::intern(method->name(), CHECK_0); + oop methodname = StringTable::intern(sym, CHECK_0); java_lang_StackTraceElement::set_methodName(element(), methodname); if (!version_matches(method, version)) { @@ -1895,6 +1910,11 @@ java_lang_StackTraceElement::set_lineNumber(element(), -1); } else { // Fill in source file name and line number. + // Use specific ik version as a holder since the mirror might + // refer to version that is now obsolete and no longer accessible + // via the previous versions list. + holder = holder->get_klass_version(version); + assert(holder != NULL, "sanity check"); Symbol* source = holder->source_file_name(); if (ShowHiddenFrames && source == NULL) source = vmSymbols::unknown_class_name(); @@ -1909,8 +1929,9 @@ oop java_lang_StackTraceElement::create(methodHandle method, int bci, TRAPS) { Handle mirror (THREAD, method->method_holder()->java_mirror()); - int method_id = method->method_idnum(); - return create(mirror, method_id, method->constants()->version(), bci, THREAD); + int method_id = method->orig_method_idnum(); + int cpref = method->name_index(); + return create(mirror, method_id, method->constants()->version(), bci, cpref, THREAD); } void java_lang_reflect_AccessibleObject::compute_offsets() { @@ -2811,33 +2832,6 @@ return (flags(mname) & (MN_IS_METHOD | MN_IS_CONSTRUCTOR)) > 0; } -#if INCLUDE_JVMTI -// Can be executed on VM thread only -void java_lang_invoke_MemberName::adjust_vmtarget(oop mname, Method* old_method, - Method* new_method, bool* trace_name_printed) { - assert(is_method(mname), "wrong type"); - assert(Thread::current()->is_VM_thread(), "not VM thread"); - - Method* target = (Method*)mname->address_field(_vmtarget_offset); - if (target == old_method) { - mname->address_field_put(_vmtarget_offset, (address)new_method); - - if (RC_TRACE_IN_RANGE(0x00100000, 0x00400000)) { - if (!(*trace_name_printed)) { - // RC_TRACE_MESG macro has an embedded ResourceMark - RC_TRACE_MESG(("adjust: name=%s", - old_method->method_holder()->external_name())); - *trace_name_printed = true; - } - // RC_TRACE macro has an embedded ResourceMark - RC_TRACE(0x00400000, ("MemberName method update: %s(%s)", - new_method->name()->as_C_string(), - new_method->signature()->as_C_string())); - } - } -} -#endif // INCLUDE_JVMTI - void java_lang_invoke_MemberName::set_vmtarget(oop mname, Metadata* ref) { assert(is_instance(mname), "wrong type"); // check the type of the vmtarget @@ -2972,14 +2966,49 @@ // Support for java_lang_invoke_CallSite int java_lang_invoke_CallSite::_target_offset; +int java_lang_invoke_CallSite::_context_offset; +int java_lang_invoke_CallSite::_default_context_offset; void java_lang_invoke_CallSite::compute_offsets() { Klass* k = SystemDictionary::CallSite_klass(); if (k != NULL) { compute_offset(_target_offset, k, vmSymbols::target_name(), vmSymbols::java_lang_invoke_MethodHandle_signature()); + compute_offset(_context_offset, k, vmSymbols::context_name(), vmSymbols::sun_misc_Cleaner_signature()); + compute_offset(_default_context_offset, k, + vmSymbols::DEFAULT_CONTEXT_name(), vmSymbols::sun_misc_Cleaner_signature(), + /*is_static=*/true, /*allow_super=*/false); } } +oop java_lang_invoke_CallSite::context_volatile(oop call_site) { + assert(java_lang_invoke_CallSite::is_instance(call_site), ""); + + oop dep_oop = call_site->obj_field_volatile(_context_offset); + return dep_oop; +} + +void java_lang_invoke_CallSite::set_context_volatile(oop call_site, oop context) { + assert(java_lang_invoke_CallSite::is_instance(call_site), ""); + call_site->obj_field_put_volatile(_context_offset, context); +} + +bool java_lang_invoke_CallSite::set_context_cas(oop call_site, oop context, oop expected) { + assert(java_lang_invoke_CallSite::is_instance(call_site), ""); + HeapWord* context_addr = call_site->obj_field_addr(_context_offset); + oop res = oopDesc::atomic_compare_exchange_oop(context, context_addr, expected, true); + bool success = (res == expected); + if (success) { + update_barrier_set((void*)context_addr, context); + } + return success; +} + +oop java_lang_invoke_CallSite::default_context() { + InstanceKlass* ik = InstanceKlass::cast(SystemDictionary::CallSite_klass()); + oop def_context_oop = ik->java_mirror()->obj_field(_default_context_offset); + assert(!oopDesc::is_null(def_context_oop), ""); + return def_context_oop; +} // Support for java_security_AccessControlContext @@ -3606,7 +3635,7 @@ tty->print_cr(" name: %s, sig: %s, flags: %08x", fs.name()->as_C_string(), fs.signature()->as_C_string(), fs.access_flags().as_int()); } #endif //PRODUCT - fatal("Invalid layout of preloaded class"); + vm_exit_during_initialization("Invalid layout of preloaded class: use -XX:+TraceClassLoading to see the origin of the problem class"); return -1; } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/classfile/javaClasses.hpp --- a/hotspot/src/share/vm/classfile/javaClasses.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Thu May 07 20:51:12 2015 -0700 @@ -485,8 +485,9 @@ trace_methods_offset = 0, trace_bcis_offset = 1, trace_mirrors_offset = 2, - trace_next_offset = 3, - trace_size = 4, + trace_cprefs_offset = 3, + trace_next_offset = 4, + trace_size = 5, trace_chunk_size = 32 }; @@ -497,7 +498,7 @@ static int static_unassigned_stacktrace_offset; // Printing - static char* print_stack_element_to_buffer(Handle mirror, int method, int version, int bci); + static char* print_stack_element_to_buffer(Handle mirror, int method, int version, int bci, int cpref); // StackTrace (programmatic access, new since 1.4) static void clear_stacktrace(oop throwable); // No stack trace available @@ -519,7 +520,7 @@ static void set_message(oop throwable, oop value); static Symbol* detail_message(oop throwable); static void print_stack_element(outputStream *st, Handle mirror, int method, - int version, int bci); + int version, int bci, int cpref); static void print_stack_element(outputStream *st, methodHandle method, int bci); static void print_stack_usage(Handle stream); @@ -961,7 +962,6 @@ static void set_clock(jlong value); }; - // Interface to java.lang.invoke.MethodHandle objects class MethodHandleEntry; @@ -1091,10 +1091,6 @@ static Metadata* vmtarget(oop mname); static void set_vmtarget(oop mname, Metadata* target); -#if INCLUDE_JVMTI - static void adjust_vmtarget(oop mname, Method* old_method, Method* new_method, - bool* trace_name_printed); -#endif // INCLUDE_JVMTI static intptr_t vmindex(oop mname); static void set_vmindex(oop mname, intptr_t index); @@ -1173,16 +1169,23 @@ private: static int _target_offset; + static int _context_offset; + static int _default_context_offset; + static void compute_offsets(); public: // Accessors - static oop target( oop site); - static void set_target( oop site, oop target); + static oop target( oop site); + static void set_target( oop site, oop target); + static void set_target_volatile( oop site, oop target); - static volatile oop target_volatile(oop site); - static void set_target_volatile(oop site, oop target); + static oop context_volatile(oop site); + static void set_context_volatile(oop site, oop context); + static bool set_context_cas (oop site, oop context, oop expected); + + static oop default_context(); // Testers static bool is_subclass(Klass* klass) { @@ -1194,7 +1197,6 @@ static int target_offset_in_bytes() { return _target_offset; } }; - // Interface to java.security.AccessControlContext objects class java_security_AccessControlContext: AllStatic { @@ -1314,7 +1316,7 @@ static void set_lineNumber(oop element, int value); // Create an instance of StackTraceElement - static oop create(Handle mirror, int method, int version, int bci, TRAPS); + static oop create(Handle mirror, int method, int version, int bci, int cpref, TRAPS); static oop create(methodHandle method, int bci, TRAPS); // Debugging diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/classfile/javaClasses.inline.hpp --- a/hotspot/src/share/vm/classfile/javaClasses.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/classfile/javaClasses.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -29,10 +29,6 @@ #include "oops/oop.inline.hpp" #include "oops/oopsHierarchy.hpp" -inline volatile oop java_lang_invoke_CallSite::target_volatile(oop site) { - return oop((oopDesc *)(site->obj_field_volatile(_target_offset))); -} - inline void java_lang_invoke_CallSite::set_target_volatile(oop site, oop target) { site->obj_field_put_volatile(_target_offset, target); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/classfile/verifier.cpp --- a/hotspot/src/share/vm/classfile/verifier.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/classfile/verifier.cpp Thu May 07 20:51:12 2015 -0700 @@ -657,6 +657,7 @@ bool this_uninit = false; // Set to true when invokespecial initialized 'this' + bool verified_exc_handlers = false; // Merge with the next instruction { @@ -688,6 +689,18 @@ } } + // Look for possible jump target in exception handlers and see if it + // matches current_frame. Do this check here for astore*, dstore*, + // fstore*, istore*, and lstore* opcodes because they can change the type + // state by adding a local. JVM Spec says that the incoming type state + // should be used for this check. So, do the check here before a possible + // local is added to the type state. + if (Bytecodes::is_store_into_local(opcode) && bci >= ex_min && bci < ex_max) { + verify_exception_handler_targets( + bci, this_uninit, ¤t_frame, &stackmap_table, CHECK_VERIFY(this)); + verified_exc_handlers = true; + } + switch (opcode) { case Bytecodes::_nop : no_control_flow = false; break; @@ -1669,9 +1682,13 @@ } // end switch } // end Merge with the next instruction - // Look for possible jump target in exception handlers and see if it - // matches current_frame - if (bci >= ex_min && bci < ex_max) { + // Look for possible jump target in exception handlers and see if it matches + // current_frame. Don't do this check if it has already been done (for + // ([a,d,f,i,l]store* opcodes). This check cannot be done earlier because + // opcodes, such as invokespecial, may set the this_uninit flag. + assert(!(verified_exc_handlers && this_uninit), + "Exception handler targets got verified before this_uninit got set"); + if (!verified_exc_handlers && bci >= ex_min && bci < ex_max) { verify_exception_handler_targets( bci, this_uninit, ¤t_frame, &stackmap_table, CHECK_VERIFY(this)); } @@ -2236,14 +2253,20 @@ } // Look at the method's handlers. If the bci is in the handler's try block -// then check if the handler_pc is already on the stack. If not, push it. +// then check if the handler_pc is already on the stack. If not, push it +// unless the handler has already been scanned. void ClassVerifier::push_handlers(ExceptionTable* exhandlers, + GrowableArray* handler_list, GrowableArray* handler_stack, u4 bci) { int exlength = exhandlers->length(); for(int x = 0; x < exlength; x++) { if (bci >= exhandlers->start_pc(x) && bci < exhandlers->end_pc(x)) { - handler_stack->append_if_missing(exhandlers->handler_pc(x)); + u4 exhandler_pc = exhandlers->handler_pc(x); + if (!handler_list->contains(exhandler_pc)) { + handler_stack->append_if_missing(exhandler_pc); + handler_list->append(exhandler_pc); + } } } } @@ -2261,6 +2284,10 @@ GrowableArray* bci_stack = new GrowableArray(30); // Create stack for handlers for try blocks containing this handler. GrowableArray* handler_stack = new GrowableArray(30); + // Create list of handlers that have been pushed onto the handler_stack + // so that handlers embedded inside of their own TRY blocks only get + // scanned once. + GrowableArray* handler_list = new GrowableArray(30); // Create list of visited branch opcodes (goto* and if*). GrowableArray* visited_branches = new GrowableArray(30); ExceptionTable exhandlers(_method()); @@ -2279,7 +2306,7 @@ // If the bytecode is in a TRY block, push its handlers so they // will get parsed. - push_handlers(&exhandlers, handler_stack, bci); + push_handlers(&exhandlers, handler_list, handler_stack, bci); switch (opcode) { case Bytecodes::_if_icmpeq: diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/classfile/verifier.hpp --- a/hotspot/src/share/vm/classfile/verifier.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/classfile/verifier.hpp Thu May 07 20:51:12 2015 -0700 @@ -305,9 +305,10 @@ bool* this_uninit, constantPoolHandle cp, StackMapTable* stackmap_table, TRAPS); - // Used by ends_in_athrow() to push all handlers that contain bci onto - // the handler_stack, if the handler is not already on the stack. + // Used by ends_in_athrow() to push all handlers that contain bci onto the + // handler_stack, if the handler has not already been pushed on the stack. void push_handlers(ExceptionTable* exhandlers, + GrowableArray* handler_list, GrowableArray* handler_stack, u4 bci); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/classfile/vmSymbols.hpp --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Thu May 07 20:51:12 2015 -0700 @@ -292,6 +292,7 @@ template(setTargetNormal_name, "setTargetNormal") \ template(setTargetVolatile_name, "setTargetVolatile") \ template(setTarget_signature, "(Ljava/lang/invoke/MethodHandle;)V") \ + template(DEFAULT_CONTEXT_name, "DEFAULT_CONTEXT") \ NOT_LP64( do_alias(intptr_signature, int_signature) ) \ LP64_ONLY( do_alias(intptr_signature, long_signature) ) \ \ @@ -501,6 +502,7 @@ template(class_signature, "Ljava/lang/Class;") \ template(string_signature, "Ljava/lang/String;") \ template(reference_signature, "Ljava/lang/ref/Reference;") \ + template(sun_misc_Cleaner_signature, "Lsun/misc/Cleaner;") \ template(executable_signature, "Ljava/lang/reflect/Executable;") \ template(concurrenthashmap_signature, "Ljava/util/concurrent/ConcurrentHashMap;") \ template(String_StringBuilder_signature, "(Ljava/lang/String;)Ljava/lang/StringBuilder;") \ @@ -531,18 +533,17 @@ template(java_lang_management_ThreadState, "java/lang/management/ThreadState") \ template(java_lang_management_MemoryUsage, "java/lang/management/MemoryUsage") \ template(java_lang_management_ThreadInfo, "java/lang/management/ThreadInfo") \ - template(sun_management_ManagementFactory, "sun/management/ManagementFactory") \ template(sun_management_Sensor, "sun/management/Sensor") \ template(sun_management_Agent, "sun/management/Agent") \ - template(sun_management_DiagnosticCommandImpl, "sun/management/DiagnosticCommandImpl") \ - template(sun_management_GarbageCollectorImpl, "sun/management/GarbageCollectorImpl") \ + template(com_sun_management_internal_DiagnosticCommandImpl, "com/sun/management/internal/DiagnosticCommandImpl") \ + template(com_sun_management_internal_GarbageCollectorExtImpl,"com/sun/management/internal/GarbageCollectorExtImpl") \ template(sun_management_ManagementFactoryHelper, "sun/management/ManagementFactoryHelper") \ template(getDiagnosticCommandMBean_name, "getDiagnosticCommandMBean") \ template(getDiagnosticCommandMBean_signature, "()Lcom/sun/management/DiagnosticCommandMBean;") \ template(getGcInfoBuilder_name, "getGcInfoBuilder") \ - template(getGcInfoBuilder_signature, "()Lsun/management/GcInfoBuilder;") \ + template(getGcInfoBuilder_signature, "()Lcom/sun/management/internal/GcInfoBuilder;") \ template(com_sun_management_GcInfo, "com/sun/management/GcInfo") \ - template(com_sun_management_GcInfo_constructor_signature, "(Lsun/management/GcInfoBuilder;JJJ[Ljava/lang/management/MemoryUsage;[Ljava/lang/management/MemoryUsage;[Ljava/lang/Object;)V") \ + template(com_sun_management_GcInfo_constructor_signature, "(Lcom/sun/management/internal/GcInfoBuilder;JJJ[Ljava/lang/management/MemoryUsage;[Ljava/lang/management/MemoryUsage;[Ljava/lang/Object;)V") \ template(createGCNotification_name, "createGCNotification") \ template(createGCNotification_signature, "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/sun/management/GcInfo;)V") \ template(createDiagnosticFrameworkNotification_name, "createDiagnosticFrameworkNotification") \ @@ -554,11 +555,12 @@ template(createGarbageCollectorMBean_signature, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/management/GarbageCollectorMBean;") \ template(trigger_name, "trigger") \ template(clear_name, "clear") \ - template(trigger_method_signature, "(ILjava/lang/management/MemoryUsage;)V") \ + template(trigger_method_signature, "(ILjava/lang/management/MemoryUsage;)V") \ template(startAgent_name, "startAgent") \ template(startRemoteAgent_name, "startRemoteManagementAgent") \ template(startLocalAgent_name, "startLocalManagementAgent") \ template(stopRemoteAgent_name, "stopRemoteManagementAgent") \ + template(getAgentStatus_name, "getManagementAgentStatus") \ template(java_lang_management_ThreadInfo_constructor_signature, "(Ljava/lang/Thread;ILjava/lang/Object;Ljava/lang/Thread;JJJJ[Ljava/lang/StackTraceElement;)V") \ template(java_lang_management_ThreadInfo_with_locks_constructor_signature, "(Ljava/lang/Thread;ILjava/lang/Object;Ljava/lang/Thread;JJJJ[Ljava/lang/StackTraceElement;[Ljava/lang/Object;[I[Ljava/lang/Object;)V") \ template(long_long_long_long_void_signature, "(JJJJ)V") \ @@ -868,9 +870,12 @@ \ /* Custom branch frequencies profiling support for JSR292 */ \ do_class(java_lang_invoke_MethodHandleImpl, "java/lang/invoke/MethodHandleImpl") \ - do_intrinsic(_profileBoolean, java_lang_invoke_MethodHandleImpl, profileBoolean_name, profileBoolean_signature, F_S) \ - do_name( profileBoolean_name, "profileBoolean") \ - do_signature(profileBoolean_signature, "(Z[I)Z") \ + do_intrinsic(_profileBoolean, java_lang_invoke_MethodHandleImpl, profileBoolean_name, profileBoolean_signature, F_S) \ + do_name( profileBoolean_name, "profileBoolean") \ + do_signature(profileBoolean_signature, "(Z[I)Z") \ + do_intrinsic(_isCompileConstant, java_lang_invoke_MethodHandleImpl, isCompileConstant_name, isCompileConstant_signature, F_S) \ + do_name( isCompileConstant_name, "isCompileConstant") \ + do_alias( isCompileConstant_signature, object_boolean_signature) \ \ /* unsafe memory references (there are a lot of them...) */ \ do_signature(getObject_signature, "(Ljava/lang/Object;J)Ljava/lang/Object;") \ @@ -950,6 +955,20 @@ do_intrinsic(_putFloatVolatile, sun_misc_Unsafe, putFloatVolatile_name, putFloat_signature, F_RN) \ do_intrinsic(_putDoubleVolatile, sun_misc_Unsafe, putDoubleVolatile_name, putDouble_signature, F_RN) \ \ + do_name(getShortUnaligned_name,"getShortUnaligned") do_name(putShortUnaligned_name,"putShortUnaligned") \ + do_name(getCharUnaligned_name,"getCharUnaligned") do_name(putCharUnaligned_name,"putCharUnaligned") \ + do_name(getIntUnaligned_name,"getIntUnaligned") do_name(putIntUnaligned_name,"putIntUnaligned") \ + do_name(getLongUnaligned_name,"getLongUnaligned") do_name(putLongUnaligned_name,"putLongUnaligned") \ + \ + do_intrinsic(_getShortUnaligned, sun_misc_Unsafe, getShortUnaligned_name, getShort_signature, F_R) \ + do_intrinsic(_getCharUnaligned, sun_misc_Unsafe, getCharUnaligned_name, getChar_signature, F_R) \ + do_intrinsic(_getIntUnaligned, sun_misc_Unsafe, getIntUnaligned_name, getInt_signature, F_R) \ + do_intrinsic(_getLongUnaligned, sun_misc_Unsafe, getLongUnaligned_name, getLong_signature, F_R) \ + do_intrinsic(_putShortUnaligned, sun_misc_Unsafe, putShortUnaligned_name, putShort_signature, F_R) \ + do_intrinsic(_putCharUnaligned, sun_misc_Unsafe, putCharUnaligned_name, putChar_signature, F_R) \ + do_intrinsic(_putIntUnaligned, sun_misc_Unsafe, putIntUnaligned_name, putInt_signature, F_R) \ + do_intrinsic(_putLongUnaligned, sun_misc_Unsafe, putLongUnaligned_name, putLong_signature, F_R) \ + \ /* %%% these are redundant except perhaps for getAddress, but Unsafe has native methods for them */ \ do_signature(getByte_raw_signature, "(J)B") \ do_signature(putByte_raw_signature, "(JB)V") \ diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/code/codeCache.cpp --- a/hotspot/src/share/vm/code/codeCache.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/code/codeCache.cpp Thu May 07 20:51:12 2015 -0700 @@ -1067,8 +1067,11 @@ int marked = 0; { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - InstanceKlass* call_site_klass = InstanceKlass::cast(call_site->klass()); - marked = call_site_klass->mark_dependent_nmethods(changes); + InstanceKlass* ctxk = MethodHandles::get_call_site_context(call_site()); + if (ctxk == NULL) { + return; // No dependencies to invalidate yet. + } + marked = ctxk->mark_dependent_nmethods(changes); } if (marked > 0) { // At least one nmethod has been marked for deoptimization diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/code/dependencies.cpp --- a/hotspot/src/share/vm/code/dependencies.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/code/dependencies.cpp Thu May 07 20:51:12 2015 -0700 @@ -117,8 +117,9 @@ } void Dependencies::assert_call_site_target_value(ciCallSite* call_site, ciMethodHandle* method_handle) { - check_ctxk(call_site->klass()); - assert_common_2(call_site_target_value, call_site, method_handle); + ciKlass* ctxk = call_site->get_context(); + check_ctxk(ctxk); + assert_common_3(call_site_target_value, ctxk, call_site, method_handle); } // Helper function. If we are adding a new dep. under ctxk2, @@ -388,7 +389,7 @@ 3, // unique_concrete_subtypes_2 ctxk, k1, k2 3, // unique_concrete_methods_2 ctxk, m1, m2 1, // no_finalizable_subclasses ctxk - 2 // call_site_target_value call_site, method_handle + 3 // call_site_target_value ctxk, call_site, method_handle }; const char* Dependencies::dep_name(Dependencies::DepType dept) { @@ -594,7 +595,7 @@ const int nargs = argument_count(); GrowableArray* args = new GrowableArray(nargs); for (int j = 0; j < nargs; j++) { - if (type() == call_site_target_value) { + if (is_oop_argument(j)) { args->push(argument_oop(j)); } else { args->push(argument(j)); @@ -614,7 +615,7 @@ int nargs = argument_count(); GrowableArray* args = new GrowableArray(nargs); for (int j = 0; j < nargs; j++) { - if (type() == call_site_target_value) { + if (is_oop_argument(j)) { args->push(argument_oop(j)); } else { args->push(argument(j)); @@ -710,7 +711,7 @@ * Returns a unique identifier for each dependency argument. */ uintptr_t Dependencies::DepStream::get_identifier(int i) { - if (has_oop_argument()) { + if (is_oop_argument(i)) { return (uintptr_t)(oopDesc*)argument_oop(i); } else { return (uintptr_t)argument(i); @@ -737,7 +738,7 @@ } // Some dependencies are using the klass of the first object - // argument as implicit context type (e.g. call_site_target_value). + // argument as implicit context type. { int ctxkj = dep_implicit_context_arg(type()); if (ctxkj >= 0) { @@ -845,7 +846,13 @@ assert((uint)n <= (uint)_num_participants, "oob"); Method* fm = _found_methods[n]; assert(n == _num_participants || fm != NULL, "proper usage"); - assert(fm == NULL || fm->method_holder() == _participants[n], "sanity"); + if (fm != NULL && fm->method_holder() != _participants[n]) { + // Default methods from interfaces can be added to classes. In + // that case the holder of the method is not the class but the + // interface where it's defined. + assert(fm->is_default_method(), "sanity"); + return NULL; + } return fm; } @@ -1508,9 +1515,16 @@ return find_finalizable_subclass(search_at); } -Klass* Dependencies::check_call_site_target_value(oop call_site, oop method_handle, CallSiteDepChange* changes) { - assert(call_site ->is_a(SystemDictionary::CallSite_klass()), "sanity"); - assert(method_handle->is_a(SystemDictionary::MethodHandle_klass()), "sanity"); +Klass* Dependencies::check_call_site_target_value(Klass* recorded_ctxk, oop call_site, oop method_handle, CallSiteDepChange* changes) { + assert(call_site->is_a(SystemDictionary::CallSite_klass()), "sanity"); + assert(!oopDesc::is_null(method_handle), "sanity"); + + Klass* call_site_ctxk = MethodHandles::get_call_site_context(call_site); + assert(!Klass::is_null(call_site_ctxk), "call site context should be initialized already"); + if (recorded_ctxk != call_site_ctxk) { + // Stale context + return recorded_ctxk; + } if (changes == NULL) { // Validate all CallSites if (java_lang_invoke_CallSite::target(call_site) != method_handle) @@ -1525,7 +1539,6 @@ return NULL; // assertion still valid } - void Dependencies::DepStream::trace_and_log_witness(Klass* witness) { if (witness != NULL) { if (TraceDependencies) { @@ -1586,7 +1599,7 @@ Klass* witness = NULL; switch (type()) { case call_site_target_value: - witness = check_call_site_target_value(argument_oop(0), argument_oop(1), changes); + witness = check_call_site_target_value(context_type(), argument_oop(1), argument_oop(2), changes); break; default: witness = NULL; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/code/dependencies.hpp --- a/hotspot/src/share/vm/code/dependencies.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/code/dependencies.hpp Thu May 07 20:51:12 2015 -0700 @@ -174,7 +174,7 @@ klass_types = all_types & ~non_klass_types, non_ctxk_types = (1 << evol_method), - implicit_ctxk_types = (1 << call_site_target_value), + implicit_ctxk_types = 0, explicit_ctxk_types = all_types & ~(non_ctxk_types | implicit_ctxk_types), max_arg_count = 3, // current maximum number of arguments (incl. ctxk) @@ -330,7 +330,7 @@ static Klass* check_exclusive_concrete_methods(Klass* ctxk, Method* m1, Method* m2, KlassDepChange* changes = NULL); static Klass* check_has_no_finalizable_subclasses(Klass* ctxk, KlassDepChange* changes = NULL); - static Klass* check_call_site_target_value(oop call_site, oop method_handle, CallSiteDepChange* changes = NULL); + static Klass* check_call_site_target_value(Klass* recorded_ctxk, oop call_site, oop method_handle, CallSiteDepChange* changes = NULL); // A returned Klass* is NULL if the dependency assertion is still // valid. A non-NULL Klass* is a 'witness' to the assertion // failure, a point in the class hierarchy where the assertion has @@ -496,7 +496,7 @@ bool next(); DepType type() { return _type; } - bool has_oop_argument() { return type() == call_site_target_value; } + bool is_oop_argument(int i) { return type() == call_site_target_value && i > 0; } uintptr_t get_identifier(int i); int argument_count() { return dep_args(type()); } @@ -682,7 +682,7 @@ _method_handle(method_handle) { assert(_call_site() ->is_a(SystemDictionary::CallSite_klass()), "must be"); - assert(_method_handle()->is_a(SystemDictionary::MethodHandle_klass()), "must be"); + assert(_method_handle.is_null() || _method_handle()->is_a(SystemDictionary::MethodHandle_klass()), "must be"); } // What kind of DepChange is this? diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/code/nmethod.cpp --- a/hotspot/src/share/vm/code/nmethod.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/code/nmethod.cpp Thu May 07 20:51:12 2015 -0700 @@ -504,7 +504,7 @@ basic_lock_owner_sp_offset, basic_lock_sp_offset, oop_maps); NOT_PRODUCT(if (nm != NULL) nmethod_stats.note_native_nmethod(nm)); - if (PrintAssembly && nm != NULL) { + if ((PrintAssembly || CompilerOracle::should_print(method)) && nm != NULL) { Disassembler::decode(nm); } } @@ -2325,6 +2325,7 @@ // Dependency checking failed. Print out information about the failed // dependency and finally fail with an assert. We can fail here, since // dependency checking is never done in a product build. + tty->print_cr("Failed dependency:"); changes.print(); nm->print(); nm->print_dependencies(); @@ -2837,11 +2838,21 @@ st.print(")"); return st.as_string(); } + case relocInfo::runtime_call_type: { + stringStream st; + st.print("runtime_call"); + runtime_call_Relocation* r = iter.runtime_call_reloc(); + address dest = r->destination(); + CodeBlob* cb = CodeCache::find_blob(dest); + if (cb != NULL) { + st.print(" %s", cb->name()); + } + return st.as_string(); + } case relocInfo::virtual_call_type: return "virtual_call"; case relocInfo::opt_virtual_call_type: return "optimized virtual_call"; case relocInfo::static_call_type: return "static_call"; case relocInfo::static_stub_type: return "static_stub"; - case relocInfo::runtime_call_type: return "runtime_call"; case relocInfo::external_word_type: return "external_word"; case relocInfo::internal_word_type: return "internal_word"; case relocInfo::section_word_type: return "section_word"; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/code/pcDesc.cpp --- a/hotspot/src/share/vm/code/pcDesc.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/code/pcDesc.cpp Thu May 07 20:51:12 2015 -0700 @@ -54,12 +54,7 @@ for (ScopeDesc* sd = code->scope_desc_at(real_pc(code)); sd != NULL; sd = sd->sender()) { - tty->print(" "); - sd->method()->print_short_name(tty); - tty->print(" @%d", sd->bci()); - if (sd->should_reexecute()) - tty->print(" reexecute=true"); - tty->cr(); + sd->print_on(tty); } #endif } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/code/scopeDesc.cpp --- a/hotspot/src/share/vm/code/scopeDesc.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/code/scopeDesc.cpp Thu May 07 20:51:12 2015 -0700 @@ -157,14 +157,18 @@ #ifndef PRODUCT void ScopeDesc::print_value_on(outputStream* st) const { - tty->print(" "); + st->print(" "); method()->print_short_name(st); int lineno = method()->line_number_from_bci(bci()); if (lineno != -1) { - st->print_cr("@%d (line %d)", bci(), lineno); + st->print("@%d (line %d)", bci(), lineno); } else { - st->print_cr("@%d", bci()); + st->print("@%d", bci()); } + if (should_reexecute()) { + st->print(" reexecute=true"); + } + st->cr(); } void ScopeDesc::print_on(outputStream* st) const { @@ -174,7 +178,7 @@ void ScopeDesc::print_on(outputStream* st, PcDesc* pd) const { // header if (pd != NULL) { - tty->print_cr("ScopeDesc(pc=" PTR_FORMAT " offset=%x):", pd->real_pc(_code), pd->pc_offset()); + st->print_cr("ScopeDesc(pc=" PTR_FORMAT " offset=%x):", pd->real_pc(_code), pd->pc_offset()); } print_value_on(st); @@ -192,7 +196,7 @@ // locals { GrowableArray* l = ((ScopeDesc*) this)->locals(); if (l != NULL) { - tty->print_cr(" Locals"); + st->print_cr(" Locals"); for (int index = 0; index < l->length(); index++) { st->print(" - l%d: ", index); l->at(index)->print_on(st); @@ -205,7 +209,7 @@ if (l != NULL) { st->print_cr(" Expression stack"); for (int index = 0; index < l->length(); index++) { - st->print(" - @%d: ", index); + st->print(" - @%d: ", index); l->at(index)->print_on(st); st->cr(); } @@ -225,12 +229,12 @@ #ifdef COMPILER2 if (DoEscapeAnalysis && is_top() && _objects != NULL) { - tty->print_cr("Objects"); + st->print_cr(" Objects"); for (int i = 0; i < _objects->length(); i++) { ObjectValue* sv = (ObjectValue*) _objects->at(i); - tty->print(" - %d: ", sv->id()); - sv->print_fields_on(tty); - tty->cr(); + st->print(" - %d: ", sv->id()); + sv->print_fields_on(st); + st->cr(); } } #endif // COMPILER2 diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/compiler/compileBroker.hpp --- a/hotspot/src/share/vm/compiler/compileBroker.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/compiler/compileBroker.hpp Thu May 07 20:51:12 2015 -0700 @@ -172,7 +172,8 @@ // these methods should be called in a thread safe context void set_current_method(const char* method) { - strncpy(_current_method, method, (size_t)cmname_buffer_length); + strncpy(_current_method, method, (size_t)cmname_buffer_length-1); + _current_method[cmname_buffer_length-1] = '\0'; if (UsePerfData) _perf_current_method->set_value(method); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/compiler/compilerOracle.cpp --- a/hotspot/src/share/vm/compiler/compilerOracle.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/compiler/compilerOracle.cpp Thu May 07 20:51:12 2015 -0700 @@ -673,9 +673,7 @@ // so read integer and fraction part of double value separately. if (sscanf(line, "%*[ \t]%255[0-9]%*[ /\t]%255[0-9]%n", buffer[0], buffer[1], &bytes_read) == 2) { char value[512] = ""; - strncat(value, buffer[0], 255); - strcat(value, "."); - strncat(value, buffer[1], 255); + jio_snprintf(value, sizeof(value), "%s.%s", buffer[0], buffer[1]); total_bytes_read += bytes_read; return add_option_string(c_name, c_match, m_name, m_match, signature, flag, atof(value)); } else { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/compiler/disassembler.cpp --- a/hotspot/src/share/vm/compiler/disassembler.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/compiler/disassembler.cpp Thu May 07 20:51:12 2015 -0700 @@ -300,6 +300,7 @@ strlen((const char*)arg) > sizeof(buffer) - 1) { // Only print this when the mach changes strncpy(buffer, (const char*)arg, sizeof(buffer) - 1); + buffer[sizeof(buffer) - 1] = '\0'; output()->print_cr("[Disassembling for mach='%s']", arg); } } else if (match(event, "format bytes-per-line")) { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/adaptiveFreeList.cpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/adaptiveFreeList.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/adaptiveFreeList.cpp Thu May 07 20:51:12 2015 -0700 @@ -25,8 +25,8 @@ #include "precompiled.hpp" #include "gc_implementation/concurrentMarkSweep/adaptiveFreeList.hpp" #include "gc_implementation/concurrentMarkSweep/freeChunk.hpp" +#include "gc_interface/collectedHeap.hpp" #include "memory/freeBlockDictionary.hpp" -#include "memory/sharedHeap.hpp" #include "runtime/globals.hpp" #include "runtime/mutex.hpp" #include "runtime/orderAccess.inline.hpp" diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsOopClosures.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsOopClosures.cpp Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc_implementation/concurrentMarkSweep/cmsOopClosures.inline.hpp" +#include "memory/iterator.inline.hpp" +#include "memory/specialized_oop_closures.hpp" + +// Generate CMS specialized oop_oop_iterate functions. +SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_CMS(ALL_KLASS_OOP_OOP_ITERATE_DEFN) diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Thu May 07 20:51:12 2015 -0700 @@ -32,6 +32,7 @@ #include "gc_interface/collectedHeap.inline.hpp" #include "memory/allocation.inline.hpp" #include "memory/blockOffsetTable.inline.hpp" +#include "memory/genCollectedHeap.hpp" #include "memory/resourceArea.hpp" #include "memory/space.inline.hpp" #include "memory/universe.inline.hpp" @@ -673,10 +674,10 @@ HeapWord* bottom, \ HeapWord* top, \ ClosureType* cl) { \ - bool is_par = SharedHeap::heap()->n_par_threads() > 0; \ + bool is_par = GenCollectedHeap::heap()->n_par_threads() > 0; \ if (is_par) { \ - assert(SharedHeap::heap()->n_par_threads() == \ - SharedHeap::heap()->workers()->active_workers(), "Mismatch"); \ + assert(GenCollectedHeap::heap()->n_par_threads() == \ + GenCollectedHeap::heap()->workers()->active_workers(), "Mismatch"); \ walk_mem_region_with_cl_par(mr, bottom, top, cl); \ } else { \ walk_mem_region_with_cl_nopar(mr, bottom, top, cl); \ @@ -1907,11 +1908,11 @@ assert(chunk->is_free() && ffc->is_free(), "Error"); _bt.split_block((HeapWord*)chunk, chunk->size(), new_size); if (rem_sz < SmallForDictionary) { - bool is_par = (SharedHeap::heap()->n_par_threads() > 0); + bool is_par = (GenCollectedHeap::heap()->n_par_threads() > 0); if (is_par) _indexedFreeListParLocks[rem_sz]->lock(); assert(!is_par || - (SharedHeap::heap()->n_par_threads() == - SharedHeap::heap()->workers()->active_workers()), "Mismatch"); + (GenCollectedHeap::heap()->n_par_threads() == + GenCollectedHeap::heap()->workers()->active_workers()), "Mismatch"); returnChunkToFreeList(ffc); split(size, rem_sz); if (is_par) _indexedFreeListParLocks[rem_sz]->unlock(); @@ -1982,7 +1983,7 @@ bool CompactibleFreeListSpace::no_allocs_since_save_marks() { assert(_promoInfo.tracking(), "No preceding save_marks?"); - assert(SharedHeap::heap()->n_par_threads() == 0, + assert(GenCollectedHeap::heap()->n_par_threads() == 0, "Shouldn't be called if using parallel gc."); return _promoInfo.noPromotions(); } @@ -1991,7 +1992,7 @@ \ void CompactibleFreeListSpace:: \ oop_since_save_marks_iterate##nv_suffix(OopClosureType* blk) { \ - assert(SharedHeap::heap()->n_par_threads() == 0, \ + assert(GenCollectedHeap::heap()->n_par_threads() == 0, \ "Shouldn't be called (yet) during parallel part of gc."); \ _promoInfo.promoted_oops_iterate##nv_suffix(blk); \ /* \ @@ -2442,11 +2443,10 @@ { VerifyAllOopsClosure cl(_collector, this, span, past_remark, _collector->markBitMap()); - CollectedHeap* ch = Universe::heap(); // Iterate over all oops in the heap. Uses the _no_header version // since we are not interested in following the klass pointers. - ch->oop_iterate_no_header(&cl); + GenCollectedHeap::heap()->oop_iterate_no_header(&cl); } if (VerifyObjectStartArray) { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp Thu May 07 20:51:12 2015 -0700 @@ -28,7 +28,7 @@ #include "gc_implementation/concurrentMarkSweep/adaptiveFreeList.hpp" #include "gc_implementation/concurrentMarkSweep/promotionInfo.hpp" #include "memory/binaryTreeDictionary.hpp" -#include "memory/blockOffsetTable.inline.hpp" +#include "memory/blockOffsetTable.hpp" #include "memory/freeList.hpp" #include "memory/space.hpp" diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Thu May 07 20:51:12 2015 -0700 @@ -53,6 +53,7 @@ #include "memory/padded.hpp" #include "memory/referencePolicy.hpp" #include "memory/resourceArea.hpp" +#include "memory/strongRootsScope.hpp" #include "memory/tenuredGeneration.hpp" #include "oops/oop.inline.hpp" #include "prims/jvmtiExport.hpp" @@ -64,6 +65,7 @@ #include "runtime/vmThread.hpp" #include "services/memoryService.hpp" #include "services/runtimeService.hpp" +#include "utilities/stack.inline.hpp" // statics CMSCollector* ConcurrentMarkSweepGeneration::_collector = NULL; @@ -208,10 +210,6 @@ use_adaptive_freelists, dictionaryChoice); NOT_PRODUCT(debug_cms_space = _cmsSpace;) - if (_cmsSpace == NULL) { - vm_exit_during_initialization( - "CompactibleFreeListSpace allocation failure"); - } _cmsSpace->_gen = this; _gc_stats = new CMSGCStats(); @@ -230,14 +228,8 @@ typedef CMSParGCThreadState* CMSParGCThreadStatePtr; _par_gc_thread_states = NEW_C_HEAP_ARRAY(CMSParGCThreadStatePtr, ParallelGCThreads, mtGC); - if (_par_gc_thread_states == NULL) { - vm_exit_during_initialization("Could not allocate par gc structs"); - } for (uint i = 0; i < ParallelGCThreads; i++) { _par_gc_thread_states[i] = new CMSParGCThreadState(cmsSpace()); - if (_par_gc_thread_states[i] == NULL) { - vm_exit_during_initialization("Could not allocate par gc structs"); - } } } else { _par_gc_thread_states = NULL; @@ -308,8 +300,6 @@ AdaptiveSizePolicy* CMSCollector::size_policy() { GenCollectedHeap* gch = GenCollectedHeap::heap(); - assert(gch->kind() == CollectedHeap::GenCollectedHeap, - "Wrong type of heap"); return gch->gen_policy()->size_policy(); } @@ -586,11 +576,6 @@ return; } _hash_seed = NEW_C_HEAP_ARRAY(int, num_queues, mtGC); - if (_hash_seed == NULL) { - warning("_hash_seed array allocation failure"); - return; - } - typedef Padded PaddedOopTaskQueue; for (i = 0; i < num_queues; i++) { PaddedOopTaskQueue *q = new PaddedOopTaskQueue(); @@ -633,12 +618,7 @@ _eden_chunk_index = 0; _eden_chunk_capacity = (_young_gen->max_capacity()+CMSSamplingGrain)/CMSSamplingGrain; _eden_chunk_array = NEW_C_HEAP_ARRAY(HeapWord*, _eden_chunk_capacity, mtGC); - if (_eden_chunk_array == NULL) { - _eden_chunk_capacity = 0; - warning("GC/CMS: _eden_chunk_array allocation failure"); - } - } - assert(_eden_chunk_array != NULL || _eden_chunk_capacity == 0, "Error"); + } // Support for parallelizing survivor space rescan if ((CMSParallelRemarkEnabled && CMSParallelSurvivorRemarkEnabled) || CMSParallelInitialMarkEnabled) { @@ -648,52 +628,15 @@ _survivor_plab_array = NEW_C_HEAP_ARRAY(ChunkArray, ParallelGCThreads, mtGC); _survivor_chunk_array = NEW_C_HEAP_ARRAY(HeapWord*, 2*max_plab_samples, mtGC); _cursor = NEW_C_HEAP_ARRAY(size_t, ParallelGCThreads, mtGC); - if (_survivor_plab_array == NULL || _survivor_chunk_array == NULL - || _cursor == NULL) { - warning("Failed to allocate survivor plab/chunk array"); - if (_survivor_plab_array != NULL) { - FREE_C_HEAP_ARRAY(ChunkArray, _survivor_plab_array); - _survivor_plab_array = NULL; - } - if (_survivor_chunk_array != NULL) { - FREE_C_HEAP_ARRAY(HeapWord*, _survivor_chunk_array); - _survivor_chunk_array = NULL; - } - if (_cursor != NULL) { - FREE_C_HEAP_ARRAY(size_t, _cursor); - _cursor = NULL; - } - } else { - _survivor_chunk_capacity = 2*max_plab_samples; - for (uint i = 0; i < ParallelGCThreads; i++) { - HeapWord** vec = NEW_C_HEAP_ARRAY(HeapWord*, max_plab_samples, mtGC); - if (vec == NULL) { - warning("Failed to allocate survivor plab array"); - for (int j = i; j > 0; j--) { - FREE_C_HEAP_ARRAY(HeapWord*, _survivor_plab_array[j-1].array()); - } - FREE_C_HEAP_ARRAY(ChunkArray, _survivor_plab_array); - FREE_C_HEAP_ARRAY(HeapWord*, _survivor_chunk_array); - _survivor_plab_array = NULL; - _survivor_chunk_array = NULL; - _survivor_chunk_capacity = 0; - break; - } else { - ChunkArray* cur = - ::new (&_survivor_plab_array[i]) ChunkArray(vec, - max_plab_samples); - assert(cur->end() == 0, "Should be 0"); - assert(cur->array() == vec, "Should be vec"); - assert(cur->capacity() == max_plab_samples, "Error"); - } - } - } - } - assert( ( _survivor_plab_array != NULL - && _survivor_chunk_array != NULL) - || ( _survivor_chunk_capacity == 0 - && _survivor_chunk_index == 0), - "Error"); + _survivor_chunk_capacity = 2*max_plab_samples; + for (uint i = 0; i < ParallelGCThreads; i++) { + HeapWord** vec = NEW_C_HEAP_ARRAY(HeapWord*, max_plab_samples, mtGC); + ChunkArray* cur = ::new (&_survivor_plab_array[i]) ChunkArray(vec, max_plab_samples); + assert(cur->end() == 0, "Should be 0"); + assert(cur->array() == vec, "Should be vec"); + assert(cur->capacity() == max_plab_samples, "Error"); + } + } NOT_PRODUCT(_overflow_counter = CMSMarkStackOverflowInterval;) _gc_counters = new CollectorCounters("CMS", 1); @@ -1037,7 +980,7 @@ assert_lock_strong(freelistLock()); #ifndef PRODUCT - if (Universe::heap()->promotion_should_fail()) { + if (GenCollectedHeap::heap()->promotion_should_fail()) { return NULL; } #endif // #ifndef PRODUCT @@ -1114,7 +1057,7 @@ oop old, markOop m, size_t word_sz) { #ifndef PRODUCT - if (Universe::heap()->promotion_should_fail()) { + if (GenCollectedHeap::heap()->promotion_should_fail()) { return NULL; } #endif // #ifndef PRODUCT @@ -2524,7 +2467,7 @@ verification_mark_bm()->iterate(&vcl); if (vcl.failed()) { gclog_or_tty->print("Verification failed"); - Universe::heap()->print_on(gclog_or_tty); + gch->print_on(gclog_or_tty); fatal("CMS: failed marking verification after remark"); } } @@ -3071,10 +3014,10 @@ gch->set_par_threads(n_workers); initialize_sequential_subtasks_for_young_gen_rescan(n_workers); if (n_workers > 1) { - GenCollectedHeap::StrongRootsScope srs(gch); + StrongRootsScope srs; workers->run_task(&tsk); } else { - GenCollectedHeap::StrongRootsScope srs(gch); + StrongRootsScope srs; tsk.work(0); } gch->set_par_threads(0); @@ -5169,11 +5112,11 @@ // necessarily be so, since it's possible that we are doing // ST marking. ReferenceProcessorMTDiscoveryMutator mt(ref_processor(), true); - GenCollectedHeap::StrongRootsScope srs(gch); + StrongRootsScope srs; workers->run_task(&tsk); } else { ReferenceProcessorMTDiscoveryMutator mt(ref_processor(), false); - GenCollectedHeap::StrongRootsScope srs(gch); + StrongRootsScope srs; tsk.work(0); } @@ -5241,7 +5184,7 @@ verify_work_stacks_empty(); gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel. - GenCollectedHeap::StrongRootsScope srs(gch); + StrongRootsScope srs; gch->gen_process_roots(_cmsGen->level(), true, // younger gens as roots diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Thu May 07 20:51:12 2015 -0700 @@ -35,11 +35,11 @@ #include "memory/freeBlockDictionary.hpp" #include "memory/iterator.hpp" #include "memory/space.hpp" +#include "memory/virtualspace.hpp" #include "runtime/mutexLocker.hpp" -#include "runtime/virtualspace.hpp" #include "services/memoryService.hpp" -#include "utilities/bitMap.inline.hpp" -#include "utilities/stack.inline.hpp" +#include "utilities/bitMap.hpp" +#include "utilities/stack.hpp" #include "utilities/taskqueue.hpp" #include "utilities/yieldingWorkgroup.hpp" diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp Thu May 07 20:51:12 2015 -0700 @@ -27,7 +27,7 @@ #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp" #include "gc_implementation/shared/concurrentGCThread.hpp" -#include "runtime/thread.inline.hpp" +#include "runtime/thread.hpp" class ConcurrentMarkSweepGeneration; class CMSCollector; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/promotionInfo.cpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/promotionInfo.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/promotionInfo.cpp Thu May 07 20:51:12 2015 -0700 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "memory/genOopClosures.hpp" #include "gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp" #include "gc_implementation/concurrentMarkSweep/promotionInfo.hpp" #include "oops/markOop.inline.hpp" diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ HandleMark hm; FreelistLocker x(_collector); MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag); - Universe::heap()->prepare_for_verify(); + GenCollectedHeap::heap()->prepare_for_verify(); Universe::verify(); } } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Thu May 07 20:51:12 2015 -0700 @@ -34,6 +34,7 @@ #include "gc_implementation/g1/g1Log.hpp" #include "gc_implementation/g1/g1OopClosures.inline.hpp" #include "gc_implementation/g1/g1RemSet.hpp" +#include "gc_implementation/g1/g1StringDedup.hpp" #include "gc_implementation/g1/heapRegion.inline.hpp" #include "gc_implementation/g1/heapRegionManager.inline.hpp" #include "gc_implementation/g1/heapRegionRemSet.hpp" @@ -46,6 +47,7 @@ #include "memory/genOopClosures.inline.hpp" #include "memory/referencePolicy.hpp" #include "memory/resourceArea.hpp" +#include "memory/strongRootsScope.hpp" #include "oops/oop.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" @@ -115,7 +117,7 @@ } size_t CMBitMap::compute_size(size_t heap_size) { - return heap_size / mark_distance(); + return ReservedSpace::allocation_align_size_up(heap_size / mark_distance()); } size_t CMBitMap::mark_distance() { @@ -941,13 +943,6 @@ _has_aborted = false; -#ifndef PRODUCT - if (G1PrintReachableAtInitialMark) { - print_reachable("at-cycle-start", - VerifyOption_G1UsePrevMarking, true /* all */); - } -#endif - // Initialize marking structures. This has to be done in a STW phase. reset(); @@ -1325,7 +1320,7 @@ if (VerifyDuringGC) { HandleMark hm; // handle scope - Universe::heap()->prepare_for_verify(); + g1h->prepare_for_verify(); Universe::verify(VerifyOption_G1UsePrevMarking, " VerifyDuringGC:(before)"); } @@ -1352,7 +1347,7 @@ // Verify the heap w.r.t. the previous marking bitmap. if (VerifyDuringGC) { HandleMark hm; // handle scope - Universe::heap()->prepare_for_verify(); + g1h->prepare_for_verify(); Universe::verify(VerifyOption_G1UsePrevMarking, " VerifyDuringGC:(overflow)"); } @@ -1378,7 +1373,7 @@ if (VerifyDuringGC) { HandleMark hm; // handle scope - Universe::heap()->prepare_for_verify(); + g1h->prepare_for_verify(); Universe::verify(VerifyOption_G1UseNextMarking, " VerifyDuringGC:(after)"); } @@ -1986,13 +1981,13 @@ if (VerifyDuringGC) { HandleMark hm; // handle scope - Universe::heap()->prepare_for_verify(); + g1h->prepare_for_verify(); Universe::verify(VerifyOption_G1UsePrevMarking, " VerifyDuringGC:(before)"); } g1h->check_bitmaps("Cleanup Start"); - G1CollectorPolicy* g1p = G1CollectedHeap::heap()->g1_policy(); + G1CollectorPolicy* g1p = g1h->g1_policy(); g1p->record_concurrent_mark_cleanup_start(); double start = os::elapsedTime(); @@ -2097,7 +2092,7 @@ if (VerifyDuringGC) { HandleMark hm; // handle scope - Universe::heap()->prepare_for_verify(); + g1h->prepare_for_verify(); Universe::verify(VerifyOption_G1UsePrevMarking, " VerifyDuringGC:(after)"); } @@ -2650,7 +2645,7 @@ g1h->ensure_parsability(false); - G1CollectedHeap::StrongRootsScope srs(g1h); + StrongRootsScope srs; // this is remark, so we'll use up all active threads uint active_workers = g1h->workers()->active_workers(); if (active_workers == 0) { @@ -2682,166 +2677,6 @@ print_stats(); } -#ifndef PRODUCT - -class PrintReachableOopClosure: public OopClosure { -private: - G1CollectedHeap* _g1h; - outputStream* _out; - VerifyOption _vo; - bool _all; - -public: - PrintReachableOopClosure(outputStream* out, - VerifyOption vo, - bool all) : - _g1h(G1CollectedHeap::heap()), - _out(out), _vo(vo), _all(all) { } - - void do_oop(narrowOop* p) { do_oop_work(p); } - void do_oop( oop* p) { do_oop_work(p); } - - template void do_oop_work(T* p) { - oop obj = oopDesc::load_decode_heap_oop(p); - const char* str = NULL; - const char* str2 = ""; - - if (obj == NULL) { - str = ""; - } else if (!_g1h->is_in_g1_reserved(obj)) { - str = " O"; - } else { - HeapRegion* hr = _g1h->heap_region_containing(obj); - bool over_tams = _g1h->allocated_since_marking(obj, hr, _vo); - bool marked = _g1h->is_marked(obj, _vo); - - if (over_tams) { - str = " >"; - if (marked) { - str2 = " AND MARKED"; - } - } else if (marked) { - str = " M"; - } else { - str = " NOT"; - } - } - - _out->print_cr(" "PTR_FORMAT": "PTR_FORMAT"%s%s", - p2i(p), p2i((void*) obj), str, str2); - } -}; - -class PrintReachableObjectClosure : public ObjectClosure { -private: - G1CollectedHeap* _g1h; - outputStream* _out; - VerifyOption _vo; - bool _all; - HeapRegion* _hr; - -public: - PrintReachableObjectClosure(outputStream* out, - VerifyOption vo, - bool all, - HeapRegion* hr) : - _g1h(G1CollectedHeap::heap()), - _out(out), _vo(vo), _all(all), _hr(hr) { } - - void do_object(oop o) { - bool over_tams = _g1h->allocated_since_marking(o, _hr, _vo); - bool marked = _g1h->is_marked(o, _vo); - bool print_it = _all || over_tams || marked; - - if (print_it) { - _out->print_cr(" "PTR_FORMAT"%s", - p2i((void *)o), (over_tams) ? " >" : (marked) ? " M" : ""); - PrintReachableOopClosure oopCl(_out, _vo, _all); - o->oop_iterate_no_header(&oopCl); - } - } -}; - -class PrintReachableRegionClosure : public HeapRegionClosure { -private: - G1CollectedHeap* _g1h; - outputStream* _out; - VerifyOption _vo; - bool _all; - -public: - bool doHeapRegion(HeapRegion* hr) { - HeapWord* b = hr->bottom(); - HeapWord* e = hr->end(); - HeapWord* t = hr->top(); - HeapWord* p = _g1h->top_at_mark_start(hr, _vo); - _out->print_cr("** ["PTR_FORMAT", "PTR_FORMAT"] top: "PTR_FORMAT" " - "TAMS: " PTR_FORMAT, p2i(b), p2i(e), p2i(t), p2i(p)); - _out->cr(); - - HeapWord* from = b; - HeapWord* to = t; - - if (to > from) { - _out->print_cr("Objects in [" PTR_FORMAT ", " PTR_FORMAT "]", p2i(from), p2i(to)); - _out->cr(); - PrintReachableObjectClosure ocl(_out, _vo, _all, hr); - hr->object_iterate_mem_careful(MemRegion(from, to), &ocl); - _out->cr(); - } - - return false; - } - - PrintReachableRegionClosure(outputStream* out, - VerifyOption vo, - bool all) : - _g1h(G1CollectedHeap::heap()), _out(out), _vo(vo), _all(all) { } -}; - -void ConcurrentMark::print_reachable(const char* str, - VerifyOption vo, - bool all) { - gclog_or_tty->cr(); - gclog_or_tty->print_cr("== Doing heap dump... "); - - if (G1PrintReachableBaseFile == NULL) { - gclog_or_tty->print_cr(" #### error: no base file defined"); - return; - } - - if (strlen(G1PrintReachableBaseFile) + 1 + strlen(str) > - (JVM_MAXPATHLEN - 1)) { - gclog_or_tty->print_cr(" #### error: file name too long"); - return; - } - - char file_name[JVM_MAXPATHLEN]; - sprintf(file_name, "%s.%s", G1PrintReachableBaseFile, str); - gclog_or_tty->print_cr(" dumping to file %s", file_name); - - fileStream fout(file_name); - if (!fout.is_open()) { - gclog_or_tty->print_cr(" #### error: could not open file"); - return; - } - - outputStream* out = &fout; - out->print_cr("-- USING %s", _g1h->top_at_mark_start_str(vo)); - out->cr(); - - out->print_cr("--- ITERATING OVER REGIONS"); - out->cr(); - PrintReachableRegionClosure rcl(out, vo, all); - _g1h->heap_region_iterate(&rcl); - out->cr(); - - gclog_or_tty->print_cr(" done"); - gclog_or_tty->flush(); -} - -#endif // PRODUCT - void ConcurrentMark::clearRangePrevBitmap(MemRegion mr) { // Note we are overriding the read-only view of the prev map here, via // the cast. @@ -2958,9 +2793,7 @@ #ifndef PRODUCT enum VerifyNoCSetOopsPhase { VerifyNoCSetOopsStack, - VerifyNoCSetOopsQueues, - VerifyNoCSetOopsSATBCompleted, - VerifyNoCSetOopsSATBThread + VerifyNoCSetOopsQueues }; class VerifyNoCSetOopsClosure : public OopClosure, public ObjectClosure { @@ -2973,8 +2806,6 @@ switch (_phase) { case VerifyNoCSetOopsStack: return "Stack"; case VerifyNoCSetOopsQueues: return "Queue"; - case VerifyNoCSetOopsSATBCompleted: return "Completed SATB Buffers"; - case VerifyNoCSetOopsSATBThread: return "Thread SATB Buffers"; default: ShouldNotReachHere(); } return NULL; @@ -3001,7 +2832,7 @@ virtual void do_oop(narrowOop* p) { // We should not come across narrow oops while scanning marking - // stacks and SATB buffers. + // stacks ShouldNotReachHere(); } @@ -3010,10 +2841,7 @@ } }; -void ConcurrentMark::verify_no_cset_oops(bool verify_stacks, - bool verify_enqueued_buffers, - bool verify_thread_buffers, - bool verify_fingers) { +void ConcurrentMark::verify_no_cset_oops() { assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint"); if (!G1CollectedHeap::heap()->mark_in_progress()) { return; @@ -3021,65 +2849,47 @@ VerifyNoCSetOopsClosure cl; - if (verify_stacks) { - // Verify entries on the global mark stack - cl.set_phase(VerifyNoCSetOopsStack); - _markStack.oops_do(&cl); - - // Verify entries on the task queues - for (uint i = 0; i < _max_worker_id; i += 1) { - cl.set_phase(VerifyNoCSetOopsQueues, i); - CMTaskQueue* queue = _task_queues->queue(i); - queue->oops_do(&cl); - } - } - - SATBMarkQueueSet& satb_qs = JavaThread::satb_mark_queue_set(); - - // Verify entries on the enqueued SATB buffers - if (verify_enqueued_buffers) { - cl.set_phase(VerifyNoCSetOopsSATBCompleted); - satb_qs.iterate_completed_buffers_read_only(&cl); - } - - // Verify entries on the per-thread SATB buffers - if (verify_thread_buffers) { - cl.set_phase(VerifyNoCSetOopsSATBThread); - satb_qs.iterate_thread_buffers_read_only(&cl); + // Verify entries on the global mark stack + cl.set_phase(VerifyNoCSetOopsStack); + _markStack.oops_do(&cl); + + // Verify entries on the task queues + for (uint i = 0; i < _max_worker_id; i += 1) { + cl.set_phase(VerifyNoCSetOopsQueues, i); + CMTaskQueue* queue = _task_queues->queue(i); + queue->oops_do(&cl); } - if (verify_fingers) { - // Verify the global finger - HeapWord* global_finger = finger(); - if (global_finger != NULL && global_finger < _heap_end) { - // The global finger always points to a heap region boundary. We - // use heap_region_containing_raw() to get the containing region - // given that the global finger could be pointing to a free region - // which subsequently becomes continues humongous. If that - // happens, heap_region_containing() will return the bottom of the - // corresponding starts humongous region and the check below will - // not hold any more. - // Since we always iterate over all regions, we might get a NULL HeapRegion - // here. - HeapRegion* global_hr = _g1h->heap_region_containing_raw(global_finger); - guarantee(global_hr == NULL || global_finger == global_hr->bottom(), - err_msg("global finger: "PTR_FORMAT" region: "HR_FORMAT, - p2i(global_finger), HR_FORMAT_PARAMS(global_hr))); - } - - // Verify the task fingers - assert(parallel_marking_threads() <= _max_worker_id, "sanity"); - for (int i = 0; i < (int) parallel_marking_threads(); i += 1) { - CMTask* task = _tasks[i]; - HeapWord* task_finger = task->finger(); - if (task_finger != NULL && task_finger < _heap_end) { - // See above note on the global finger verification. - HeapRegion* task_hr = _g1h->heap_region_containing_raw(task_finger); - guarantee(task_hr == NULL || task_finger == task_hr->bottom() || - !task_hr->in_collection_set(), - err_msg("task finger: "PTR_FORMAT" region: "HR_FORMAT, - p2i(task_finger), HR_FORMAT_PARAMS(task_hr))); - } + // Verify the global finger + HeapWord* global_finger = finger(); + if (global_finger != NULL && global_finger < _heap_end) { + // The global finger always points to a heap region boundary. We + // use heap_region_containing_raw() to get the containing region + // given that the global finger could be pointing to a free region + // which subsequently becomes continues humongous. If that + // happens, heap_region_containing() will return the bottom of the + // corresponding starts humongous region and the check below will + // not hold any more. + // Since we always iterate over all regions, we might get a NULL HeapRegion + // here. + HeapRegion* global_hr = _g1h->heap_region_containing_raw(global_finger); + guarantee(global_hr == NULL || global_finger == global_hr->bottom(), + err_msg("global finger: "PTR_FORMAT" region: "HR_FORMAT, + p2i(global_finger), HR_FORMAT_PARAMS(global_hr))); + } + + // Verify the task fingers + assert(parallel_marking_threads() <= _max_worker_id, "sanity"); + for (int i = 0; i < (int) parallel_marking_threads(); i += 1) { + CMTask* task = _tasks[i]; + HeapWord* task_finger = task->finger(); + if (task_finger != NULL && task_finger < _heap_end) { + // See above note on the global finger verification. + HeapRegion* task_hr = _g1h->heap_region_containing_raw(task_finger); + guarantee(task_hr == NULL || task_finger == task_hr->bottom() || + !task_hr->in_collection_set(), + err_msg("task finger: "PTR_FORMAT" region: "HR_FORMAT, + p2i(task_finger), HR_FORMAT_PARAMS(task_hr))); } } } @@ -3392,22 +3202,29 @@ } #endif -void CMTask::scan_object(oop obj) { +template +inline void CMTask::process_grey_object(oop obj) { + assert(scan || obj->is_typeArray(), "Skipping scan of grey non-typeArray"); assert(_nextMarkBitMap->isMarked((HeapWord*) obj), "invariant"); if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%u] we're scanning object "PTR_FORMAT, + gclog_or_tty->print_cr("[%u] processing grey object " PTR_FORMAT, _worker_id, p2i((void*) obj)); } size_t obj_size = obj->size(); _words_scanned += obj_size; - obj->oop_iterate(_cm_oop_closure); + if (scan) { + obj->oop_iterate(_cm_oop_closure); + } statsOnly( ++_objs_scanned ); check_limits(); } +template void CMTask::process_grey_object(oop); +template void CMTask::process_grey_object(oop); + // Closure for iteration over bitmaps class CMBitMapClosure : public BitMapClosure { private: @@ -3878,12 +3695,11 @@ CMObjectClosure oc(this); SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); - satb_mq_set.set_closure(_worker_id, &oc); // This keeps claiming and applying the closure to completed buffers // until we run out of buffers or we need to abort. while (!has_aborted() && - satb_mq_set.apply_closure_to_completed_buffer(_worker_id)) { + satb_mq_set.apply_closure_to_completed_buffer(&oc)) { if (_cm->verbose_medium()) { gclog_or_tty->print_cr("[%u] processed an SATB buffer", _worker_id); } @@ -3897,8 +3713,6 @@ concurrent() || satb_mq_set.completed_buffers_num() == 0, "invariant"); - satb_mq_set.set_closure(_worker_id, NULL); - // again, this was a potentially expensive operation, decrease the // limits to get the regular clock call early decrease_limits(); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp Thu May 07 20:51:12 2015 -0700 @@ -785,14 +785,9 @@ } // Verify that there are no CSet oops on the stacks (taskqueues / - // global mark stack), enqueued SATB buffers, per-thread SATB - // buffers, and fingers (global / per-task). The boolean parameters - // decide which of the above data structures to verify. If marking - // is not in progress, it's a no-op. - void verify_no_cset_oops(bool verify_stacks, - bool verify_enqueued_buffers, - bool verify_thread_buffers, - bool verify_fingers) PRODUCT_RETURN; + // global mark stack) and fingers (global / per-task). + // If marking is not in progress, it's a no-op. + void verify_no_cset_oops() PRODUCT_RETURN; bool isPrevMarked(oop p) const { assert(p != NULL && p->is_oop(), "expected an oop"); @@ -1100,6 +1095,12 @@ void regular_clock_call(); bool concurrent() { return _concurrent; } + // Test whether objAddr might have already been passed over by the + // mark bitmap scan, and so needs to be pushed onto the mark stack. + bool is_below_finger(HeapWord* objAddr, HeapWord* global_finger) const; + + template void process_grey_object(oop obj); + public: // It resets the task; it should be called right at the beginning of // a marking phase. @@ -1152,7 +1153,7 @@ inline void deal_with_reference(oop obj); // It scans an object and visits its children. - void scan_object(oop obj); + void scan_object(oop obj) { process_grey_object(obj); } // It pushes an object on the local queue. inline void push(oop obj); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -259,14 +259,35 @@ ++_local_pushes ); } -// This determines whether the method below will check both the local -// and global fingers when determining whether to push on the stack a -// gray object (value 1) or whether it will only check the global one -// (value 0). The tradeoffs are that the former will be a bit more -// accurate and possibly push less on the stack, but it might also be -// a little bit slower. +inline bool CMTask::is_below_finger(HeapWord* objAddr, + HeapWord* global_finger) const { + // If objAddr is above the global finger, then the mark bitmap scan + // will find it later, and no push is needed. Similarly, if we have + // a current region and objAddr is between the local finger and the + // end of the current region, then no push is needed. The tradeoff + // of checking both vs only checking the global finger is that the + // local check will be more accurate and so result in fewer pushes, + // but may also be a little slower. + if (_finger != NULL) { + // We have a current region. -#define _CHECK_BOTH_FINGERS_ 1 + // Finger and region values are all NULL or all non-NULL. We + // use _finger to check since we immediately use its value. + assert(_curr_region != NULL, "invariant"); + assert(_region_limit != NULL, "invariant"); + assert(_region_limit <= global_finger, "invariant"); + + // True if objAddr is less than the local finger, or is between + // the region limit and the global finger. + if (objAddr < _finger) { + return true; + } else if (objAddr < _region_limit) { + return false; + } // Else check global finger. + } + // Check global finger. + return objAddr < global_finger; +} inline void CMTask::deal_with_reference(oop obj) { if (_cm->verbose_high()) { @@ -297,50 +318,43 @@ // CAS done in CMBitMap::parMark() call in the routine above. HeapWord* global_finger = _cm->finger(); -#if _CHECK_BOTH_FINGERS_ - // we will check both the local and global fingers - - if (_finger != NULL && objAddr < _finger) { - if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%u] below the local finger ("PTR_FORMAT"), " - "pushing it", _worker_id, p2i(_finger)); + // We only need to push a newly grey object on the mark + // stack if it is in a section of memory the mark bitmap + // scan has already examined. Mark bitmap scanning + // maintains progress "fingers" for determining that. + // + // Notice that the global finger might be moving forward + // concurrently. This is not a problem. In the worst case, we + // mark the object while it is above the global finger and, by + // the time we read the global finger, it has moved forward + // past this object. In this case, the object will probably + // be visited when a task is scanning the region and will also + // be pushed on the stack. So, some duplicate work, but no + // correctness problems. + if (is_below_finger(objAddr, global_finger)) { + if (obj->is_typeArray()) { + // Immediately process arrays of primitive types, rather + // than pushing on the mark stack. This keeps us from + // adding humongous objects to the mark stack that might + // be reclaimed before the entry is processed - see + // selection of candidates for eager reclaim of humongous + // objects. The cost of the additional type test is + // mitigated by avoiding a trip through the mark stack, + // by only doing a bookkeeping update and avoiding the + // actual scan of the object - a typeArray contains no + // references, and the metadata is built-in. + process_grey_object(obj); + } else { + if (_cm->verbose_high()) { + gclog_or_tty->print_cr("[%u] below a finger (local: " PTR_FORMAT + ", global: " PTR_FORMAT ") pushing " + PTR_FORMAT " on mark stack", + _worker_id, p2i(_finger), + p2i(global_finger), p2i(objAddr)); + } + push(obj); } - push(obj); - } else if (_curr_region != NULL && objAddr < _region_limit) { - // do nothing - } else if (objAddr < global_finger) { - // Notice that the global finger might be moving forward - // concurrently. This is not a problem. In the worst case, we - // mark the object while it is above the global finger and, by - // the time we read the global finger, it has moved forward - // passed this object. In this case, the object will probably - // be visited when a task is scanning the region and will also - // be pushed on the stack. So, some duplicate work, but no - // correctness problems. - - if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%u] below the global finger " - "("PTR_FORMAT"), pushing it", - _worker_id, p2i(global_finger)); - } - push(obj); - } else { - // do nothing } -#else // _CHECK_BOTH_FINGERS_ - // we will only check the global finger - - if (objAddr < global_finger) { - // see long comment above - - if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%u] below the global finger " - "("PTR_FORMAT"), pushing it", - _worker_id, p2i(global_finger)); - } - push(obj); - } -#endif // _CHECK_BOTH_FINGERS_ } } } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1Allocator.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1Allocator.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1Allocator.cpp Thu May 07 20:51:12 2015 -0700 @@ -110,15 +110,15 @@ _retained_old_gc_alloc_region = NULL; } -G1ParGCAllocBuffer::G1ParGCAllocBuffer(size_t gclab_word_size) : - ParGCAllocBuffer(gclab_word_size), _retired(true) { } +G1PLAB::G1PLAB(size_t gclab_word_size) : + PLAB(gclab_word_size), _retired(true) { } HeapWord* G1ParGCAllocator::allocate_direct_or_new_plab(InCSetState dest, size_t word_sz, AllocationContext_t context) { size_t gclab_word_size = _g1h->desired_plab_sz(dest); if (word_sz * 100 < gclab_word_size * ParallelGCBufferWastePct) { - G1ParGCAllocBuffer* alloc_buf = alloc_buffer(dest, context); + G1PLAB* alloc_buf = alloc_buffer(dest, context); add_to_alloc_buffer_waste(alloc_buf->words_remaining()); alloc_buf->retire(); @@ -151,7 +151,7 @@ void G1DefaultParGCAllocator::retire_alloc_buffers() { for (uint state = 0; state < InCSetState::Num; state++) { - G1ParGCAllocBuffer* const buf = _alloc_buffers[state]; + G1PLAB* const buf = _alloc_buffers[state]; if (buf != NULL) { add_to_alloc_buffer_waste(buf->words_remaining()); buf->flush_and_retire_stats(_g1h->alloc_buffer_stats(state)); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1Allocator.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1Allocator.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1Allocator.hpp Thu May 07 20:51:12 2015 -0700 @@ -28,7 +28,10 @@ #include "gc_implementation/g1/g1AllocationContext.hpp" #include "gc_implementation/g1/g1AllocRegion.hpp" #include "gc_implementation/g1/g1InCSetState.hpp" -#include "gc_implementation/shared/parGCAllocBuffer.hpp" +#include "gc_implementation/shared/plab.hpp" +#include "gc_interface/collectedHeap.hpp" + +class EvacuationInfo; // Base class for G1 allocators. class G1Allocator : public CHeapObj { @@ -144,18 +147,18 @@ } }; -class G1ParGCAllocBuffer: public ParGCAllocBuffer { +class G1PLAB: public PLAB { private: bool _retired; public: - G1ParGCAllocBuffer(size_t gclab_word_size); - virtual ~G1ParGCAllocBuffer() { + G1PLAB(size_t gclab_word_size); + virtual ~G1PLAB() { guarantee(_retired, "Allocation buffer has not been retired"); } virtual void set_buf(HeapWord* buf) { - ParGCAllocBuffer::set_buf(buf); + PLAB::set_buf(buf); _retired = false; } @@ -163,7 +166,12 @@ if (_retired) { return; } - ParGCAllocBuffer::retire(); + PLAB::retire(); + _retired = true; + } + + virtual void flush_and_retire_stats(PLABStats* stats) { + PLAB::flush_and_retire_stats(stats); _retired = true; } }; @@ -187,7 +195,7 @@ void add_to_undo_waste(size_t waste) { _undo_waste += waste; } virtual void retire_alloc_buffers() = 0; - virtual G1ParGCAllocBuffer* alloc_buffer(InCSetState dest, AllocationContext_t context) = 0; + virtual G1PLAB* alloc_buffer(InCSetState dest, AllocationContext_t context) = 0; // Calculate the survivor space object alignment in bytes. Returns that or 0 if // there are no restrictions on survivor alignment. @@ -208,6 +216,7 @@ _g1h(g1h), _survivor_alignment_bytes(calc_survivor_alignment_bytes()), _alloc_buffer_waste(0), _undo_waste(0) { } + virtual ~G1ParGCAllocator() { } static G1ParGCAllocator* create_allocator(G1CollectedHeap* g1h); @@ -226,7 +235,7 @@ HeapWord* plab_allocate(InCSetState dest, size_t word_sz, AllocationContext_t context) { - G1ParGCAllocBuffer* buffer = alloc_buffer(dest, context); + G1PLAB* buffer = alloc_buffer(dest, context); if (_survivor_alignment_bytes == 0) { return buffer->allocate(word_sz); } else { @@ -256,14 +265,14 @@ }; class G1DefaultParGCAllocator : public G1ParGCAllocator { - G1ParGCAllocBuffer _surviving_alloc_buffer; - G1ParGCAllocBuffer _tenured_alloc_buffer; - G1ParGCAllocBuffer* _alloc_buffers[InCSetState::Num]; + G1PLAB _surviving_alloc_buffer; + G1PLAB _tenured_alloc_buffer; + G1PLAB* _alloc_buffers[InCSetState::Num]; public: G1DefaultParGCAllocator(G1CollectedHeap* g1h); - virtual G1ParGCAllocBuffer* alloc_buffer(InCSetState dest, AllocationContext_t context) { + virtual G1PLAB* alloc_buffer(InCSetState dest, AllocationContext_t context) { assert(dest.is_valid(), err_msg("Allocation buffer index out-of-bounds: " CSETSTATE_FORMAT, dest.value())); assert(_alloc_buffers[dest.value()] != NULL, diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "gc_implementation/g1/g1CollectedHeap.hpp" #include "gc_implementation/g1/g1BlockOffsetTable.inline.hpp" #include "gc_implementation/g1/heapRegion.hpp" #include "memory/space.hpp" @@ -303,9 +304,9 @@ assert(blk_start <= threshold, "blk_start should be at or before threshold"); assert(pointer_delta(threshold, blk_start) <= N_words, "offset should be <= BlockOffsetSharedArray::N"); - assert(Universe::heap()->is_in_reserved(blk_start), + assert(G1CollectedHeap::heap()->is_in_reserved(blk_start), "reference must be into the heap"); - assert(Universe::heap()->is_in_reserved(blk_end-1), + assert(G1CollectedHeap::heap()->is_in_reserved(blk_end-1), "limit must be within the heap"); assert(threshold == _array->_reserved.start() + index*N_words, "index must agree with threshold"); @@ -458,7 +459,7 @@ } HeapWord* G1BlockOffsetArrayContigSpace::initialize_threshold_raw() { - assert(!Universe::heap()->is_in_reserved(_array->_offset_array), + assert(!G1CollectedHeap::heap()->is_in_reserved(_array->_offset_array), "just checking"); _next_offset_index = _array->index_for_raw(_bottom); _next_offset_index++; @@ -468,7 +469,7 @@ } void G1BlockOffsetArrayContigSpace::zero_bottom_entry_raw() { - assert(!Universe::heap()->is_in_reserved(_array->_offset_array), + assert(!G1CollectedHeap::heap()->is_in_reserved(_array->_offset_array), "just checking"); size_t bottom_index = _array->index_for_raw(_bottom); assert(_array->address_for_index_raw(bottom_index) == _bottom, @@ -477,7 +478,7 @@ } HeapWord* G1BlockOffsetArrayContigSpace::initialize_threshold() { - assert(!Universe::heap()->is_in_reserved(_array->_offset_array), + assert(!G1CollectedHeap::heap()->is_in_reserved(_array->_offset_array), "just checking"); _next_offset_index = _array->index_for(_bottom); _next_offset_index++; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ #include "gc_implementation/g1/g1RegionToSpaceMapper.hpp" #include "memory/memRegion.hpp" -#include "runtime/virtualspace.hpp" +#include "memory/virtualspace.hpp" #include "utilities/globalDefinitions.hpp" // The CollectedHeap type requires subtypes to implement a method diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1CardCounts.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CardCounts.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CardCounts.hpp Thu May 07 20:51:12 2015 -0700 @@ -27,7 +27,7 @@ #include "gc_implementation/g1/g1RegionToSpaceMapper.hpp" #include "memory/allocation.hpp" -#include "runtime/virtualspace.hpp" +#include "memory/virtualspace.hpp" #include "utilities/globalDefinitions.hpp" class CardTableModRefBS; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu May 07 20:51:12 2015 -0700 @@ -22,11 +22,6 @@ * */ -#if !defined(__clang_major__) && defined(__GNUC__) -// FIXME, formats have issues. Disable this macro definition, compile, and study warnings for more information. -#define ATTRIBUTE_PRINTF(x,y) -#endif - #include "precompiled.hpp" #include "classfile/metadataOnStackMark.hpp" #include "classfile/stringTable.hpp" @@ -70,6 +65,7 @@ #include "runtime/orderAccess.inline.hpp" #include "runtime/vmThread.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/stack.inline.hpp" size_t G1CollectedHeap::_humongous_object_threshold_in_words = 0; @@ -200,7 +196,7 @@ if (!curr->is_young()) { gclog_or_tty->print_cr("### YOUNG REGION "PTR_FORMAT"-"PTR_FORMAT" " "incorrectly tagged (y: %d, surv: %d)", - curr->bottom(), curr->end(), + p2i(curr->bottom()), p2i(curr->end()), curr->is_young(), curr->is_survivor()); ret = false; } @@ -329,8 +325,8 @@ while (curr != NULL) { gclog_or_tty->print_cr(" "HR_FORMAT", P: "PTR_FORMAT ", N: "PTR_FORMAT", age: %4d", HR_FORMAT_PARAMS(curr), - curr->prev_top_at_mark_start(), - curr->next_top_at_mark_start(), + p2i(curr->prev_top_at_mark_start()), + p2i(curr->next_top_at_mark_start()), curr->age_in_surv_rate_group_cond()); curr = curr->get_next_young_region(); } @@ -409,10 +405,6 @@ return !hr->is_humongous(); } -// Private class members. - -G1CollectedHeap* G1CollectedHeap::_g1h; - // Private methods. HeapRegion* @@ -1728,7 +1720,7 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : - SharedHeap(), + CollectedHeap(), _g1_policy(policy_), _dirty_card_queue_set(false), _into_cset_dirty_card_queue_set(false), @@ -1746,7 +1738,7 @@ _secondary_free_list("Secondary Free List", new SecondaryFreeRegionListMtSafeChecker()), _old_set("Old Set", false /* humongous */, new OldRegionSetMtSafeChecker()), _humongous_set("Master Humongous Set", true /* humongous */, new HumongousRegionSetMtSafeChecker()), - _humongous_is_live(), + _humongous_reclaim_candidates(), _has_humongous_reclaim_candidates(false), _free_regions_coming(false), _young_list(new YoungList(this)), @@ -1768,9 +1760,12 @@ _gc_tracer_stw(new (ResourceObj::C_HEAP, mtGC) G1NewTracer()), _gc_tracer_cm(new (ResourceObj::C_HEAP, mtGC) G1OldTracer()) { - _g1h = this; - - _allocator = G1Allocator::create_allocator(_g1h); + _workers = new FlexibleWorkGang("GC Thread", ParallelGCThreads, + /* are_GC_task_threads */true, + /* are_ConcurrentGC_threads */false); + _workers->initialize_workers(); + + _allocator = G1Allocator::create_allocator(this); _humongous_object_threshold_in_words = HeapRegion::GrainWords / 2; int n_queues = MAX2((int)ParallelGCThreads, 1); @@ -1797,6 +1792,26 @@ guarantee(_task_queues != NULL, "task_queues allocation failure."); } +G1RegionToSpaceMapper* G1CollectedHeap::create_aux_memory_mapper(const char* description, + size_t size, + size_t translation_factor) { + size_t preferred_page_size = os::page_size_for_region_unaligned(size, 1); + // Allocate a new reserved space, preferring to use large pages. + ReservedSpace rs(size, preferred_page_size); + G1RegionToSpaceMapper* result = + G1RegionToSpaceMapper::create_mapper(rs, + size, + rs.alignment(), + HeapRegion::GrainBytes, + translation_factor, + mtGC); + if (TracePageSizes) { + gclog_or_tty->print_cr("G1 '%s': pg_sz=" SIZE_FORMAT " base=" PTR_FORMAT " size=" SIZE_FORMAT " alignment=" SIZE_FORMAT " reqsize=" SIZE_FORMAT, + description, preferred_page_size, p2i(rs.base()), rs.size(), rs.alignment(), size); + } + return result; +} + jint G1CollectedHeap::initialize() { CollectedHeap::pre_initialize(); os::enable_vtime(); @@ -1864,57 +1879,35 @@ ReservedSpace g1_rs = heap_rs.first_part(max_byte_size); G1RegionToSpaceMapper* heap_storage = G1RegionToSpaceMapper::create_mapper(g1_rs, + g1_rs.size(), UseLargePages ? os::large_page_size() : os::vm_page_size(), HeapRegion::GrainBytes, 1, mtJavaHeap); heap_storage->set_mapping_changed_listener(&_listener); - // Reserve space for the block offset table. We do not support automatic uncommit - // for the card table at this time. BOT only. - ReservedSpace bot_rs(G1BlockOffsetSharedArray::compute_size(g1_rs.size() / HeapWordSize)); + // Create storage for the BOT, card table, card counts table (hot card cache) and the bitmaps. G1RegionToSpaceMapper* bot_storage = - G1RegionToSpaceMapper::create_mapper(bot_rs, - os::vm_page_size(), - HeapRegion::GrainBytes, - G1BlockOffsetSharedArray::N_bytes, - mtGC); + create_aux_memory_mapper("Block offset table", + G1BlockOffsetSharedArray::compute_size(g1_rs.size() / HeapWordSize), + G1BlockOffsetSharedArray::N_bytes); ReservedSpace cardtable_rs(G1SATBCardTableLoggingModRefBS::compute_size(g1_rs.size() / HeapWordSize)); G1RegionToSpaceMapper* cardtable_storage = - G1RegionToSpaceMapper::create_mapper(cardtable_rs, - os::vm_page_size(), - HeapRegion::GrainBytes, - G1BlockOffsetSharedArray::N_bytes, - mtGC); - - // Reserve space for the card counts table. - ReservedSpace card_counts_rs(G1BlockOffsetSharedArray::compute_size(g1_rs.size() / HeapWordSize)); + create_aux_memory_mapper("Card table", + G1SATBCardTableLoggingModRefBS::compute_size(g1_rs.size() / HeapWordSize), + G1BlockOffsetSharedArray::N_bytes); + G1RegionToSpaceMapper* card_counts_storage = - G1RegionToSpaceMapper::create_mapper(card_counts_rs, - os::vm_page_size(), - HeapRegion::GrainBytes, - G1BlockOffsetSharedArray::N_bytes, - mtGC); - - // Reserve space for prev and next bitmap. + create_aux_memory_mapper("Card counts table", + G1BlockOffsetSharedArray::compute_size(g1_rs.size() / HeapWordSize), + G1BlockOffsetSharedArray::N_bytes); + size_t bitmap_size = CMBitMap::compute_size(g1_rs.size()); - - ReservedSpace prev_bitmap_rs(ReservedSpace::allocation_align_size_up(bitmap_size)); G1RegionToSpaceMapper* prev_bitmap_storage = - G1RegionToSpaceMapper::create_mapper(prev_bitmap_rs, - os::vm_page_size(), - HeapRegion::GrainBytes, - CMBitMap::mark_distance(), - mtGC); - - ReservedSpace next_bitmap_rs(ReservedSpace::allocation_align_size_up(bitmap_size)); + create_aux_memory_mapper("Prev Bitmap", bitmap_size, CMBitMap::mark_distance()); G1RegionToSpaceMapper* next_bitmap_storage = - G1RegionToSpaceMapper::create_mapper(next_bitmap_rs, - os::vm_page_size(), - HeapRegion::GrainBytes, - CMBitMap::mark_distance(), - mtGC); + create_aux_memory_mapper("Next Bitmap", bitmap_size, CMBitMap::mark_distance()); _hrm.initialize(heap_storage, prev_bitmap_storage, next_bitmap_storage, bot_storage, cardtable_storage, card_counts_storage); g1_barrier_set()->initialize(cardtable_storage); @@ -1935,10 +1928,14 @@ _bot_shared = new G1BlockOffsetSharedArray(reserved_region(), bot_storage); - _g1h = this; - - _in_cset_fast_test.initialize(_hrm.reserved().start(), _hrm.reserved().end(), HeapRegion::GrainBytes); - _humongous_is_live.initialize(_hrm.reserved().start(), _hrm.reserved().end(), HeapRegion::GrainBytes); + { + HeapWord* start = _hrm.reserved().start(); + HeapWord* end = _hrm.reserved().end(); + size_t granularity = HeapRegion::GrainBytes; + + _in_cset_fast_test.initialize(start, end, granularity); + _humongous_reclaim_candidates.initialize(start, end, granularity); + } // Create the ConcurrentMark data structure and thread. // (Must do this late, so that "max_regions" is defined.) @@ -2026,15 +2023,15 @@ } } -void G1CollectedHeap::clear_humongous_is_live_table() { - guarantee(G1EagerReclaimHumongousObjects, "Should only be called if true"); - _humongous_is_live.clear(); -} - size_t G1CollectedHeap::conservative_max_heap_alignment() { return HeapRegion::max_region_size(); } +void G1CollectedHeap::post_initialize() { + CollectedHeap::post_initialize(); + ref_processing_init(); +} + void G1CollectedHeap::ref_processing_init() { // Reference processing in G1 currently works as follows: // @@ -2071,7 +2068,6 @@ // * Discovery is atomic - i.e. not concurrent. // * Reference discovery will not need a barrier. - SharedHeap::ref_processing_init(); MemRegion mr = reserved_region(); // Concurrent Mark ref processor @@ -2128,6 +2124,7 @@ } #ifndef PRODUCT + class CheckGCTimeStampsHRClosure : public HeapRegionClosure { private: unsigned _gc_time_stamp; @@ -2462,11 +2459,6 @@ } }; -void G1CollectedHeap::oop_iterate(ExtendedOopClosure* cl) { - IterateOopClosureRegionClosure blk(cl); - heap_region_iterate(&blk); -} - // Iterates an ObjectClosure over all objects within a HeapRegion. class IterateObjectClosureRegionClosure: public HeapRegionClosure { @@ -2486,23 +2478,6 @@ heap_region_iterate(&blk); } -// Calls a SpaceClosure on a HeapRegion. - -class SpaceClosureRegionClosure: public HeapRegionClosure { - SpaceClosure* _cl; -public: - SpaceClosureRegionClosure(SpaceClosure* cl) : _cl(cl) {} - bool doHeapRegion(HeapRegion* r) { - _cl->do_space(r); - return false; - } -}; - -void G1CollectedHeap::space_iterate(SpaceClosure* cl) { - SpaceClosureRegionClosure blk(cl); - heap_region_iterate(&blk); -} - void G1CollectedHeap::heap_region_iterate(HeapRegionClosure* cl) const { _hrm.iterate(cl); } @@ -2639,23 +2614,19 @@ return result; } -Space* G1CollectedHeap::space_containing(const void* addr) const { - return heap_region_containing(addr); -} - HeapWord* G1CollectedHeap::block_start(const void* addr) const { - Space* sp = space_containing(addr); - return sp->block_start(addr); + HeapRegion* hr = heap_region_containing(addr); + return hr->block_start(addr); } size_t G1CollectedHeap::block_size(const HeapWord* addr) const { - Space* sp = space_containing(addr); - return sp->block_size(addr); + HeapRegion* hr = heap_region_containing(addr); + return hr->block_size(addr); } bool G1CollectedHeap::block_is_obj(const HeapWord* addr) const { - Space* sp = space_containing(addr); - return sp->block_is_obj(addr); + HeapRegion* hr = heap_region_containing(addr); + return hr->block_is_obj(addr); } bool G1CollectedHeap::supports_tlab_allocation() const { @@ -2776,9 +2747,9 @@ oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); if (_g1h->is_obj_dead_cond(obj, _vo)) { gclog_or_tty->print_cr("Root location "PTR_FORMAT" " - "points to dead obj "PTR_FORMAT, p, (void*) obj); + "points to dead obj "PTR_FORMAT, p2i(p), p2i(obj)); if (_vo == VerifyOption_G1UseMarkWord) { - gclog_or_tty->print_cr(" Mark word: "PTR_FORMAT, (void*)(obj->mark())); + gclog_or_tty->print_cr(" Mark word: "INTPTR_FORMAT, (intptr_t)obj->mark()); } obj->print_on(gclog_or_tty); _failures = true; @@ -2826,9 +2797,9 @@ // contains the nmethod if (!hrrs->strong_code_roots_list_contains(_nm)) { gclog_or_tty->print_cr("Code root location "PTR_FORMAT" " - "from nmethod "PTR_FORMAT" not in strong " - "code roots for region ["PTR_FORMAT","PTR_FORMAT")", - p, _nm, hr->bottom(), hr->end()); + "from nmethod "PTR_FORMAT" not in strong " + "code roots for region ["PTR_FORMAT","PTR_FORMAT")", + p2i(p), p2i(_nm), p2i(hr->bottom()), p2i(hr->end())); _failures = true; } } @@ -2884,7 +2855,7 @@ _young_ref_counter_closure.reset_count(); k->oops_do(&_young_ref_counter_closure); if (_young_ref_counter_closure.count() > 0) { - guarantee(k->has_modified_oops(), err_msg("Klass " PTR_FORMAT ", has young refs but is not dirty.", k)); + guarantee(k->has_modified_oops(), err_msg("Klass " PTR_FORMAT ", has young refs but is not dirty.", p2i(k))); } } }; @@ -2945,35 +2916,6 @@ size_t live_bytes() { return _live_bytes; } }; -class PrintObjsInRegionClosure : public ObjectClosure { - HeapRegion *_hr; - G1CollectedHeap *_g1; -public: - PrintObjsInRegionClosure(HeapRegion *hr) : _hr(hr) { - _g1 = G1CollectedHeap::heap(); - }; - - void do_object(oop o) { - if (o != NULL) { - HeapWord *start = (HeapWord *) o; - size_t word_sz = o->size(); - gclog_or_tty->print("\nPrinting obj "PTR_FORMAT" of size " SIZE_FORMAT - " isMarkedPrev %d isMarkedNext %d isAllocSince %d\n", - (void*) o, word_sz, - _g1->isMarkedPrev(o), - _g1->isMarkedNext(o), - _hr->obj_allocated_since_prev_marking(o)); - HeapWord *end = start + word_sz; - HeapWord *cur; - int *val; - for (cur = start; cur < end; cur++) { - val = (int *) cur; - gclog_or_tty->print("\t "PTR_FORMAT":%d\n", val, *val); - } - } - } -}; - class VerifyRegionClosure: public HeapRegionClosure { private: bool _par; @@ -3006,7 +2948,7 @@ gclog_or_tty->print_cr("["PTR_FORMAT","PTR_FORMAT"] " "max_live_bytes "SIZE_FORMAT" " "< calculated "SIZE_FORMAT, - r->bottom(), r->end(), + p2i(r->bottom()), p2i(r->end()), r->max_live_bytes(), not_dead_yet_cl.live_bytes()); _failures = true; @@ -3125,12 +3067,6 @@ // print_extended_on() instead of print_on(). print_extended_on(gclog_or_tty); gclog_or_tty->cr(); -#ifndef PRODUCT - if (VerifyDuringGC && G1VerifyDuringGCPrintReachable) { - concurrent_mark()->print_reachable("at-verification-failure", - vo, false /* all */); - } -#endif gclog_or_tty->flush(); } guarantee(!failures, "there should not have been any failures"); @@ -3210,10 +3146,10 @@ st->print(" %-20s", "garbage-first heap"); st->print(" total " SIZE_FORMAT "K, used " SIZE_FORMAT "K", capacity()/K, used_unlocked()/K); - st->print(" [" INTPTR_FORMAT ", " INTPTR_FORMAT ", " INTPTR_FORMAT ")", - _hrm.reserved().start(), - _hrm.reserved().start() + _hrm.length() + HeapRegion::GrainWords, - _hrm.reserved().end()); + st->print(" [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT ")", + p2i(_hrm.reserved().start()), + p2i(_hrm.reserved().start() + _hrm.length() + HeapRegion::GrainWords), + p2i(_hrm.reserved().end())); st->cr(); st->print(" region size " SIZE_FORMAT "K, ", HeapRegion::GrainBytes / K); uint young_regions = _young_list->length(); @@ -3336,9 +3272,10 @@ #endif // PRODUCT G1CollectedHeap* G1CollectedHeap::heap() { - assert(_sh->kind() == CollectedHeap::G1CollectedHeap, - "not a garbage-first heap"); - return _g1h; + CollectedHeap* heap = Universe::heap(); + assert(heap != NULL, "Uninitialized access to G1CollectedHeap::heap()"); + assert(heap->kind() == CollectedHeap::G1CollectedHeap, "Not a G1CollectedHeap"); + return (G1CollectedHeap*)heap; } void G1CollectedHeap::gc_prologue(bool full /* Ignored */) { @@ -3434,12 +3371,6 @@ return g1_rem_set()->cardsScanned(); } -bool G1CollectedHeap::humongous_region_is_always_live(uint index) { - HeapRegion* region = region_at(index); - assert(region->is_starts_humongous(), "Must start a humongous object"); - return oop(region->bottom())->is_objArray() || !region->rem_set()->is_empty(); -} - class RegisterHumongousWithInCSetFastTestClosure : public HeapRegionClosure { private: size_t _total_humongous; @@ -3447,14 +3378,59 @@ DirtyCardQueue _dcq; - bool humongous_region_is_candidate(uint index) { - HeapRegion* region = G1CollectedHeap::heap()->region_at(index); - assert(region->is_starts_humongous(), "Must start a humongous object"); + // We don't nominate objects with many remembered set entries, on + // the assumption that such objects are likely still live. + bool is_remset_small(HeapRegion* region) const { HeapRegionRemSet* const rset = region->rem_set(); - bool const allow_stale_refs = G1EagerReclaimHumongousObjectsWithStaleRefs; - return !oop(region->bottom())->is_objArray() && - ((allow_stale_refs && rset->occupancy_less_or_equal_than(G1RSetSparseRegionEntries)) || - (!allow_stale_refs && rset->is_empty())); + return G1EagerReclaimHumongousObjectsWithStaleRefs + ? rset->occupancy_less_or_equal_than(G1RSetSparseRegionEntries) + : rset->is_empty(); + } + + bool is_typeArray_region(HeapRegion* region) const { + return oop(region->bottom())->is_typeArray(); + } + + bool humongous_region_is_candidate(G1CollectedHeap* heap, HeapRegion* region) const { + assert(region->is_starts_humongous(), "Must start a humongous object"); + + // Candidate selection must satisfy the following constraints + // while concurrent marking is in progress: + // + // * In order to maintain SATB invariants, an object must not be + // reclaimed if it was allocated before the start of marking and + // has not had its references scanned. Such an object must have + // its references (including type metadata) scanned to ensure no + // live objects are missed by the marking process. Objects + // allocated after the start of concurrent marking don't need to + // be scanned. + // + // * An object must not be reclaimed if it is on the concurrent + // mark stack. Objects allocated after the start of concurrent + // marking are never pushed on the mark stack. + // + // Nominating only objects allocated after the start of concurrent + // marking is sufficient to meet both constraints. This may miss + // some objects that satisfy the constraints, but the marking data + // structures don't support efficiently performing the needed + // additional tests or scrubbing of the mark stack. + // + // However, we presently only nominate is_typeArray() objects. + // A humongous object containing references induces remembered + // set entries on other regions. In order to reclaim such an + // object, those remembered sets would need to be cleaned up. + // + // We also treat is_typeArray() objects specially, allowing them + // to be reclaimed even if allocated before the start of + // concurrent mark. For this we rely on mark stack insertion to + // exclude is_typeArray() objects, preventing reclaiming an object + // that is in the mark stack. We also rely on the metadata for + // such objects to be built-in and so ensured to be kept live. + // Frequent allocation and drop of large binary blobs is an + // important use case for eager reclaim, and this special handling + // may reduce needed headroom. + + return is_typeArray_region(region) && is_remset_small(region); } public: @@ -3470,14 +3446,17 @@ } G1CollectedHeap* g1h = G1CollectedHeap::heap(); - uint region_idx = r->hrm_index(); - bool is_candidate = humongous_region_is_candidate(region_idx); - // Is_candidate already filters out humongous object with large remembered sets. - // If we have a humongous object with a few remembered sets, we simply flush these - // remembered set entries into the DCQS. That will result in automatic - // re-evaluation of their remembered set entries during the following evacuation - // phase. + bool is_candidate = humongous_region_is_candidate(g1h, r); + uint rindex = r->hrm_index(); + g1h->set_humongous_reclaim_candidate(rindex, is_candidate); if (is_candidate) { + _candidate_humongous++; + g1h->register_humongous_region_with_cset(rindex); + // Is_candidate already filters out humongous object with large remembered sets. + // If we have a humongous object with a few remembered sets, we simply flush these + // remembered set entries into the DCQS. That will result in automatic + // re-evaluation of their remembered set entries during the following evacuation + // phase. if (!r->rem_set()->is_empty()) { guarantee(r->rem_set()->occupancy_less_or_equal_than(G1RSetSparseRegionEntries), "Found a not-small remembered set here. This is inconsistent with previous assumptions."); @@ -3499,8 +3478,6 @@ r->rem_set()->clear_locked(); } assert(r->rem_set()->is_empty(), "At this point any humongous candidate remembered set must be empty."); - g1h->register_humongous_region_with_cset(region_idx); - _candidate_humongous++; } _total_humongous++; @@ -3520,6 +3497,7 @@ } double time = os::elapsed_counter(); + // Collect reclaim candidate information and register candidates with cset. RegisterHumongousWithInCSetFastTestClosure cl; heap_region_iterate(&cl); @@ -3529,10 +3507,6 @@ cl.candidate_humongous()); _has_humongous_reclaim_candidates = cl.candidate_humongous() > 0; - if (_has_humongous_reclaim_candidates || G1TraceEagerReclaimHumongousObjects) { - clear_humongous_is_live_table(); - } - // Finally flush all remembered set entries to re-check into the global DCQS. cl.flush_rem_set_entries(); } @@ -3832,14 +3806,9 @@ assert(check_cset_fast_test(), "Inconsistency in the InCSetState table."); _cm->note_start_of_gc(); - // We should not verify the per-thread SATB buffers given that - // we have not filtered them yet (we'll do so during the - // GC). We also call this after finalize_cset() to + // We call this after finalize_cset() to // ensure that the CSet has been finalized. - _cm->verify_no_cset_oops(true /* verify_stacks */, - true /* verify_enqueued_buffers */, - false /* verify_thread_buffers */, - true /* verify_fingers */); + _cm->verify_no_cset_oops(); if (_hr_printer.is_active()) { HeapRegion* hr = g1_policy()->collection_set(); @@ -3862,16 +3831,6 @@ // Actually do the work... evacuate_collection_set(evacuation_info); - // We do this to mainly verify the per-thread SATB buffers - // (which have been filtered by now) since we didn't verify - // them earlier. No point in re-checking the stacks / enqueued - // buffers given that the CSet has not changed since last time - // we checked. - _cm->verify_no_cset_oops(false /* verify_stacks */, - false /* verify_enqueued_buffers */, - true /* verify_thread_buffers */, - true /* verify_fingers */); - free_collection_set(g1_policy()->collection_set(), evacuation_info); eagerly_reclaim_humongous_regions(); @@ -3954,10 +3913,7 @@ // We redo the verification but now wrt to the new CSet which // has just got initialized after the previous CSet was freed. - _cm->verify_no_cset_oops(true /* verify_stacks */, - true /* verify_enqueued_buffers */, - true /* verify_thread_buffers */, - true /* verify_fingers */); + _cm->verify_no_cset_oops(); _cm->note_end_of_gc(); // This timing is only used by the ergonomics to handle our pause target. @@ -4116,7 +4072,7 @@ oop old) { assert(obj_in_cs(old), err_msg("obj: "PTR_FORMAT" should still be in the CSet", - (HeapWord*) old)); + p2i(old))); markOop m = old->mark(); oop forward_ptr = old->forward_to_atomic(old); if (forward_ptr == NULL) { @@ -4151,7 +4107,7 @@ assert(old == forward_ptr || !obj_in_cs(forward_ptr), err_msg("obj: "PTR_FORMAT" forwarded to: "PTR_FORMAT" " "should not be in the CSet", - (HeapWord*) old, (HeapWord*) forward_ptr)); + p2i(old), p2i(forward_ptr))); return forward_ptr; } } @@ -4856,7 +4812,7 @@ void G1CollectedHeap::unlink_string_and_symbol_table(BoolObjectClosure* is_alive, bool process_strings, bool process_symbols) { { - uint n_workers = _g1h->workers()->active_workers(); + uint n_workers = workers()->active_workers(); G1StringSymbolTableUnlinkTask g1_unlink_task(is_alive, process_strings, process_symbols); set_par_threads(n_workers); workers()->run_task(&g1_unlink_task); @@ -4888,7 +4844,7 @@ void G1CollectedHeap::redirty_logged_cards() { double redirty_logged_cards_start = os::elapsedTime(); - uint n_workers = _g1h->workers()->active_workers(); + uint n_workers = workers()->active_workers(); G1RedirtyLoggedCardsTask redirty_task(&dirty_card_queue_set()); dirty_card_queue_set().reset_for_par_iteration(); @@ -5001,8 +4957,7 @@ _par_scan_state->push_on_queue(p); } else { assert(!Metaspace::contains((const void*)p), - err_msg("Unexpectedly found a pointer from metadata: " - PTR_FORMAT, p)); + err_msg("Unexpectedly found a pointer from metadata: " PTR_FORMAT, p2i(p))); _copy_non_heap_obj_cl->do_oop(p); } } @@ -5321,7 +5276,7 @@ OopClosure* copy_non_heap_cl = &only_copy_non_heap_cl; - if (_g1h->g1_policy()->during_initial_mark_pause()) { + if (g1_policy()->during_initial_mark_pause()) { // We also need to mark copied objects. copy_non_heap_cl = ©_mark_non_heap_cl; } @@ -5667,14 +5622,14 @@ bool G1CollectedHeap::verify_no_bits_over_tams(const char* bitmap_name, CMBitMapRO* bitmap, HeapWord* tams, HeapWord* end) { guarantee(tams <= end, - err_msg("tams: "PTR_FORMAT" end: "PTR_FORMAT, tams, end)); + err_msg("tams: "PTR_FORMAT" end: "PTR_FORMAT, p2i(tams), p2i(end))); HeapWord* result = bitmap->getNextMarkedWordAddress(tams, end); if (result < end) { gclog_or_tty->cr(); gclog_or_tty->print_cr("## wrong marked address on %s bitmap: "PTR_FORMAT, - bitmap_name, result); + bitmap_name, p2i(result)); gclog_or_tty->print_cr("## %s tams: "PTR_FORMAT" end: "PTR_FORMAT, - bitmap_name, tams, end); + bitmap_name, p2i(tams), p2i(end)); return false; } return true; @@ -5994,41 +5949,42 @@ // required because stale remembered sets might reference locations that // are currently allocated into. uint region_idx = r->hrm_index(); - if (g1h->humongous_is_live(region_idx) || - g1h->humongous_region_is_always_live(region_idx)) { + if (!g1h->is_humongous_reclaim_candidate(region_idx) || + !r->rem_set()->is_empty()) { if (G1TraceEagerReclaimHumongousObjects) { - gclog_or_tty->print_cr("Live humongous region %u size "SIZE_FORMAT" start "PTR_FORMAT" length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d", + gclog_or_tty->print_cr("Live humongous region %u size "SIZE_FORMAT" start "PTR_FORMAT" length %u with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d reclaim candidate %d type array %d", region_idx, - obj->size()*HeapWordSize, - r->bottom(), + (size_t)obj->size() * HeapWordSize, + p2i(r->bottom()), r->region_num(), r->rem_set()->occupied(), r->rem_set()->strong_code_roots_list_length(), next_bitmap->isMarked(r->bottom()), - g1h->humongous_is_live(region_idx), - obj->is_objArray() + g1h->is_humongous_reclaim_candidate(region_idx), + obj->is_typeArray() ); } return false; } - guarantee(!obj->is_objArray(), - err_msg("Eagerly reclaiming object arrays is not supported, but the object "PTR_FORMAT" is.", - r->bottom())); + guarantee(obj->is_typeArray(), + err_msg("Only eagerly reclaiming type arrays is supported, but the object " + PTR_FORMAT " is not.", + p2i(r->bottom()))); if (G1TraceEagerReclaimHumongousObjects) { - gclog_or_tty->print_cr("Dead humongous region %u size "SIZE_FORMAT" start "PTR_FORMAT" length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d", + gclog_or_tty->print_cr("Dead humongous region %u size "SIZE_FORMAT" start "PTR_FORMAT" length %u with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d reclaim candidate %d type array %d", region_idx, - obj->size()*HeapWordSize, - r->bottom(), + (size_t)obj->size() * HeapWordSize, + p2i(r->bottom()), r->region_num(), r->rem_set()->occupied(), r->rem_set()->strong_code_roots_list_length(), next_bitmap->isMarked(r->bottom()), - g1h->humongous_is_live(region_idx), - obj->is_objArray() + g1h->is_humongous_reclaim_candidate(region_idx), + obj->is_typeArray() ); } // Need to clear mark bit of the humongous object if already set. @@ -6075,12 +6031,12 @@ HeapRegionSetCount empty_set; remove_from_old_sets(empty_set, cl.humongous_free_count()); - G1HRPrinter* hr_printer = _g1h->hr_printer(); - if (hr_printer->is_active()) { + G1HRPrinter* hrp = hr_printer(); + if (hrp->is_active()) { FreeRegionListIterator iter(&local_cleanup_list); while (iter.more_available()) { HeapRegion* hr = iter.get_next(); - hr_printer->cleanup(hr); + hrp->cleanup(hr); } } @@ -6163,8 +6119,6 @@ } void G1CollectedHeap::set_region_short_lived_locked(HeapRegion* hr) { - assert(heap_lock_held_for_gc(), - "the heap lock should already be held by or for this thread"); _young_list->push_region(hr); } @@ -6176,7 +6130,7 @@ bool doHeapRegion(HeapRegion* r) { if (r->is_young()) { gclog_or_tty->print_cr("Region ["PTR_FORMAT", "PTR_FORMAT") tagged as young", - r->bottom(), r->end()); + p2i(r->bottom()), p2i(r->end())); _success = false; } return false; @@ -6526,7 +6480,7 @@ assert(!hr->is_continues_humongous(), err_msg("trying to add code root "PTR_FORMAT" in continuation of humongous region "HR_FORMAT " starting at "HR_FORMAT, - _nm, HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region()))); + p2i(_nm), HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region()))); // HeapRegion::add_strong_code_root_locked() avoids adding duplicate entries. hr->add_strong_code_root_locked(_nm); @@ -6553,7 +6507,7 @@ assert(!hr->is_continues_humongous(), err_msg("trying to remove code root "PTR_FORMAT" in continuation of humongous region "HR_FORMAT " starting at "HR_FORMAT, - _nm, HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region()))); + p2i(_nm), HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region()))); hr->remove_strong_code_root(_nm); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu May 07 20:51:12 2015 -0700 @@ -39,10 +39,9 @@ #include "gc_implementation/g1/heapRegionManager.hpp" #include "gc_implementation/g1/heapRegionSet.hpp" #include "gc_implementation/shared/hSpaceCounters.hpp" -#include "gc_implementation/shared/parGCAllocBuffer.hpp" +#include "gc_interface/collectedHeap.hpp" #include "memory/barrierSet.hpp" #include "memory/memRegion.hpp" -#include "memory/sharedHeap.hpp" #include "utilities/stack.hpp" // A "G1CollectedHeap" is an implementation of a java heap for HotSpot. @@ -76,6 +75,7 @@ class EvacuationFailedInfo; class nmethod; class Ticks; +class FlexibleWorkGang; typedef OverflowTaskQueue RefToScanQueue; typedef GenericTaskQueueSet RefToScanQueueSet; @@ -177,7 +177,7 @@ virtual void on_commit(uint start_idx, size_t num_regions, bool zero_filled); }; -class G1CollectedHeap : public SharedHeap { +class G1CollectedHeap : public CollectedHeap { friend class VM_CollectForMetadataAllocation; friend class VM_G1CollectForAllocation; friend class VM_G1CollectFull; @@ -201,8 +201,7 @@ friend class G1CheckCSetFastTableClosure; private: - // The one and only G1CollectedHeap, so static functions can find it. - static G1CollectedHeap* _g1h; + FlexibleWorkGang* _workers; static size_t _humongous_object_threshold_in_words; @@ -217,7 +216,6 @@ // It keeps track of the humongous regions. HeapRegionSet _humongous_set; - void clear_humongous_is_live_table(); void eagerly_reclaim_humongous_regions(); // The number of regions we could create by expansion. @@ -287,22 +285,26 @@ // Helper for monitoring and management support. G1MonitoringSupport* _g1mm; - // Records whether the region at the given index is kept live by roots or - // references from the young generation. - class HumongousIsLiveBiasedMappedArray : public G1BiasedMappedArray { + // Records whether the region at the given index is (still) a + // candidate for eager reclaim. Only valid for humongous start + // regions; other regions have unspecified values. Humongous start + // regions are initialized at start of collection pause, with + // candidates removed from the set as they are found reachable from + // roots or the young generation. + class HumongousReclaimCandidates : public G1BiasedMappedArray { protected: bool default_value() const { return false; } public: void clear() { G1BiasedMappedArray::clear(); } - void set_live(uint region) { - set_by_index(region, true); + void set_candidate(uint region, bool value) { + set_by_index(region, value); } - bool is_live(uint region) { + bool is_candidate(uint region) { return get_by_index(region); } }; - HumongousIsLiveBiasedMappedArray _humongous_is_live; + HumongousReclaimCandidates _humongous_reclaim_candidates; // Stores whether during humongous object registration we found candidate regions. // If not, we can skip a few steps. bool _has_humongous_reclaim_candidates; @@ -351,6 +353,12 @@ // heap after a compaction. void print_hrm_post_compaction(); + // Create a memory mapper for auxiliary data structures of the given size and + // translation factor. + static G1RegionToSpaceMapper* create_aux_memory_mapper(const char* description, + size_t size, + size_t translation_factor); + double verify(bool guard, const char* msg); void verify_before_gc(); void verify_after_gc(); @@ -605,6 +613,7 @@ void enqueue_discovered_references(uint no_of_gc_workers); public: + FlexibleWorkGang* workers() const { return _workers; } G1Allocator* allocator() { return _allocator; @@ -630,21 +639,18 @@ inline AllocationContextStats& allocation_context_stats(); // Do anything common to GC's. - virtual void gc_prologue(bool full); - virtual void gc_epilogue(bool full); + void gc_prologue(bool full); + void gc_epilogue(bool full); + // Modify the reclaim candidate set and test for presence. + // These are only valid for starts_humongous regions. + inline void set_humongous_reclaim_candidate(uint region, bool value); + inline bool is_humongous_reclaim_candidate(uint region); + + // Remove from the reclaim candidate set. Also remove from the + // collection set so that later encounters avoid the slow path. inline void set_humongous_is_live(oop obj); - bool humongous_is_live(uint region) { - return _humongous_is_live.is_live(region); - } - - // Returns whether the given region (which must be a humongous (start) region) - // is to be considered conservatively live regardless of any other conditions. - bool humongous_region_is_always_live(uint index); - // Returns whether the given region (which must be a humongous (start) region) - // is considered a candidate for eager reclamation. - bool humongous_region_is_candidate(uint index); // Register the given region to be part of the collection set. inline void register_humongous_region_with_cset(uint index); // Register regions with humongous objects (actually on the start region) in @@ -1000,11 +1006,14 @@ // Return the (conservative) maximum heap alignment for any G1 heap static size_t conservative_max_heap_alignment(); + // Does operations required after initialization has been done. + void post_initialize(); + // Initialize weak reference processing. - virtual void ref_processing_init(); + void ref_processing_init(); // Explicitly import set_par_threads into this scope - using SharedHeap::set_par_threads; + using CollectedHeap::set_par_threads; // Set _n_par_threads according to a policy TBD. void set_par_threads(); @@ -1251,10 +1260,6 @@ // Iteration functions. - // Iterate over all the ref-containing fields of all objects, calling - // "cl.do_oop" on each. - virtual void oop_iterate(ExtendedOopClosure* cl); - // Iterate over all objects, calling "cl.do_object" on each. virtual void object_iterate(ObjectClosure* cl); @@ -1262,9 +1267,6 @@ object_iterate(cl); } - // Iterate over all spaces in use in the heap, in ascending address order. - virtual void space_iterate(SpaceClosure* cl); - // Iterate over heap regions, in address order, terminating the // iteration early if the "doHeapRegion" method returns "true". void heap_region_iterate(HeapRegionClosure* blk) const; @@ -1307,10 +1309,6 @@ HeapRegion* next_compaction_region(const HeapRegion* from) const; - // A CollectedHeap will contain some number of spaces. This finds the - // space containing a given address, or else returns NULL. - virtual Space* space_containing(const void* addr) const; - // Returns the HeapRegion that contains addr. addr must not be NULL. template inline HeapRegion* heap_region_containing_raw(const T addr) const; @@ -1344,9 +1342,6 @@ // the block is an object. virtual bool block_is_obj(const HeapWord* addr) const; - // Does this heap support heap inspection? (+PrintClassHistogram) - virtual bool supports_heap_inspection() const { return true; } - // Section on thread-local allocation buffers (TLABs) // See CollectedHeap for semantics. diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -352,20 +352,30 @@ return is_obj_ill(obj, heap_region_containing(obj)); } +inline void G1CollectedHeap::set_humongous_reclaim_candidate(uint region, bool value) { + assert(_hrm.at(region)->is_starts_humongous(), "Must start a humongous object"); + _humongous_reclaim_candidates.set_candidate(region, value); +} + +inline bool G1CollectedHeap::is_humongous_reclaim_candidate(uint region) { + assert(_hrm.at(region)->is_starts_humongous(), "Must start a humongous object"); + return _humongous_reclaim_candidates.is_candidate(region); +} + inline void G1CollectedHeap::set_humongous_is_live(oop obj) { uint region = addr_to_region((HeapWord*)obj); - // We not only set the "live" flag in the humongous_is_live table, but also + // Clear the flag in the humongous_reclaim_candidates table. Also // reset the entry in the _in_cset_fast_test table so that subsequent references // to the same humongous object do not go into the slow path again. // This is racy, as multiple threads may at the same time enter here, but this // is benign. - // During collection we only ever set the "live" flag, and only ever clear the + // During collection we only ever clear the "candidate" flag, and only ever clear the // entry in the in_cset_fast_table. // We only ever evaluate the contents of these tables (in the VM thread) after // having synchronized the worker threads with the VM thread, or in the same // thread (i.e. within the VM thread). - if (!_humongous_is_live.is_live(region)) { - _humongous_is_live.set_live(region); + if (is_humongous_reclaim_candidate(region)) { + set_humongous_reclaim_candidate(region, false); _in_cset_fast_test.clear_humongous(region); } } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Thu May 07 20:51:12 2015 -0700 @@ -22,11 +22,6 @@ * */ -#ifndef __clang_major__ -// FIXME, formats have issues. Disable this macro definition, compile, and study warnings for more information. -#define ATTRIBUTE_PRINTF(x,y) -#endif - #include "precompiled.hpp" #include "gc_implementation/g1/concurrentG1Refine.hpp" #include "gc_implementation/g1/concurrentMark.hpp" @@ -302,7 +297,7 @@ if (reserve_perc > 50) { reserve_perc = 50; warning("G1ReservePercent is set to a value that is too large, " - "it's been updated to %u", reserve_perc); + "it's been updated to " UINTX_FORMAT, reserve_perc); } _reserve_factor = (double) reserve_perc / 100.0; // This will be set when the heap is expanded @@ -1460,7 +1455,7 @@ _max_survivor_regions = (uint) ceil(max_survivor_regions_d); _tenuring_threshold = _survivors_age_table.compute_tenuring_threshold( - HeapRegion::GrainWords * _max_survivor_regions); + HeapRegion::GrainWords * _max_survivor_regions, counters()); } bool G1CollectorPolicy::force_initial_mark_if_outside_cycle( @@ -1800,7 +1795,7 @@ assert(csr->in_collection_set(), "bad CS"); st->print_cr(" "HR_FORMAT", P: "PTR_FORMAT "N: "PTR_FORMAT", age: %4d", HR_FORMAT_PARAMS(csr), - csr->prev_top_at_mark_start(), csr->next_top_at_mark_start(), + p2i(csr->prev_top_at_mark_start()), p2i(csr->next_top_at_mark_start()), csr->age_in_surv_rate_group_cond()); csr = next; } @@ -2166,7 +2161,7 @@ void TraceYoungGenTimeData::print_summary_sd(const char* str, const NumberSeq* seq) const { print_summary(str, seq); - gclog_or_tty->print_cr("%+45s = %5d, std dev = %8.2lf ms, max = %8.2lf ms)", + gclog_or_tty->print_cr("%45s = %5d, std dev = %8.2lf ms, max = %8.2lf ms)", "(num", seq->num(), seq->sd(), seq->maximum()); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1ErgoVerbose.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1ErgoVerbose.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1ErgoVerbose.hpp Thu May 07 20:51:12 2015 -0700 @@ -160,40 +160,43 @@ } while (0) -#define ergo_verbose(_tag_, _action_) \ - ergo_verbose_common(_tag_, _action_, "", 0, 0, 0, 0, 0, 0) - -#define ergo_verbose0(_tag_, _action_, _extra_format_) \ - ergo_verbose_common(_tag_, _action_, _extra_format_, 0, 0, 0, 0, 0, 0) - -#define ergo_verbose1(_tag_, _action_, _extra_format_, \ - _arg0_) \ - ergo_verbose_common(_tag_, _action_, _extra_format_, \ - _arg0_, 0, 0, 0, 0, 0) - -#define ergo_verbose2(_tag_, _action_, _extra_format_, \ - _arg0_, _arg1_) \ - ergo_verbose_common(_tag_, _action_, _extra_format_, \ - _arg0_, _arg1_, 0, 0, 0, 0) - -#define ergo_verbose3(_tag_, _action_, _extra_format_, \ - _arg0_, _arg1_, _arg2_) \ - ergo_verbose_common(_tag_, _action_, _extra_format_, \ - _arg0_, _arg1_, _arg2_, 0, 0, 0) - -#define ergo_verbose4(_tag_, _action_, _extra_format_, \ - _arg0_, _arg1_, _arg2_, _arg3_) \ - ergo_verbose_common(_tag_, _action_, _extra_format_, \ - _arg0_, _arg1_, _arg2_, _arg3_, 0, 0) - -#define ergo_verbose5(_tag_, _action_, _extra_format_, \ - _arg0_, _arg1_, _arg2_, _arg3_, _arg4_) \ - ergo_verbose_common(_tag_, _action_, _extra_format_, \ - _arg0_, _arg1_, _arg2_, _arg3_, _arg4_, 0) - #define ergo_verbose6(_tag_, _action_, _extra_format_, \ _arg0_, _arg1_, _arg2_, _arg3_, _arg4_, _arg5_) \ ergo_verbose_common(_tag_, _action_, _extra_format_, \ _arg0_, _arg1_, _arg2_, _arg3_, _arg4_, _arg5_) +#define ergo_verbose5(_tag_, _action_, _extra_format_, \ + _arg0_, _arg1_, _arg2_, _arg3_, _arg4_) \ + ergo_verbose6(_tag_, _action_, _extra_format_ "%s", \ + _arg0_, _arg1_, _arg2_, _arg3_, _arg4_, "") + +#define ergo_verbose4(_tag_, _action_, _extra_format_, \ + _arg0_, _arg1_, _arg2_, _arg3_) \ + ergo_verbose5(_tag_, _action_, _extra_format_ "%s", \ + _arg0_, _arg1_, _arg2_, _arg3_, "") + +#define ergo_verbose3(_tag_, _action_, _extra_format_, \ + _arg0_, _arg1_, _arg2_) \ + ergo_verbose4(_tag_, _action_, _extra_format_ "%s", \ + _arg0_, _arg1_, _arg2_, "") + +#define ergo_verbose2(_tag_, _action_, _extra_format_, \ + _arg0_, _arg1_) \ + ergo_verbose3(_tag_, _action_, _extra_format_ "%s", \ + _arg0_, _arg1_, "") + +#define ergo_verbose1(_tag_, _action_, _extra_format_, \ + _arg0_) \ + ergo_verbose2(_tag_, _action_, _extra_format_ "%s", \ + _arg0_, "") + + +#define ergo_verbose0(_tag_, _action_, _extra_format_) \ + ergo_verbose1(_tag_, _action_, _extra_format_ "%s", \ + "") + +#define ergo_verbose(_tag_, _action_) \ + ergo_verbose0(_tag_, _action_, "") + + #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1ERGOVERBOSE_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015 Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -263,7 +263,6 @@ _gc_par_phases[SystemDictionaryRoots] = new WorkerDataArray(max_gc_threads, "SystemDictionary Roots (ms)", true, G1Log::LevelFinest, 3); _gc_par_phases[CLDGRoots] = new WorkerDataArray(max_gc_threads, "CLDG Roots (ms)", true, G1Log::LevelFinest, 3); _gc_par_phases[JVMTIRoots] = new WorkerDataArray(max_gc_threads, "JVMTI Roots (ms)", true, G1Log::LevelFinest, 3); - _gc_par_phases[CodeCacheRoots] = new WorkerDataArray(max_gc_threads, "CodeCache Roots (ms)", true, G1Log::LevelFinest, 3); _gc_par_phases[CMRefRoots] = new WorkerDataArray(max_gc_threads, "CM RefProcessor Roots (ms)", true, G1Log::LevelFinest, 3); _gc_par_phases[WaitForStrongCLD] = new WorkerDataArray(max_gc_threads, "Wait For Strong CLD (ms)", true, G1Log::LevelFinest, 3); _gc_par_phases[WeakCLDRoots] = new WorkerDataArray(max_gc_threads, "Weak CLD Roots (ms)", true, G1Log::LevelFinest, 3); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015 Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,7 +51,6 @@ SystemDictionaryRoots, CLDGRoots, JVMTIRoots, - CodeCacheRoots, CMRefRoots, WaitForStrongCLD, WeakCLDRoots, diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1HotCardCache.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1HotCardCache.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1HotCardCache.hpp Thu May 07 20:51:12 2015 -0700 @@ -29,7 +29,7 @@ #include "gc_implementation/g1/g1CardCounts.hpp" #include "memory/allocation.hpp" #include "runtime/safepoint.hpp" -#include "runtime/thread.inline.hpp" +#include "runtime/thread.hpp" #include "utilities/globalDefinitions.hpp" class DirtyCardQueue; @@ -123,7 +123,7 @@ // Resets the hot card cache and discards the entries. void reset_hot_cache() { assert(SafepointSynchronize::is_at_safepoint(), "Should be at a safepoint"); - assert(Thread::current()->is_VM_thread(), "Current thread should be the VMthread"); + assert(Thread::current_noinline()->is_VM_thread(), "Current thread should be the VMthread"); if (default_use_cache()) { reset_hot_cache_internal(); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Thu May 07 20:51:12 2015 -0700 @@ -61,9 +61,8 @@ bool clear_all_softrefs) { assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint"); - SharedHeap* sh = SharedHeap::heap(); #ifdef ASSERT - if (sh->collector_policy()->should_clear_all_soft_refs()) { + if (G1CollectedHeap::heap()->collector_policy()->should_clear_all_soft_refs()) { assert(clear_all_softrefs, "Policy should have been checked earler"); } #endif @@ -102,11 +101,6 @@ BiasedLocking::restore_marks(); GenMarkSweep::deallocate_stacks(); - // "free at last gc" is calculated from these. - // CHF: cheating for now!!! - // Universe::set_heap_capacity_at_last_gc(Universe::heap()->capacity()); - // Universe::set_heap_used_at_last_gc(Universe::heap()->used()); - CodeCache::gc_epilogue(); JvmtiExport::gc_epilogue(); @@ -125,7 +119,6 @@ bool clear_all_softrefs) { // Recursively traverse all live objects and mark them GCTraceTime tm("phase 1", G1Log::fine() && Verbose, true, gc_timer(), gc_tracer()->gc_id()); - GenMarkSweep::trace(" 1"); G1CollectedHeap* g1h = G1CollectedHeap::heap(); @@ -168,12 +161,12 @@ Klass::clean_weak_klass_links(&GenMarkSweep::is_alive); // Delete entries for dead interned string and clean up unreferenced symbols in symbol table. - G1CollectedHeap::heap()->unlink_string_and_symbol_table(&GenMarkSweep::is_alive); + g1h->unlink_string_and_symbol_table(&GenMarkSweep::is_alive); if (VerifyDuringGC) { HandleMark hm; // handle scope COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact); - Universe::heap()->prepare_for_verify(); + g1h->prepare_for_verify(); // Note: we can verify only the heap here. When an object is // marked, the previous value of the mark word (including // identity hash values, ages, etc) is preserved, and the mark @@ -187,7 +180,7 @@ if (!VerifySilently) { gclog_or_tty->print(" VerifyDuringGC:(full)[Verifying "); } - Universe::heap()->verify(VerifySilently, VerifyOption_G1UseMarkWord); + g1h->verify(VerifySilently, VerifyOption_G1UseMarkWord); if (!VerifySilently) { gclog_or_tty->print_cr("]"); } @@ -205,7 +198,6 @@ // tracking expects us to do so. See comment under phase4. GCTraceTime tm("phase 2", G1Log::fine() && Verbose, true, gc_timer(), gc_tracer()->gc_id()); - GenMarkSweep::trace("2"); prepare_compaction(); } @@ -239,7 +231,6 @@ // Adjust the pointers to reflect the new locations GCTraceTime tm("phase 3", G1Log::fine() && Verbose, true, gc_timer(), gc_tracer()->gc_id()); - GenMarkSweep::trace("3"); // Need cleared claim bits for the roots processing ClassLoaderDataGraph::clear_claimed_marks(); @@ -301,7 +292,6 @@ G1CollectedHeap* g1h = G1CollectedHeap::heap(); GCTraceTime tm("phase 4", G1Log::fine() && Verbose, true, gc_timer(), gc_tracer()->gc_id()); - GenMarkSweep::trace("4"); G1SpaceCompactClosure blk; g1h->heap_region_iterate(&blk); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.hpp Thu May 07 20:51:12 2015 -0700 @@ -25,7 +25,7 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1MARKSWEEP_HPP #define SHARE_VM_GC_IMPLEMENTATION_G1_G1MARKSWEEP_HPP -#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" +#include "gc_implementation/g1/g1CollectedHeap.hpp" #include "gc_implementation/g1/heapRegion.hpp" #include "memory/genMarkSweep.hpp" #include "memory/generation.hpp" diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.cpp Thu May 07 20:51:12 2015 -0700 @@ -23,9 +23,12 @@ */ #include "precompiled.hpp" +#include "gc_implementation/g1/g1_specialized_oop_closures.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1OopClosures.inline.hpp" #include "gc_implementation/g1/g1ParScanThreadState.hpp" +#include "memory/iterator.inline.hpp" +#include "utilities/stack.inline.hpp" G1ParCopyHelper::G1ParCopyHelper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) : G1ParClosureSuper(g1, par_scan_state), _scanned_klass(NULL), @@ -50,3 +53,6 @@ assert(_worker_id < MAX2((uint)ParallelGCThreads, 1u), err_msg("The given worker id %u must be less than the number of threads %u", _worker_id, MAX2((uint)ParallelGCThreads, 1u))); } + +// Generate G1 specialized oop_oop_iterate functions. +SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_G1(ALL_KLASS_OOP_OOP_ITERATE_DEFN) diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -172,7 +172,7 @@ oopDesc* o = obj; #endif // CHECK_UNHANDLED_OOPS assert((intptr_t)o % MinObjAlignmentInBytes == 0, "not oop aligned"); - assert(Universe::heap()->is_in_reserved(obj), "must be in heap"); + assert(_g1->is_in_reserved(obj), "must be in heap"); #endif // ASSERT assert(_from != NULL, "from region must be non-NULL"); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,37 +44,45 @@ #endif #include "utilities/bitMap.inline.hpp" -G1PageBasedVirtualSpace::G1PageBasedVirtualSpace() : _low_boundary(NULL), - _high_boundary(NULL), _committed(), _page_size(0), _special(false), +G1PageBasedVirtualSpace::G1PageBasedVirtualSpace(ReservedSpace rs, size_t used_size, size_t page_size) : + _low_boundary(NULL), _high_boundary(NULL), _committed(), _page_size(0), _special(false), _dirty(), _executable(false) { + initialize_with_page_size(rs, used_size, page_size); } -bool G1PageBasedVirtualSpace::initialize_with_granularity(ReservedSpace rs, size_t page_size) { - if (!rs.is_reserved()) { - return false; // Allocation failed. - } - assert(_low_boundary == NULL, "VirtualSpace already initialized"); - assert(page_size > 0, "Granularity must be non-zero."); +void G1PageBasedVirtualSpace::initialize_with_page_size(ReservedSpace rs, size_t used_size, size_t page_size) { + guarantee(rs.is_reserved(), "Given reserved space must have been reserved already."); + + vmassert(_low_boundary == NULL, "VirtualSpace already initialized"); + vmassert(page_size > 0, "Page size must be non-zero."); + + guarantee(is_ptr_aligned(rs.base(), page_size), + err_msg("Reserved space base " PTR_FORMAT " is not aligned to requested page size " SIZE_FORMAT, p2i(rs.base()), page_size)); + guarantee(is_size_aligned(used_size, os::vm_page_size()), + err_msg("Given used reserved space size needs to be OS page size aligned (%d bytes) but is " SIZE_FORMAT, os::vm_page_size(), used_size)); + guarantee(used_size <= rs.size(), + err_msg("Used size of reserved space " SIZE_FORMAT " bytes is smaller than reservation at " SIZE_FORMAT " bytes", used_size, rs.size())); + guarantee(is_size_aligned(rs.size(), page_size), + err_msg("Expected that the virtual space is size aligned, but " SIZE_FORMAT " is not aligned to page size " SIZE_FORMAT, rs.size(), page_size)); _low_boundary = rs.base(); - _high_boundary = _low_boundary + rs.size(); + _high_boundary = _low_boundary + used_size; _special = rs.special(); _executable = rs.executable(); _page_size = page_size; - assert(_committed.size() == 0, "virtual space initialized more than once"); - uintx size_in_bits = rs.size() / page_size; - _committed.resize(size_in_bits, /* in_resource_area */ false); + vmassert(_committed.size() == 0, "virtual space initialized more than once"); + BitMap::idx_t size_in_pages = rs.size() / page_size; + _committed.resize(size_in_pages, /* in_resource_area */ false); if (_special) { - _dirty.resize(size_in_bits, /* in_resource_area */ false); + _dirty.resize(size_in_pages, /* in_resource_area */ false); } - return true; + _tail_size = used_size % _page_size; } - G1PageBasedVirtualSpace::~G1PageBasedVirtualSpace() { release(); } @@ -87,12 +95,18 @@ _special = false; _executable = false; _page_size = 0; + _tail_size = 0; _committed.resize(0, false); _dirty.resize(0, false); } size_t G1PageBasedVirtualSpace::committed_size() const { - return _committed.count_one_bits() * _page_size; + size_t result = _committed.count_one_bits() * _page_size; + // The last page might not be in full. + if (is_last_page_partial() && _committed.at(_committed.size() - 1)) { + result -= _page_size - _tail_size; + } + return result; } size_t G1PageBasedVirtualSpace::reserved_size() const { @@ -103,65 +117,134 @@ return reserved_size() - committed_size(); } -uintptr_t G1PageBasedVirtualSpace::addr_to_page_index(char* addr) const { +size_t G1PageBasedVirtualSpace::addr_to_page_index(char* addr) const { return (addr - _low_boundary) / _page_size; } -bool G1PageBasedVirtualSpace::is_area_committed(uintptr_t start, size_t size_in_pages) const { - uintptr_t end = start + size_in_pages; - return _committed.get_next_zero_offset(start, end) >= end; +bool G1PageBasedVirtualSpace::is_area_committed(size_t start_page, size_t size_in_pages) const { + size_t end_page = start_page + size_in_pages; + return _committed.get_next_zero_offset(start_page, end_page) >= end_page; } -bool G1PageBasedVirtualSpace::is_area_uncommitted(uintptr_t start, size_t size_in_pages) const { - uintptr_t end = start + size_in_pages; - return _committed.get_next_one_offset(start, end) >= end; +bool G1PageBasedVirtualSpace::is_area_uncommitted(size_t start_page, size_t size_in_pages) const { + size_t end_page = start_page + size_in_pages; + return _committed.get_next_one_offset(start_page, end_page) >= end_page; } -char* G1PageBasedVirtualSpace::page_start(uintptr_t index) { +char* G1PageBasedVirtualSpace::page_start(size_t index) const { return _low_boundary + index * _page_size; } -size_t G1PageBasedVirtualSpace::byte_size_for_pages(size_t num) { - return num * _page_size; +bool G1PageBasedVirtualSpace::is_after_last_page(size_t index) const { + guarantee(index <= _committed.size(), + err_msg("Given boundary page " SIZE_FORMAT " is beyond managed page count " SIZE_FORMAT, index, _committed.size())); + return index == _committed.size(); +} + +void G1PageBasedVirtualSpace::commit_preferred_pages(size_t start, size_t num_pages) { + vmassert(num_pages > 0, "No full pages to commit"); + vmassert(start + num_pages <= _committed.size(), + err_msg("Tried to commit area from page " SIZE_FORMAT " to page " SIZE_FORMAT " " + "that is outside of managed space of " SIZE_FORMAT " pages", + start, start + num_pages, _committed.size())); + + char* start_addr = page_start(start); + size_t size = num_pages * _page_size; + + os::commit_memory_or_exit(start_addr, size, _page_size, _executable, + err_msg("Failed to commit area from " PTR_FORMAT " to " PTR_FORMAT " of length " SIZE_FORMAT ".", + p2i(start_addr), p2i(start_addr + size), size)); +} + +void G1PageBasedVirtualSpace::commit_tail() { + vmassert(_tail_size > 0, "The size of the tail area must be > 0 when reaching here"); + + char* const aligned_end_address = (char*)align_ptr_down(_high_boundary, _page_size); + os::commit_memory_or_exit(aligned_end_address, _tail_size, os::vm_page_size(), _executable, + err_msg("Failed to commit tail area from " PTR_FORMAT " to " PTR_FORMAT " of length " SIZE_FORMAT ".", + p2i(aligned_end_address), p2i(_high_boundary), _tail_size)); } -bool G1PageBasedVirtualSpace::commit(uintptr_t start, size_t size_in_pages) { +void G1PageBasedVirtualSpace::commit_internal(size_t start_page, size_t end_page) { + guarantee(start_page < end_page, + err_msg("Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page)); + guarantee(end_page <= _committed.size(), + err_msg("Given end page " SIZE_FORMAT " is beyond end of managed page amount of " SIZE_FORMAT, end_page, _committed.size())); + + size_t pages = end_page - start_page; + bool need_to_commit_tail = is_after_last_page(end_page) && is_last_page_partial(); + + // If we have to commit some (partial) tail area, decrease the amount of pages to avoid + // committing that in the full-page commit code. + if (need_to_commit_tail) { + pages--; + } + + if (pages > 0) { + commit_preferred_pages(start_page, pages); + } + + if (need_to_commit_tail) { + commit_tail(); + } +} + +char* G1PageBasedVirtualSpace::bounded_end_addr(size_t end_page) const { + return MIN2(_high_boundary, page_start(end_page)); +} + +void G1PageBasedVirtualSpace::pretouch_internal(size_t start_page, size_t end_page) { + guarantee(start_page < end_page, + err_msg("Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page)); + + os::pretouch_memory(page_start(start_page), bounded_end_addr(end_page)); +} + +bool G1PageBasedVirtualSpace::commit(size_t start_page, size_t size_in_pages) { // We need to make sure to commit all pages covered by the given area. - guarantee(is_area_uncommitted(start, size_in_pages), "Specified area is not uncommitted"); + guarantee(is_area_uncommitted(start_page, size_in_pages), "Specified area is not uncommitted"); bool zero_filled = true; - uintptr_t end = start + size_in_pages; + size_t end_page = start_page + size_in_pages; if (_special) { // Check for dirty pages and update zero_filled if any found. - if (_dirty.get_next_one_offset(start,end) < end) { + if (_dirty.get_next_one_offset(start_page, end_page) < end_page) { zero_filled = false; - _dirty.clear_range(start, end); + _dirty.clear_range(start_page, end_page); } } else { - os::commit_memory_or_exit(page_start(start), byte_size_for_pages(size_in_pages), _executable, - err_msg("Failed to commit pages from "SIZE_FORMAT" of length "SIZE_FORMAT, start, size_in_pages)); + commit_internal(start_page, end_page); } - _committed.set_range(start, end); + _committed.set_range(start_page, end_page); if (AlwaysPreTouch) { - os::pretouch_memory(page_start(start), page_start(end)); + pretouch_internal(start_page, end_page); } return zero_filled; } -void G1PageBasedVirtualSpace::uncommit(uintptr_t start, size_t size_in_pages) { - guarantee(is_area_committed(start, size_in_pages), "checking"); +void G1PageBasedVirtualSpace::uncommit_internal(size_t start_page, size_t end_page) { + guarantee(start_page < end_page, + err_msg("Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page)); + char* start_addr = page_start(start_page); + os::uncommit_memory(start_addr, pointer_delta(bounded_end_addr(end_page), start_addr, sizeof(char))); +} + +void G1PageBasedVirtualSpace::uncommit(size_t start_page, size_t size_in_pages) { + guarantee(is_area_committed(start_page, size_in_pages), "checking"); + + size_t end_page = start_page + size_in_pages; if (_special) { // Mark that memory is dirty. If committed again the memory might // need to be cleared explicitly. - _dirty.set_range(start, start + size_in_pages); + _dirty.set_range(start_page, end_page); } else { - os::uncommit_memory(page_start(start), byte_size_for_pages(size_in_pages)); + uncommit_internal(start_page, end_page); } - _committed.clear_range(start, start + size_in_pages); + _committed.clear_range(start_page, end_page); } bool G1PageBasedVirtualSpace::contains(const void* p) const { @@ -175,7 +258,8 @@ out->cr(); out->print_cr(" - committed: " SIZE_FORMAT, committed_size()); out->print_cr(" - reserved: " SIZE_FORMAT, reserved_size()); - out->print_cr(" - [low_b, high_b]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]", p2i(_low_boundary), p2i(_high_boundary)); + out->print_cr(" - preferred page size: " SIZE_FORMAT, _page_size); + out->print_cr(" - [low_b, high_b]: [" PTR_FORMAT ", " PTR_FORMAT "]", p2i(_low_boundary), p2i(_high_boundary)); } void G1PageBasedVirtualSpace::print() { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,13 +27,19 @@ #include "memory/allocation.hpp" #include "memory/memRegion.hpp" -#include "runtime/virtualspace.hpp" +#include "memory/virtualspace.hpp" #include "utilities/bitMap.hpp" // Virtual space management helper for a virtual space with an OS page allocation // granularity. // (De-)Allocation requests are always OS page aligned by passing a page index // and multiples of pages. +// For systems that only commits of memory in a given size (always greater than +// page size) the base address is required to be aligned to that page size. +// The actual size requested need not be aligned to that page size, but the size +// of the reservation passed may be rounded up to this page size. Any fragment +// (less than the page size) of the actual size at the tail of the request will +// be committed using OS small pages. // The implementation gives an error when trying to commit or uncommit pages that // have already been committed or uncommitted. class G1PageBasedVirtualSpace VALUE_OBJ_CLASS_SPEC { @@ -43,7 +49,11 @@ char* _low_boundary; char* _high_boundary; - // The commit/uncommit granularity in bytes. + // The size of the tail in bytes of the handled space that needs to be committed + // using small pages. + size_t _tail_size; + + // The preferred page size used for commit/uncommit in bytes. size_t _page_size; // Bitmap used for verification of commit/uncommit operations. @@ -62,30 +72,55 @@ // Indicates whether the committed space should be executable. bool _executable; + // Helper function for committing memory. Commit the given memory range by using + // _page_size pages as much as possible and the remainder with small sized pages. + void commit_internal(size_t start_page, size_t end_page); + // Commit num_pages pages of _page_size size starting from start. All argument + // checking has been performed. + void commit_preferred_pages(size_t start_page, size_t end_page); + // Commit space at the high end of the space that needs to be committed with small + // sized pages. + void commit_tail(); + + // Uncommit the given memory range. + void uncommit_internal(size_t start_page, size_t end_page); + + // Pretouch the given memory range. + void pretouch_internal(size_t start_page, size_t end_page); + // Returns the index of the page which contains the given address. uintptr_t addr_to_page_index(char* addr) const; // Returns the address of the given page index. - char* page_start(uintptr_t index); - // Returns the byte size of the given number of pages. - size_t byte_size_for_pages(size_t num); + char* page_start(size_t index) const; + + // Is the given page index the last page? + bool is_last_page(size_t index) const { return index == (_committed.size() - 1); } + // Is the given page index the first after last page? + bool is_after_last_page(size_t index) const; + // Is the last page only partially covered by this space? + bool is_last_page_partial() const { return !is_ptr_aligned(_high_boundary, _page_size); } + // Returns the end address of the given page bounded by the reserved space. + char* bounded_end_addr(size_t end_page) const; // Returns true if the entire area is backed by committed memory. - bool is_area_committed(uintptr_t start, size_t size_in_pages) const; + bool is_area_committed(size_t start_page, size_t size_in_pages) const; // Returns true if the entire area is not backed by committed memory. - bool is_area_uncommitted(uintptr_t start, size_t size_in_pages) const; + bool is_area_uncommitted(size_t start_page, size_t size_in_pages) const; + void initialize_with_page_size(ReservedSpace rs, size_t used_size, size_t page_size); public: // Commit the given area of pages starting at start being size_in_pages large. // Returns true if the given area is zero filled upon completion. - bool commit(uintptr_t start, size_t size_in_pages); + bool commit(size_t start_page, size_t size_in_pages); // Uncommit the given area of pages starting at start being size_in_pages large. - void uncommit(uintptr_t start, size_t size_in_pages); + void uncommit(size_t start_page, size_t size_in_pages); - // Initialization - G1PageBasedVirtualSpace(); - bool initialize_with_granularity(ReservedSpace rs, size_t page_size); + // Initialize the given reserved space with the given base address and the size + // actually used. + // Prefer to commit in page_size chunks. + G1PageBasedVirtualSpace(ReservedSpace rs, size_t used_size, size_t page_size); // Destruction ~G1PageBasedVirtualSpace(); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp Thu May 07 20:51:12 2015 -0700 @@ -26,8 +26,10 @@ #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1OopClosures.inline.hpp" #include "gc_implementation/g1/g1ParScanThreadState.inline.hpp" +#include "gc_implementation/g1/g1StringDedup.hpp" #include "oops/oop.inline.hpp" #include "runtime/prefetch.inline.hpp" +#include "utilities/stack.inline.hpp" G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, uint queue_num, ReferenceProcessor* rp) : _g1h(g1h), diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,7 +63,7 @@ assert(has_partial_array_mask(p), "invariant"); oop from_obj = clear_partial_array_mask(p); - assert(Universe::heap()->is_in_reserved(from_obj), "must be in heap."); + assert(_g1h->is_in_reserved(from_obj), "must be in heap."); assert(from_obj->is_objArray(), "must be obj array"); objArrayOop from_obj_array = objArrayOop(from_obj); // The from-space object contains the real length. diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,22 +26,21 @@ #include "gc_implementation/g1/g1BiasedArray.hpp" #include "gc_implementation/g1/g1RegionToSpaceMapper.hpp" #include "memory/allocation.inline.hpp" -#include "runtime/virtualspace.hpp" +#include "memory/virtualspace.hpp" #include "services/memTracker.hpp" #include "utilities/bitMap.inline.hpp" G1RegionToSpaceMapper::G1RegionToSpaceMapper(ReservedSpace rs, - size_t commit_granularity, + size_t used_size, + size_t page_size, size_t region_granularity, MemoryType type) : - _storage(), - _commit_granularity(commit_granularity), + _storage(rs, used_size, page_size), _region_granularity(region_granularity), _listener(NULL), _commit_map() { - guarantee(is_power_of_2(commit_granularity), "must be"); + guarantee(is_power_of_2(page_size), "must be"); guarantee(is_power_of_2(region_granularity), "must be"); - _storage.initialize_with_granularity(rs, commit_granularity); MemTracker::record_virtual_memory_type((address)rs.base(), type); } @@ -55,25 +54,26 @@ public: G1RegionsLargerThanCommitSizeMapper(ReservedSpace rs, - size_t os_commit_granularity, + size_t actual_size, + size_t page_size, size_t alloc_granularity, size_t commit_factor, MemoryType type) : - G1RegionToSpaceMapper(rs, os_commit_granularity, alloc_granularity, type), - _pages_per_region(alloc_granularity / (os_commit_granularity * commit_factor)) { + G1RegionToSpaceMapper(rs, actual_size, page_size, alloc_granularity, type), + _pages_per_region(alloc_granularity / (page_size * commit_factor)) { - guarantee(alloc_granularity >= os_commit_granularity, "allocation granularity smaller than commit granularity"); + guarantee(alloc_granularity >= page_size, "allocation granularity smaller than commit granularity"); _commit_map.resize(rs.size() * commit_factor / alloc_granularity, /* in_resource_area */ false); } - virtual void commit_regions(uintptr_t start_idx, size_t num_regions) { - bool zero_filled = _storage.commit(start_idx * _pages_per_region, num_regions * _pages_per_region); + virtual void commit_regions(uint start_idx, size_t num_regions) { + bool zero_filled = _storage.commit((size_t)start_idx * _pages_per_region, num_regions * _pages_per_region); _commit_map.set_range(start_idx, start_idx + num_regions); fire_on_commit(start_idx, num_regions, zero_filled); } - virtual void uncommit_regions(uintptr_t start_idx, size_t num_regions) { - _storage.uncommit(start_idx * _pages_per_region, num_regions * _pages_per_region); + virtual void uncommit_regions(uint start_idx, size_t num_regions) { + _storage.uncommit((size_t)start_idx * _pages_per_region, num_regions * _pages_per_region); _commit_map.clear_range(start_idx, start_idx + num_regions); } }; @@ -98,22 +98,23 @@ public: G1RegionsSmallerThanCommitSizeMapper(ReservedSpace rs, - size_t os_commit_granularity, + size_t actual_size, + size_t page_size, size_t alloc_granularity, size_t commit_factor, MemoryType type) : - G1RegionToSpaceMapper(rs, os_commit_granularity, alloc_granularity, type), - _regions_per_page((os_commit_granularity * commit_factor) / alloc_granularity), _refcounts() { + G1RegionToSpaceMapper(rs, actual_size, page_size, alloc_granularity, type), + _regions_per_page((page_size * commit_factor) / alloc_granularity), _refcounts() { - guarantee((os_commit_granularity * commit_factor) >= alloc_granularity, "allocation granularity smaller than commit granularity"); - _refcounts.initialize((HeapWord*)rs.base(), (HeapWord*)(rs.base() + rs.size()), os_commit_granularity); + guarantee((page_size * commit_factor) >= alloc_granularity, "allocation granularity smaller than commit granularity"); + _refcounts.initialize((HeapWord*)rs.base(), (HeapWord*)(rs.base() + align_size_up(rs.size(), page_size)), page_size); _commit_map.resize(rs.size() * commit_factor / alloc_granularity, /* in_resource_area */ false); } - virtual void commit_regions(uintptr_t start_idx, size_t num_regions) { - for (uintptr_t i = start_idx; i < start_idx + num_regions; i++) { - assert(!_commit_map.at(i), err_msg("Trying to commit storage at region "INTPTR_FORMAT" that is already committed", i)); - uintptr_t idx = region_idx_to_page_idx(i); + virtual void commit_regions(uint start_idx, size_t num_regions) { + for (uint i = start_idx; i < start_idx + num_regions; i++) { + assert(!_commit_map.at(i), err_msg("Trying to commit storage at region %u that is already committed", i)); + size_t idx = region_idx_to_page_idx(i); uint old_refcount = _refcounts.get_by_index(idx); bool zero_filled = false; if (old_refcount == 0) { @@ -125,10 +126,10 @@ } } - virtual void uncommit_regions(uintptr_t start_idx, size_t num_regions) { - for (uintptr_t i = start_idx; i < start_idx + num_regions; i++) { - assert(_commit_map.at(i), err_msg("Trying to uncommit storage at region "INTPTR_FORMAT" that is not committed", i)); - uintptr_t idx = region_idx_to_page_idx(i); + virtual void uncommit_regions(uint start_idx, size_t num_regions) { + for (uint i = start_idx; i < start_idx + num_regions; i++) { + assert(_commit_map.at(i), err_msg("Trying to uncommit storage at region %u that is not committed", i)); + size_t idx = region_idx_to_page_idx(i); uint old_refcount = _refcounts.get_by_index(idx); assert(old_refcount > 0, "must be"); if (old_refcount == 1) { @@ -147,14 +148,15 @@ } G1RegionToSpaceMapper* G1RegionToSpaceMapper::create_mapper(ReservedSpace rs, - size_t os_commit_granularity, + size_t actual_size, + size_t page_size, size_t region_granularity, size_t commit_factor, MemoryType type) { - if (region_granularity >= (os_commit_granularity * commit_factor)) { - return new G1RegionsLargerThanCommitSizeMapper(rs, os_commit_granularity, region_granularity, commit_factor, type); + if (region_granularity >= (page_size * commit_factor)) { + return new G1RegionsLargerThanCommitSizeMapper(rs, actual_size, page_size, region_granularity, commit_factor, type); } else { - return new G1RegionsSmallerThanCommitSizeMapper(rs, os_commit_granularity, region_granularity, commit_factor, type); + return new G1RegionsSmallerThanCommitSizeMapper(rs, actual_size, page_size, region_granularity, commit_factor, type); } } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.hpp Thu May 07 20:51:12 2015 -0700 @@ -46,12 +46,12 @@ protected: // Backing storage. G1PageBasedVirtualSpace _storage; - size_t _commit_granularity; + size_t _region_granularity; // Mapping management BitMap _commit_map; - G1RegionToSpaceMapper(ReservedSpace rs, size_t commit_granularity, size_t region_granularity, MemoryType type); + G1RegionToSpaceMapper(ReservedSpace rs, size_t used_size, size_t page_size, size_t region_granularity, MemoryType type); void fire_on_commit(uint start_idx, size_t num_regions, bool zero_filled); public: @@ -70,16 +70,20 @@ return _commit_map.at(idx); } - virtual void commit_regions(uintptr_t start_idx, size_t num_regions = 1) = 0; - virtual void uncommit_regions(uintptr_t start_idx, size_t num_regions = 1) = 0; + virtual void commit_regions(uint start_idx, size_t num_regions = 1) = 0; + virtual void uncommit_regions(uint start_idx, size_t num_regions = 1) = 0; // Creates an appropriate G1RegionToSpaceMapper for the given parameters. + // The actual space to be used within the given reservation is given by actual_size. + // This is because some OSes need to round up the reservation size to guarantee + // alignment of page_size. // The byte_translation_factor defines how many bytes in a region correspond to // a single byte in the data structure this mapper is for. // Eg. in the card table, this value corresponds to the size a single card - // table entry corresponds to. + // table entry corresponds to in the heap. static G1RegionToSpaceMapper* create_mapper(ReservedSpace rs, - size_t os_commit_granularity, + size_t actual_size, + size_t page_size, size_t region_granularity, size_t byte_translation_factor, MemoryType type); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Thu May 07 20:51:12 2015 -0700 @@ -38,6 +38,7 @@ #include "oops/oop.inline.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/intHisto.hpp" +#include "utilities/stack.inline.hpp" #define CARD_REPEAT_HISTO 0 diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,7 +57,7 @@ oopDesc* o = obj; #endif // CHECK_UNHANDLED_OOPS assert((intptr_t)o % MinObjAlignmentInBytes == 0, "not oop aligned"); - assert(Universe::heap()->is_in_reserved(obj), "must be in heap"); + assert(_g1->is_in_reserved(obj), "must be in heap"); #endif // ASSERT assert(from == NULL || from->is_in_reserved(p), "p is not in from"); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1RootProcessor.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1RootProcessor.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RootProcessor.cpp Thu May 07 20:51:12 2015 -0700 @@ -116,7 +116,7 @@ G1RootProcessor::G1RootProcessor(G1CollectedHeap* g1h) : _g1h(g1h), _process_strong_tasks(new SubTasksDone(G1RP_PS_NumElements)), - _srs(g1h), + _srs(), _lock(Mutex::leaf, "G1 Root Scanning barrier lock", false, Monitor::_safepoint_check_never), _n_workers_discovered_strong_classes(0) {} @@ -253,7 +253,8 @@ { G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::ThreadRoots, worker_i); - Threads::possibly_parallel_oops_do(strong_roots, thread_stack_clds, strong_code); + bool is_par = _g1h->n_par_threads() > 0; + Threads::possibly_parallel_oops_do(is_par, strong_roots, thread_stack_clds, strong_code); } } @@ -323,10 +324,6 @@ void G1RootProcessor::scan_remembered_sets(G1ParPushHeapRSClosure* scan_rs, OopClosure* scan_non_heap_weak_roots, uint worker_i) { - G1GCPhaseTimes* phase_times = _g1h->g1_policy()->phase_times(); - G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::CodeCacheRoots, worker_i); - - // Now scan the complement of the collection set. G1CodeBlobClosure scavenge_cs_nmethods(scan_non_heap_weak_roots); _g1h->g1_rem_set()->oops_into_collection_set_do(scan_rs, &scavenge_cs_nmethods, worker_i); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1RootProcessor.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1RootProcessor.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RootProcessor.hpp Thu May 07 20:51:12 2015 -0700 @@ -26,7 +26,7 @@ #define SHARE_VM_GC_IMPLEMENTATION_G1_ROOTPROCESSOR_HPP #include "memory/allocation.hpp" -#include "memory/sharedHeap.hpp" +#include "memory/strongRootsScope.hpp" #include "runtime/mutex.hpp" class CLDClosure; @@ -46,7 +46,7 @@ class G1RootProcessor : public StackObj { G1CollectedHeap* _g1h; SubTasksDone* _process_strong_tasks; - SharedHeap::StrongRootsScope _srs; + StrongRootsScope _srs; // Used to implement the Thread work barrier. Monitor _lock; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp Thu May 07 20:51:12 2015 -0700 @@ -206,7 +206,7 @@ if (new_val == NULL) return; // Otherwise, log it. G1SATBCardTableLoggingModRefBS* g1_bs = - barrier_set_cast(Universe::heap()->barrier_set()); + barrier_set_cast(G1CollectedHeap::heap()->barrier_set()); g1_bs->write_ref_field_work(field, new_val); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.cpp Thu May 07 20:51:12 2015 -0700 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/javaClasses.inline.hpp" +#include "gc_implementation/g1/g1CollectedHeap.hpp" #include "gc_implementation/g1/g1StringDedup.hpp" #include "gc_implementation/g1/g1StringDedupQueue.hpp" #include "memory/gcLocker.hpp" @@ -163,7 +164,7 @@ while (!iter.is_empty()) { oop obj = iter.next(); if (obj != NULL) { - guarantee(Universe::heap()->is_in_reserved(obj), "Object must be on the heap"); + guarantee(G1CollectedHeap::heap()->is_in_reserved(obj), "Object must be on the heap"); guarantee(!obj->is_forwarded(), "Object must not be forwarded"); guarantee(java_lang_String::is_instance(obj), "Object must be a String"); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.cpp Thu May 07 20:51:12 2015 -0700 @@ -27,6 +27,7 @@ #include "classfile/javaClasses.inline.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" +#include "gc_implementation/g1/g1StringDedup.hpp" #include "gc_implementation/g1/g1StringDedupTable.hpp" #include "memory/gcLocker.hpp" #include "memory/padded.inline.hpp" @@ -519,7 +520,7 @@ while (*entry != NULL) { typeArrayOop value = (*entry)->obj(); guarantee(value != NULL, "Object must not be NULL"); - guarantee(Universe::heap()->is_in_reserved(value), "Object must be on the heap"); + guarantee(G1CollectedHeap::heap()->is_in_reserved(value), "Object must be on the heap"); guarantee(!value->is_forwarded(), "Object must not be forwarded"); guarantee(value->is_typeArray(), "Object must be a typeArrayOop"); unsigned int hash = hash_code(value); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.hpp Thu May 07 20:51:12 2015 -0700 @@ -29,6 +29,7 @@ #include "runtime/mutexLocker.hpp" class G1StringDedupEntryCache; +class G1StringDedupUnlinkOrOopsDoClosure; // // Table entry in the deduplication hashtable. Points weakly to the diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp Thu May 07 20:51:12 2015 -0700 @@ -41,15 +41,6 @@ develop(intx, G1MarkingVerboseLevel, 0, \ "Level (0-4) of verboseness of the marking code") \ \ - develop(bool, G1PrintReachableAtInitialMark, false, \ - "Reachable object dump at the initial mark pause") \ - \ - develop(bool, G1VerifyDuringGCPrintReachable, false, \ - "If conc mark verification fails, dump reachable objects") \ - \ - develop(ccstr, G1PrintReachableBaseFile, NULL, \ - "The base file name for the reachable object dumps") \ - \ develop(bool, G1TraceMarkStackOverflow, false, \ "If true, extra debugging code for CM restart for ovflw.") \ \ @@ -99,9 +90,6 @@ "the buffer will be enqueued for processing. A value of 0 " \ "specifies that mutator threads should not do such filtering.") \ \ - develop(bool, G1SATBPrintStubs, false, \ - "If true, print generated stubs for the SATB barrier") \ - \ experimental(intx, G1ExpandByPercentOfAvailable, 20, \ "When expanding, % of uncommitted space to claim.") \ \ diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp Thu May 07 20:51:12 2015 -0700 @@ -31,7 +31,6 @@ #include "gc_implementation/g1/survRateGroup.hpp" #include "gc_implementation/shared/ageTable.hpp" #include "gc_implementation/shared/spaceDecorator.hpp" -#include "memory/space.inline.hpp" #include "memory/watermark.hpp" #include "utilities/macros.hpp" @@ -45,6 +44,7 @@ // The solution is to remove this method from the definition // of a Space. +class G1CollectedHeap; class HeapRegionRemSet; class HeapRegionRemSetIterator; class HeapRegion; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.cpp Thu May 07 20:51:12 2015 -0700 @@ -330,8 +330,12 @@ assert(!hrclaimer->is_region_claimed(ch_index), "Must not have been claimed yet because claiming of humongous continuation first claims the start region"); - // There's no need to actually claim the continues humongous region, but we can do it in an assert as an extra precaution. - assert(hrclaimer->claim_region(ch_index), "We should always be able to claim the continuesHumongous part of the humongous object"); + // Claim the region so no other worker tries to process the region. When a worker processes a + // starts_humongous region it may also process the associated continues_humongous regions. + // The continues_humongous regions can be changed to free regions. Unless this worker claims + // all of these regions, other workers might try claim and process these newly free regions. + bool claim_result = hrclaimer->claim_region(ch_index); + guarantee(claim_result, "We should always be able to claim the continuesHumongous part of the humongous object"); bool res2 = blk->doHeapRegion(chr); if (res2) { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp Thu May 07 20:51:12 2015 -0700 @@ -419,6 +419,7 @@ ReservedSpace bot_rs(G1BlockOffsetSharedArray::compute_size(heap.word_size())); G1RegionToSpaceMapper* bot_storage = G1RegionToSpaceMapper::create_mapper(bot_rs, + bot_rs.size(), os::vm_page_size(), HeapRegion::GrainBytes, G1BlockOffsetSharedArray::N_bytes, diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/satbQueue.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/satbQueue.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/satbQueue.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,38 +25,75 @@ #include "precompiled.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/satbQueue.hpp" +#include "gc_interface/collectedHeap.hpp" #include "memory/allocation.inline.hpp" -#include "memory/sharedHeap.hpp" #include "oops/oop.inline.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/thread.hpp" #include "runtime/vmThread.hpp" void ObjPtrQueue::flush() { - // The buffer might contain refs into the CSet. We have to filter it - // first before we flush it, otherwise we might end up with an - // enqueued buffer with refs into the CSet which breaks our invariants. + // Filter now to possibly save work later. If filtering empties the + // buffer then flush_impl can deallocate the buffer. filter(); flush_impl(); } -// This method removes entries from an SATB buffer that will not be -// useful to the concurrent marking threads. An entry is removed if it -// satisfies one of the following conditions: +// Return true if a SATB buffer entry refers to an object that +// requires marking. +// +// The entry must point into the G1 heap. In particular, it must not +// be a NULL pointer. NULL pointers are pre-filtered and never +// inserted into a SATB buffer. +// +// An entry that is below the NTAMS pointer for the containing heap +// region requires marking. Such an entry must point to a valid object. +// +// An entry that is at least the NTAMS pointer for the containing heap +// region might be any of the following, none of which should be marked. +// +// * A reference to an object allocated since marking started. +// According to SATB, such objects are implicitly kept live and do +// not need to be dealt with via SATB buffer processing. +// +// * A reference to a young generation object. Young objects are +// handled separately and are not marked by concurrent marking. +// +// * A stale reference to a young generation object. If a young +// generation object reference is recorded and not filtered out +// before being moved by a young collection, the reference becomes +// stale. // -// * it points to an object outside the G1 heap (G1's concurrent -// marking only visits objects inside the G1 heap), -// * it points to an object that has been allocated since marking -// started (according to SATB those objects do not need to be -// visited during marking), or -// * it points to an object that has already been marked (no need to -// process it again). +// * A stale reference to an eagerly reclaimed humongous object. If a +// humongous object is recorded and then reclaimed, the reference +// becomes stale. // -// The rest of the entries will be retained and are compacted towards -// the top of the buffer. Note that, because we do not allow old -// regions in the CSet during marking, all objects on the CSet regions -// are young (eden or survivors) and therefore implicitly live. So any -// references into the CSet will be removed during filtering. +// The stale reference cases are implicitly handled by the NTAMS +// comparison. Because of the possibility of stale references, buffer +// processing must be somewhat circumspect and not assume entries +// in an unfiltered buffer refer to valid objects. + +inline bool requires_marking(const void* entry, G1CollectedHeap* heap) { + // Includes rejection of NULL pointers. + assert(heap->is_in_reserved(entry), + err_msg("Non-heap pointer in SATB buffer: " PTR_FORMAT, p2i(entry))); + + HeapRegion* region = heap->heap_region_containing_raw(entry); + assert(region != NULL, err_msg("No region for " PTR_FORMAT, p2i(entry))); + if (entry >= region->next_top_at_mark_start()) { + return false; + } + + assert(((oop)entry)->is_oop(true /* ignore mark word */), + err_msg("Invalid oop in SATB buffer: " PTR_FORMAT, p2i(entry))); + + return true; +} + +// This method removes entries from a SATB buffer that will not be +// useful to the concurrent marking threads. Entries are retained if +// they require marking and are not already marked. Retained entries +// are compacted toward the top of the buffer. void ObjPtrQueue::filter() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); @@ -78,26 +115,25 @@ assert(i > 0, "we should have at least one more entry to process"); i -= oopSize; debug_only(entries += 1;) - oop* p = (oop*) &buf[byte_index_to_index((int) i)]; - oop obj = *p; + void** p = &buf[byte_index_to_index((int) i)]; + void* entry = *p; // NULL the entry so that unused parts of the buffer contain NULLs // at the end. If we are going to retain it we will copy it to its // final place. If we have retained all entries we have visited so // far, we'll just end up copying it to the same place. *p = NULL; - bool retain = g1h->is_obj_ill(obj); - if (retain) { + if (requires_marking(entry, g1h) && !g1h->isMarkedNext((oop)entry)) { assert(new_index > 0, "we should not have already filled up the buffer"); new_index -= oopSize; assert(new_index >= i, "new_index should never be below i, as we always compact 'up'"); - oop* new_p = (oop*) &buf[byte_index_to_index((int) new_index)]; + void** new_p = &buf[byte_index_to_index((int) new_index)]; assert(new_p >= p, "the destination location should never be below " "the source as we always compact 'up'"); assert(*new_p == NULL, "we should have already cleared the destination location"); - *new_p = obj; + *new_p = entry; debug_only(retained += 1;) } } @@ -144,12 +180,6 @@ return should_enqueue; } -void ObjPtrQueue::apply_closure(ObjectClosure* cl) { - if (_buf != NULL) { - apply_closure_to_buffer(cl, _buf, _index, _sz); - } -} - void ObjPtrQueue::apply_closure_and_empty(ObjectClosure* cl) { if (_buf != NULL) { apply_closure_to_buffer(cl, _buf, _index, _sz); @@ -184,23 +214,12 @@ } #endif // PRODUCT -#ifdef ASSERT -void ObjPtrQueue::verify_oops_in_buffer() { - if (_buf == NULL) return; - for (size_t i = _index; i < _sz; i += oopSize) { - oop obj = (oop)_buf[byte_index_to_index((int)i)]; - assert(obj != NULL && obj->is_oop(true /* ignore mark word */), - "Not an oop"); - } -} -#endif - #ifdef _MSC_VER // the use of 'this' below gets a warning, make it go away #pragma warning( disable:4355 ) // 'this' : used in base member initializer list #endif // _MSC_VER SATBMarkQueueSet::SATBMarkQueueSet() : - PtrQueueSet(), _closures(NULL), + PtrQueueSet(), _shared_satb_queue(this, true /*perm*/) { } void SATBMarkQueueSet::initialize(Monitor* cbl_mon, Mutex* fl_lock, @@ -208,11 +227,9 @@ Mutex* lock) { PtrQueueSet::initialize(cbl_mon, fl_lock, process_completed_threshold, -1); _shared_satb_queue.set_lock(lock); - _closures = NEW_C_HEAP_ARRAY(ObjectClosure*, ParallelGCThreads, mtGC); } void SATBMarkQueueSet::handle_zero_index_for_thread(JavaThread* t) { - DEBUG_ONLY(t->satb_mark_queue().verify_oops_in_buffer();) t->satb_mark_queue().handle_zero_index(); } @@ -272,13 +289,7 @@ shared_satb_queue()->filter(); } -void SATBMarkQueueSet::set_closure(uint worker, ObjectClosure* closure) { - assert(_closures != NULL, "Precondition"); - assert(worker < ParallelGCThreads, "Worker index must be in range [0...ParallelGCThreads)"); - _closures[worker] = closure; -} - -bool SATBMarkQueueSet::apply_closure_to_completed_buffer(uint worker) { +bool SATBMarkQueueSet::apply_closure_to_completed_buffer(ObjectClosure* cl) { BufferNode* nd = NULL; { MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); @@ -290,7 +301,6 @@ if (_n_completed_buffers == 0) _process_completed = false; } } - ObjectClosure* cl = _closures[worker]; if (nd != NULL) { void **buf = BufferNode::make_buffer_from_node(nd); ObjPtrQueue::apply_closure_to_buffer(cl, buf, 0, _sz); @@ -301,28 +311,6 @@ } } -void SATBMarkQueueSet::iterate_completed_buffers_read_only(ObjectClosure* cl) { - assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); - assert(cl != NULL, "pre-condition"); - - BufferNode* nd = _completed_buffers_head; - while (nd != NULL) { - void** buf = BufferNode::make_buffer_from_node(nd); - ObjPtrQueue::apply_closure_to_buffer(cl, buf, 0, _sz); - nd = nd->next(); - } -} - -void SATBMarkQueueSet::iterate_thread_buffers_read_only(ObjectClosure* cl) { - assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); - assert(cl != NULL, "pre-condition"); - - for (JavaThread* t = Threads::first(); t; t = t->next()) { - t->satb_mark_queue().apply_closure(cl); - } - shared_satb_queue()->apply_closure(cl); -} - #ifndef PRODUCT // Helpful for debugging diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/satbQueue.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/satbQueue.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/satbQueue.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,9 +41,6 @@ // Filter out unwanted entries from the buffer. void filter(); - // Apply the closure to all elements. - void apply_closure(ObjectClosure* cl); - // Apply the closure to all elements and empty the buffer; void apply_closure_and_empty(ObjectClosure* cl); @@ -72,13 +69,9 @@ void print(const char* name); static void print(const char* name, void** buf, size_t index, size_t sz); #endif // PRODUCT - - void verify_oops_in_buffer() NOT_DEBUG_RETURN; }; class SATBMarkQueueSet: public PtrQueueSet { - ObjectClosure** _closures; // One per ParGCThread. - ObjPtrQueue _shared_satb_queue; #ifdef ASSERT @@ -104,22 +97,10 @@ // Filter all the currently-active SATB buffers. void filter_thread_buffers(); - // Register closure for the given worker thread. The "apply_closure_to_completed_buffer" - // method will apply this closure to a completed buffer, and "iterate_closure_all_threads" - // applies it to partially-filled buffers (the latter should only be done - // with the world stopped). - void set_closure(uint worker, ObjectClosure* closure); - // If there exists some completed buffer, pop it, then apply the - // registered closure to all its elements, and return true. If no + // closure to all its elements, and return true. If no // completed buffers exist, return false. - bool apply_closure_to_completed_buffer(uint worker); - - // Apply the given closure on enqueued and currently-active buffers - // respectively. Both methods are read-only, i.e., they do not - // modify any of the buffers. - void iterate_completed_buffers_read_only(ObjectClosure* cl); - void iterate_thread_buffers_read_only(ObjectClosure* cl); + bool apply_closure_to_completed_buffer(ObjectClosure* closure); #ifndef PRODUCT // Helpful for debugging diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp Thu May 07 20:51:12 2015 -0700 @@ -26,8 +26,8 @@ #define SHARE_VM_GC_IMPLEMENTATION_G1_VMSTRUCTS_G1_HPP #include "gc_implementation/g1/heapRegion.hpp" -#include "gc_implementation/g1/heapRegionManager.inline.hpp" -#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" +#include "gc_implementation/g1/heapRegionManager.hpp" +#include "gc_implementation/g1/g1CollectedHeap.hpp" #define VM_STRUCTS_G1(nonstatic_field, static_field) \ \ @@ -70,7 +70,7 @@ \ declare_toplevel_type(G1HeapRegionTable) \ \ - declare_type(G1CollectedHeap, SharedHeap) \ + declare_type(G1CollectedHeap, CollectedHeap) \ \ declare_type(G1OffsetTableContigSpace, CompactibleSpace) \ declare_type(HeapRegion, G1OffsetTableContigSpace) \ diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Thu May 07 20:51:12 2015 -0700 @@ -225,15 +225,10 @@ void VM_CGC_Operation::doit() { TraceCPUTime tcpu(G1Log::finer(), true, gclog_or_tty); - GCTraceTime t(_printGCMessage, G1Log::fine(), true, G1CollectedHeap::heap()->gc_timer_cm(), G1CollectedHeap::heap()->concurrent_mark()->concurrent_gc_id()); - SharedHeap* sh = SharedHeap::heap(); - // This could go away if CollectedHeap gave access to _gc_is_active... - if (sh != NULL) { - IsGCActiveMark x; - _cl->do_void(); - } else { - _cl->do_void(); - } + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + GCTraceTime t(_printGCMessage, G1Log::fine(), true, g1h->gc_timer_cm(), g1h->concurrent_mark()->concurrent_gc_id()); + IsGCActiveMark x; + _cl->do_void(); } bool VM_CGC_Operation::doit_prologue() { @@ -244,14 +239,12 @@ } Heap_lock->lock(); - SharedHeap::heap()->_thread_holds_heap_lock_for_gc = true; return true; } void VM_CGC_Operation::doit_epilogue() { // Note the relative order of the unlocks must match that in // VM_GC_Operation::doit_epilogue() - SharedHeap::heap()->_thread_holds_heap_lock_for_gc = false; Heap_lock->unlock(); if (_needs_pll) { release_and_notify_pending_list_lock(); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp --- a/hotspot/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp Thu May 07 20:51:12 2015 -0700 @@ -23,17 +23,17 @@ */ #include "precompiled.hpp" +#include "gc_interface/collectedHeap.hpp" #include "memory/allocation.inline.hpp" #include "memory/cardTableModRefBS.hpp" #include "memory/cardTableRS.hpp" -#include "memory/sharedHeap.hpp" +#include "memory/genCollectedHeap.hpp" #include "memory/space.inline.hpp" -#include "memory/universe.hpp" +#include "memory/virtualspace.hpp" #include "oops/oop.inline.hpp" #include "runtime/java.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/orderAccess.inline.hpp" -#include "runtime/virtualspace.hpp" #include "runtime/vmThread.hpp" void CardTableModRefBS::non_clean_card_iterate_parallel_work(Space* sp, MemRegion mr, @@ -449,7 +449,7 @@ // Do a dirty read here. If we pass the conditional then take the rare // event lock and do the read again in case some other thread had already // succeeded and done the resize. - int cur_collection = Universe::heap()->total_collections(); + int cur_collection = GenCollectedHeap::heap()->total_collections(); if (_last_LNC_resizing_collection[i] != cur_collection) { MutexLocker x(ParGCRareEvent_lock); if (_last_LNC_resizing_collection[i] != cur_collection) { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp --- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Thu May 07 20:51:12 2015 -0700 @@ -34,7 +34,7 @@ #include "gc_implementation/shared/gcTimer.hpp" #include "gc_implementation/shared/gcTrace.hpp" #include "gc_implementation/shared/gcTraceTime.hpp" -#include "gc_implementation/shared/parGCAllocBuffer.inline.hpp" +#include "gc_implementation/shared/plab.inline.hpp" #include "gc_implementation/shared/spaceDecorator.hpp" #include "memory/defNewGeneration.inline.hpp" #include "memory/genCollectedHeap.hpp" @@ -42,7 +42,7 @@ #include "memory/generation.hpp" #include "memory/referencePolicy.hpp" #include "memory/resourceArea.hpp" -#include "memory/sharedHeap.hpp" +#include "memory/strongRootsScope.hpp" #include "memory/space.hpp" #include "oops/objArrayOop.hpp" #include "oops/oop.inline.hpp" @@ -53,6 +53,7 @@ #include "runtime/thread.inline.hpp" #include "utilities/copy.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/stack.inline.hpp" #include "utilities/workgroup.hpp" #ifdef _MSC_VER @@ -117,7 +118,7 @@ void ParScanThreadState::scan_partial_array_and_push_remainder(oop old) { assert(old->is_objArray(), "must be obj array"); assert(old->is_forwarded(), "must be forwarded"); - assert(Universe::heap()->is_in_reserved(old), "must be in heap."); + assert(GenCollectedHeap::heap()->is_in_reserved(old), "must be in heap."); assert(!old_gen()->is_in(old), "must be in young generation."); objArrayOop obj = objArrayOop(old->forwardee()); @@ -199,9 +200,9 @@ for (size_t i = 0; i != num_take_elems; i++) { oop cur = of_stack->pop(); oop obj_to_push = cur->forwardee(); - assert(Universe::heap()->is_in_reserved(cur), "Should be in heap"); + assert(GenCollectedHeap::heap()->is_in_reserved(cur), "Should be in heap"); assert(!old_gen()->is_in_reserved(cur), "Should be in young gen"); - assert(Universe::heap()->is_in_reserved(obj_to_push), "Should be in heap"); + assert(GenCollectedHeap::heap()->is_in_reserved(obj_to_push), "Should be in heap"); if (should_be_partially_scanned(obj_to_push, cur)) { assert(arrayOop(cur)->length() == 0, "entire array remaining to be scanned"); obj_to_push = cur; @@ -225,7 +226,7 @@ // buffer. HeapWord* obj = NULL; if (!_to_space_full) { - ParGCAllocBuffer* const plab = to_space_alloc_buffer(); + PLAB* const plab = to_space_alloc_buffer(); Space* const sp = to_space(); if (word_sz * 100 < ParallelGCBufferWastePct * plab->word_sz()) { @@ -235,7 +236,7 @@ HeapWord* buf_space = sp->par_allocate(buf_size); if (buf_space == NULL) { const size_t min_bytes = - ParGCAllocBuffer::min_size() << LogHeapWordSize; + PLAB::min_size() << LogHeapWordSize; size_t free_bytes = sp->free(); while(buf_space == NULL && free_bytes >= min_bytes) { buf_size = free_bytes >> LogHeapWordSize; @@ -251,7 +252,7 @@ record_survivor_plab(buf_space, buf_size); obj = plab->allocate_aligned(word_sz, SurvivorAlignmentInBytes); // Note that we cannot compare buf_size < word_sz below - // because of AlignmentReserve (see ParGCAllocBuffer::allocate()). + // because of AlignmentReserve (see PLAB::allocate()). assert(obj != NULL || plab->words_remaining() < word_sz, "Else should have been able to allocate"); // It's conceivable that we may be able to use the @@ -596,8 +597,6 @@ // and handle marks. ResourceMark rm; HandleMark hm; - // We would need multiple old-gen queues otherwise. - assert(gch->n_gens() == 2, "Par young collection currently only works with one older gen."); ParScanThreadState& par_scan_state = _state_set->thread_state(worker_id); assert(_state_set->is_valid(worker_id), "Should not have been called"); @@ -697,7 +696,7 @@ _par_cl->do_oop_nv(p); - if (Universe::heap()->is_in_reserved(p)) { + if (GenCollectedHeap::heap()->is_in_reserved(p)) { oop obj = oopDesc::load_decode_heap_oop_not_null(p); _rs->write_ref_field_gc_par(p, obj); } @@ -724,7 +723,7 @@ _cl->do_oop_nv(p); - if (Universe::heap()->is_in_reserved(p)) { + if (GenCollectedHeap::heap()->is_in_reserved(p)) { oop obj = oopDesc::load_decode_heap_oop_not_null(p); _rs->write_ref_field_gc_par(p, obj); } @@ -823,8 +822,6 @@ void ParNewRefProcTaskExecutor::execute(ProcessTask& task) { GenCollectedHeap* gch = GenCollectedHeap::heap(); - assert(gch->kind() == CollectedHeap::GenCollectedHeap, - "not a generational heap"); FlexibleWorkGang* workers = gch->workers(); assert(workers != NULL, "Need parallel worker threads."); _state_set.reset(workers->active_workers(), _generation.promotion_failed()); @@ -899,7 +896,7 @@ _gc_tracer.report_promotion_failed(_promotion_failed_info); } // Reset the PromotionFailureALot counters. - NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();) + NOT_PRODUCT(gch->reset_promotion_should_fail();) } void ParNewGeneration::collect(bool full, @@ -912,8 +909,6 @@ _gc_timer->register_gc_start(); - assert(gch->kind() == CollectedHeap::GenCollectedHeap, - "not a CMS generational heap"); AdaptiveSizePolicy* size_policy = gch->gen_policy()->size_policy(); FlexibleWorkGang* workers = gch->workers(); assert(workers != NULL, "Need workgang for parallel work"); @@ -922,8 +917,6 @@ workers->active_workers(), Threads::number_of_non_daemon_threads()); workers->set_active_workers(active_workers); - assert(gch->n_gens() == 2, - "Par collection currently only works with single older gen."); _old_gen = gch->old_gen(); // If the next generation is too full to accommodate worst-case promotion @@ -974,10 +967,10 @@ // in the multi-threaded case, but we special-case n=1 here to get // repeatable measurements of the 1-thread overhead of the parallel code. if (n_workers > 1) { - GenCollectedHeap::StrongRootsScope srs(gch); + StrongRootsScope srs; workers->run_task(&tsk); } else { - GenCollectedHeap::StrongRootsScope srs(gch); + StrongRootsScope srs; tsk.work(0); } thread_state_set.reset(0 /* Bad value in debug if not reset */, @@ -1194,7 +1187,7 @@ } else { // Is in to-space; do copying ourselves. Copy::aligned_disjoint_words((HeapWord*)old, (HeapWord*)new_obj, sz); - assert(Universe::heap()->is_in_reserved(new_obj), "illegal forwarding pointer value."); + assert(GenCollectedHeap::heap()->is_in_reserved(new_obj), "illegal forwarding pointer value."); forward_ptr = old->forward_to_atomic(new_obj); // Restore the mark word copied above. new_obj->set_mark(m); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp --- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp Thu May 07 20:51:12 2015 -0700 @@ -27,7 +27,7 @@ #include "gc_implementation/parNew/parOopClosures.hpp" #include "gc_implementation/shared/gcTrace.hpp" -#include "gc_implementation/shared/parGCAllocBuffer.hpp" +#include "gc_implementation/shared/plab.hpp" #include "gc_implementation/shared/copyFailedInfo.hpp" #include "memory/defNewGeneration.hpp" #include "memory/padded.hpp" @@ -65,7 +65,7 @@ ObjToScanQueue *_work_queue; Stack* const _overflow_stack; - ParGCAllocBuffer _to_space_alloc_buffer; + PLAB _to_space_alloc_buffer; ParScanWithoutBarrierClosure _to_space_closure; // scan_without_gc_barrier ParScanWithBarrierClosure _old_gen_closure; // scan_with_gc_barrier @@ -140,7 +140,7 @@ ObjToScanQueue* work_queue() { return _work_queue; } - ParGCAllocBuffer* to_space_alloc_buffer() { + PLAB* to_space_alloc_buffer() { return &_to_space_alloc_buffer; } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parNew/parOopClosures.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/gc_implementation/parNew/parOopClosures.cpp Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "memory/iterator.inline.hpp" +#include "memory/specialized_oop_closures.hpp" +#include "gc_implementation/parNew/parOopClosures.inline.hpp" + +// Generate ParNew specialized oop_oop_iterate functions. +SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_P(ALL_KLASS_OOP_OOP_ITERATE_DEFN); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parNew/parOopClosures.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/parNew/parOopClosures.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parNew/parOopClosures.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -70,7 +70,7 @@ inline void ParScanClosure::do_oop_work(T* p, bool gc_barrier, bool root_scan) { - assert((!Universe::heap()->is_in_reserved(p) || + assert((!GenCollectedHeap::heap()->is_in_reserved(p) || generation()->is_in_reserved(p)) && (generation()->level() == 0 || gc_barrier), "The gen must be right, and we must be doing the barrier " @@ -82,7 +82,7 @@ #ifndef PRODUCT if (_g->to()->is_in_reserved(obj)) { tty->print_cr("Scanning field (" PTR_FORMAT ") twice?", p2i(p)); - GenCollectedHeap* gch = (GenCollectedHeap*)Universe::heap(); + GenCollectedHeap* gch = GenCollectedHeap::heap(); Space* sp = gch->space_containing(p); oop obj = oop(sp->block_start(p)); assert((HeapWord*)obj < (HeapWord*)p, "Error"); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSOldGen.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSOldGen.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSOldGen.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -89,7 +89,7 @@ assert(virtual_space()->is_aligned(gen_size_limit()), "not aligned"); assert(gen_size_limit() >= virtual_space()->committed_size(), "bad gen size"); - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); size_t result = gen_size_limit() - virtual_space()->committed_size(); size_t result_aligned = align_size_down(result, heap->generation_alignment()); return result_aligned; @@ -101,7 +101,7 @@ return uncommitted_bytes; } - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); const size_t gen_alignment = heap->generation_alignment(); PSAdaptiveSizePolicy* policy = heap->size_policy(); const size_t working_size = diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,7 +73,7 @@ size_t current_committed_size = virtual_space()->committed_size(); assert((gen_size_limit() >= current_committed_size), "generation size limit is wrong"); - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); size_t result = gen_size_limit() - current_committed_size; size_t result_aligned = align_size_down(result, heap->generation_alignment()); return result_aligned; @@ -91,7 +91,7 @@ if (eden_space()->is_empty()) { // Respect the minimum size for eden and for the young gen as a whole. - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); const size_t eden_alignment = heap->space_alignment(); const size_t gen_alignment = heap->generation_alignment(); @@ -128,7 +128,7 @@ // If to_space is below from_space, to_space is not considered. // to_space can be. size_t ASPSYoungGen::available_to_live() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); const size_t alignment = heap->space_alignment(); // Include any space that is committed but is not in eden. @@ -292,7 +292,7 @@ assert(eden_start < from_start, "Cannot push into from_space"); - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); const size_t alignment = heap->space_alignment(); const bool maintain_minimum = (requested_eden_size + 2 * requested_survivor_size) <= min_gen_size(); @@ -345,8 +345,6 @@ // Does the optimal to-space overlap from-space? if (to_start < (char*)from_space()->end()) { - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - // Calculate the minimum offset possible for from_end size_t from_size = pointer_delta(from_space()->top(), from_start, sizeof(char)); @@ -509,9 +507,7 @@ assert(from_space()->top() == old_from_top, "from top changed!"); if (PrintAdaptiveSizePolicy) { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); gclog_or_tty->print("AdaptiveSizePolicy::survivor space sizes: " "collection: %d " "(" SIZE_FORMAT ", " SIZE_FORMAT ") -> " @@ -542,7 +538,7 @@ } MemRegion cmr((HeapWord*)virtual_space()->low(), (HeapWord*)virtual_space()->high()); - Universe::heap()->barrier_set()->resize_covered_region(cmr); + ParallelScavengeHeap::heap()->barrier_set()->resize_covered_region(cmr); space_invariants(); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Thu May 07 20:51:12 2015 -0700 @@ -76,9 +76,7 @@ public: CheckForUnmarkedObjects() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _young_gen = heap->young_gen(); _card_table = barrier_set_cast(heap->barrier_set()); // No point in asserting barrier set type here. Need to make CardTableExtension @@ -325,9 +323,7 @@ void CardTableExtension::verify_all_young_refs_imprecise() { CheckForUnmarkedObjects check; - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSOldGen* old_gen = heap->old_gen(); old_gen->object_iterate(&check); @@ -335,9 +331,7 @@ // This should be called immediately after a scavenge, before mutators resume. void CardTableExtension::verify_all_young_refs_precise() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSOldGen* old_gen = heap->old_gen(); CheckForPreciseMarks check( @@ -351,7 +345,7 @@ void CardTableExtension::verify_all_young_refs_precise_helper(MemRegion mr) { CardTableExtension* card_table = - barrier_set_cast(Universe::heap()->barrier_set()); + barrier_set_cast(ParallelScavengeHeap::heap()->barrier_set()); jbyte* bot = card_table->byte_for(mr.start()); jbyte* top = card_table->byte_for(mr.end()); @@ -523,7 +517,7 @@ cur_committed = new_committed; } #ifdef ASSERT - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); assert(cur_committed.start() == (HeapWord*) align_size_up((uintptr_t) cur_committed.start(), os::vm_page_size()), diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Thu May 07 20:51:12 2015 -0700 @@ -49,42 +49,25 @@ PSOldGen* ParallelScavengeHeap::_old_gen = NULL; PSAdaptiveSizePolicy* ParallelScavengeHeap::_size_policy = NULL; PSGCAdaptivePolicyCounters* ParallelScavengeHeap::_gc_policy_counters = NULL; -ParallelScavengeHeap* ParallelScavengeHeap::_psh = NULL; GCTaskManager* ParallelScavengeHeap::_gc_task_manager = NULL; jint ParallelScavengeHeap::initialize() { CollectedHeap::pre_initialize(); - // Initialize collector policy - _collector_policy = new GenerationSizer(); - _collector_policy->initialize_all(); - const size_t heap_size = _collector_policy->max_heap_byte_size(); ReservedSpace heap_rs = Universe::reserve_heap(heap_size, _collector_policy->heap_alignment()); - MemTracker::record_virtual_memory_type((address)heap_rs.base(), mtJavaHeap); os::trace_page_sizes("ps main", _collector_policy->min_heap_byte_size(), heap_size, generation_alignment(), heap_rs.base(), heap_rs.size()); - if (!heap_rs.is_reserved()) { - vm_shutdown_during_initialization( - "Could not reserve enough space for object heap"); - return JNI_ENOMEM; - } initialize_reserved_region((HeapWord*)heap_rs.base(), (HeapWord*)(heap_rs.base() + heap_rs.size())); CardTableExtension* const barrier_set = new CardTableExtension(reserved_region()); barrier_set->initialize(); - _barrier_set = barrier_set; - oopDesc::set_bs(_barrier_set); - if (_barrier_set == NULL) { - vm_shutdown_during_initialization( - "Could not reserve enough space for barrier set"); - return JNI_ENOMEM; - } + set_barrier_set(barrier_set); // Make up the generations // Calculate the maximum size that a generation can grow. This @@ -120,7 +103,6 @@ // initialize the policy counters - 2 collectors, 3 generations _gc_policy_counters = new PSGCAdaptivePolicyCounters("ParScav:MSC", 2, 3, _size_policy); - _psh = this; // Set up the GCTaskManager _gc_task_manager = GCTaskManager::create(ParallelGCThreads); @@ -176,27 +158,11 @@ } bool ParallelScavengeHeap::is_in(const void* p) const { - if (young_gen()->is_in(p)) { - return true; - } - - if (old_gen()->is_in(p)) { - return true; - } - - return false; + return young_gen()->is_in(p) || old_gen()->is_in(p); } bool ParallelScavengeHeap::is_in_reserved(const void* p) const { - if (young_gen()->is_in_reserved(p)) { - return true; - } - - if (old_gen()->is_in_reserved(p)) { - return true; - } - - return false; + return young_gen()->is_in_reserved(p) || old_gen()->is_in_reserved(p); } bool ParallelScavengeHeap::is_scavengable(const void* addr) { @@ -265,7 +231,7 @@ // total_collections() value! { MutexLocker ml(Heap_lock); - gc_count = Universe::heap()->total_collections(); + gc_count = total_collections(); result = young_gen()->allocate(size); if (result != NULL) { @@ -315,8 +281,7 @@ // This prevents us from looping until time out on requests that can // not be satisfied. if (op.prologue_succeeded()) { - assert(Universe::heap()->is_in_or_null(op.result()), - "result not in heap"); + assert(is_in_or_null(op.result()), "result not in heap"); // If GC was locked out during VM operation then retry allocation // and/or stall as necessary. @@ -426,7 +391,7 @@ HeapWord* ParallelScavengeHeap::failed_mem_allocate(size_t size) { assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread"); - assert(!Universe::heap()->is_gc_active(), "not reentrant"); + assert(!is_gc_active(), "not reentrant"); assert(!Heap_lock->owned_by_self(), "this thread should not own the Heap_lock"); // We assume that allocation in eden will fail unless we collect. @@ -514,18 +479,14 @@ { MutexLocker ml(Heap_lock); // This value is guarded by the Heap_lock - gc_count = Universe::heap()->total_collections(); - full_gc_count = Universe::heap()->total_full_collections(); + gc_count = total_collections(); + full_gc_count = total_full_collections(); } VM_ParallelGCSystemGC op(gc_count, full_gc_count, cause); VMThread::execute(&op); } -void ParallelScavengeHeap::oop_iterate(ExtendedOopClosure* cl) { - Unimplemented(); -} - void ParallelScavengeHeap::object_iterate(ObjectClosure* cl) { young_gen()->object_iterate(cl); old_gen()->object_iterate(cl); @@ -661,9 +622,10 @@ } ParallelScavengeHeap* ParallelScavengeHeap::heap() { - assert(_psh != NULL, "Uninitialized access to ParallelScavengeHeap::heap()"); - assert(_psh->kind() == CollectedHeap::ParallelScavengeHeap, "not a parallel scavenge heap"); - return _psh; + CollectedHeap* heap = Universe::heap(); + assert(heap != NULL, "Uninitialized access to ParallelScavengeHeap::heap()"); + assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Not a ParallelScavengeHeap"); + return (ParallelScavengeHeap*)heap; } // Before delegating the resize to the young generation, diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp Thu May 07 20:51:12 2015 -0700 @@ -32,8 +32,9 @@ #include "gc_implementation/parallelScavenge/psYoungGen.hpp" #include "gc_implementation/shared/gcPolicyCounters.hpp" #include "gc_implementation/shared/gcWhen.hpp" -#include "gc_interface/collectedHeap.inline.hpp" +#include "gc_interface/collectedHeap.hpp" #include "memory/collectorPolicy.hpp" +#include "memory/strongRootsScope.hpp" #include "utilities/ostream.hpp" class AdjoiningGenerations; @@ -52,8 +53,6 @@ static PSAdaptiveSizePolicy* _size_policy; static PSGCAdaptivePolicyCounters* _gc_policy_counters; - static ParallelScavengeHeap* _psh; - GenerationSizer* _collector_policy; // Collection of generations that are adjacent in the @@ -75,7 +74,8 @@ HeapWord* mem_allocate_old_gen(size_t size); public: - ParallelScavengeHeap() : CollectedHeap(), _death_march_count(0) { } + ParallelScavengeHeap(GenerationSizer* policy) : + CollectedHeap(), _collector_policy(policy), _death_march_count(0) { } // For use by VM operations enum CollectionType { @@ -131,9 +131,6 @@ // the young gen. virtual bool is_scavengable(const void* addr); - // Does this heap support heap inspection? (+PrintClassHistogram) - bool supports_heap_inspection() const { return true; } - size_t max_capacity() const; // Whether p is in the allocated part of the heap @@ -201,7 +198,6 @@ // initializing stores to an object at this address. virtual bool can_elide_initializing_store_barrier(oop new_obj); - void oop_iterate(ExtendedOopClosure* cl); void object_iterate(ObjectClosure* cl); void safe_object_iterate(ObjectClosure* cl) { object_iterate(cl); } @@ -238,7 +234,7 @@ void gen_mangle_unused_area() PRODUCT_RETURN; // Call these in sequential code around the processing of strong roots. - class ParStrongRootsScope : public MarkingCodeBlobClosure::MarkScope { + class ParStrongRootsScope : public MarkScope { public: ParStrongRootsScope(); ~ParStrongRootsScope(); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp Thu May 07 20:51:12 2015 -0700 @@ -41,13 +41,14 @@ #include "runtime/thread.hpp" #include "runtime/vmThread.hpp" #include "services/management.hpp" +#include "utilities/stack.inline.hpp" // // ThreadRootsMarkingTask // void ThreadRootsMarkingTask::do_it(GCTaskManager* manager, uint which) { - assert(Universe::heap()->is_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); ResourceMark rm; @@ -78,7 +79,7 @@ void MarkFromRootsTask::do_it(GCTaskManager* manager, uint which) { - assert(Universe::heap()->is_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); NOT_PRODUCT(GCTraceTime tm("MarkFromRootsTask", PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); @@ -149,7 +150,7 @@ void RefProcTaskProxy::do_it(GCTaskManager* manager, uint which) { - assert(Universe::heap()->is_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); NOT_PRODUCT(GCTraceTime tm("RefProcTask", PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); @@ -167,7 +168,7 @@ void RefProcTaskExecutor::execute(ProcessTask& task) { - ParallelScavengeHeap* heap = PSParallelCompact::gc_heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); uint parallel_gc_threads = heap->gc_task_manager()->workers(); uint active_gc_threads = heap->gc_task_manager()->active_workers(); RegionTaskQueueSet* qset = ParCompactionManager::region_array(); @@ -188,7 +189,7 @@ void RefProcTaskExecutor::execute(EnqueueTask& task) { - ParallelScavengeHeap* heap = PSParallelCompact::gc_heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); uint parallel_gc_threads = heap->gc_task_manager()->workers(); GCTaskQueue* q = GCTaskQueue::create(); for(uint i=0; iis_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); NOT_PRODUCT(GCTraceTime tm("StealMarkingTask", PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); @@ -237,7 +238,7 @@ _terminator(t) {} void StealRegionCompactionTask::do_it(GCTaskManager* manager, uint which) { - assert(Universe::heap()->is_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); NOT_PRODUCT(GCTraceTime tm("StealRegionCompactionTask", PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); @@ -319,7 +320,7 @@ } void DrainStacksCompactionTask::do_it(GCTaskManager* manager, uint which) { - assert(Universe::heap()->is_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); NOT_PRODUCT(GCTraceTime tm("DrainStacksCompactionTask", PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.cpp Thu May 07 20:51:12 2015 -0700 @@ -30,7 +30,10 @@ #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" #include "gc_implementation/parallelScavenge/psCompactionManager.inline.hpp" #include "gc_implementation/parallelScavenge/psOldGen.hpp" -#include "gc_implementation/parallelScavenge/psParallelCompact.hpp" +#include "gc_implementation/parallelScavenge/psParallelCompact.inline.hpp" +#include "memory/iterator.inline.hpp" +#include "oops/instanceKlass.inline.hpp" +#include "oops/instanceMirrorKlass.inline.hpp" #include "oops/objArrayKlass.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.inline.hpp" @@ -57,8 +60,7 @@ _region_stack(NULL), _region_stack_index((uint)max_uintx) { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _old_gen = heap->old_gen(); _start_array = old_gen()->start_array(); @@ -174,6 +176,142 @@ return _manager_array[index]; } +void InstanceKlass::oop_pc_follow_contents(oop obj, ParCompactionManager* cm) { + assert(obj != NULL, "can't follow the content of NULL object"); + + PSParallelCompact::follow_klass(cm, this); + // Only mark the header and let the scan of the meta-data mark + // everything else. + + PSParallelCompact::MarkAndPushClosure cl(cm); + InstanceKlass::oop_oop_iterate_oop_maps(obj, &cl); +} + +void InstanceMirrorKlass::oop_pc_follow_contents(oop obj, ParCompactionManager* cm) { + InstanceKlass::oop_pc_follow_contents(obj, cm); + + // Follow the klass field in the mirror. + Klass* klass = java_lang_Class::as_Klass(obj); + if (klass != NULL) { + // An anonymous class doesn't have its own class loader, so the call + // to follow_klass will mark and push its java mirror instead of the + // class loader. When handling the java mirror for an anonymous class + // we need to make sure its class loader data is claimed, this is done + // by calling follow_class_loader explicitly. For non-anonymous classes + // the call to follow_class_loader is made when the class loader itself + // is handled. + if (klass->oop_is_instance() && InstanceKlass::cast(klass)->is_anonymous()) { + PSParallelCompact::follow_class_loader(cm, klass->class_loader_data()); + } else { + PSParallelCompact::follow_klass(cm, klass); + } + } else { + // If klass is NULL then this a mirror for a primitive type. + // We don't have to follow them, since they are handled as strong + // roots in Universe::oops_do. + assert(java_lang_Class::is_primitive(obj), "Sanity check"); + } + + PSParallelCompact::MarkAndPushClosure cl(cm); + oop_oop_iterate_statics(obj, &cl); +} + +void InstanceClassLoaderKlass::oop_pc_follow_contents(oop obj, ParCompactionManager* cm) { + InstanceKlass::oop_pc_follow_contents(obj, cm); + + ClassLoaderData * const loader_data = java_lang_ClassLoader::loader_data(obj); + if (loader_data != NULL) { + PSParallelCompact::follow_class_loader(cm, loader_data); + } +} + +template +static void oop_pc_follow_contents_specialized(InstanceRefKlass* klass, oop obj, ParCompactionManager* cm) { + T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); + T heap_oop = oopDesc::load_heap_oop(referent_addr); + debug_only( + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr("InstanceRefKlass::oop_pc_follow_contents " PTR_FORMAT, p2i(obj)); + } + ) + if (!oopDesc::is_null(heap_oop)) { + oop referent = oopDesc::decode_heap_oop_not_null(heap_oop); + if (PSParallelCompact::mark_bitmap()->is_unmarked(referent) && + PSParallelCompact::ref_processor()->discover_reference(obj, klass->reference_type())) { + // reference already enqueued, referent will be traversed later + klass->InstanceKlass::oop_pc_follow_contents(obj, cm); + debug_only( + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr(" Non NULL enqueued " PTR_FORMAT, p2i(obj)); + } + ) + return; + } else { + // treat referent as normal oop + debug_only( + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr(" Non NULL normal " PTR_FORMAT, p2i(obj)); + } + ) + PSParallelCompact::mark_and_push(cm, referent_addr); + } + } + T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); + if (ReferenceProcessor::pending_list_uses_discovered_field()) { + // Treat discovered as normal oop, if ref is not "active", + // i.e. if next is non-NULL. + T next_oop = oopDesc::load_heap_oop(next_addr); + if (!oopDesc::is_null(next_oop)) { // i.e. ref is not "active" + T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); + debug_only( + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr(" Process discovered as normal " + PTR_FORMAT, p2i(discovered_addr)); + } + ) + PSParallelCompact::mark_and_push(cm, discovered_addr); + } + } else { +#ifdef ASSERT + // In the case of older JDKs which do not use the discovered + // field for the pending list, an inactive ref (next != NULL) + // must always have a NULL discovered field. + T next = oopDesc::load_heap_oop(next_addr); + oop discovered = java_lang_ref_Reference::discovered(obj); + assert(oopDesc::is_null(next) || oopDesc::is_null(discovered), + err_msg("Found an inactive reference " PTR_FORMAT " with a non-NULL discovered field", + p2i(obj))); +#endif + } + PSParallelCompact::mark_and_push(cm, next_addr); + klass->InstanceKlass::oop_pc_follow_contents(obj, cm); +} + + +void InstanceRefKlass::oop_pc_follow_contents(oop obj, ParCompactionManager* cm) { + if (UseCompressedOops) { + oop_pc_follow_contents_specialized(this, obj, cm); + } else { + oop_pc_follow_contents_specialized(this, obj, cm); + } +} + +void ObjArrayKlass::oop_pc_follow_contents(oop obj, ParCompactionManager* cm) { + PSParallelCompact::follow_klass(cm, this); + + if (UseCompressedOops) { + oop_pc_follow_contents_specialized(objArrayOop(obj), 0, cm); + } else { + oop_pc_follow_contents_specialized(objArrayOop(obj), 0, cm); + } +} + +void TypeArrayKlass::oop_pc_follow_contents(oop obj, ParCompactionManager* cm) { + assert(obj->is_typeArray(),"must be a type array"); + // Performance tweak: We skip iterating over the klass pointer since we + // know that Universe::TypeArrayKlass never moves. +} + void ParCompactionManager::follow_marking_stacks() { do { // Drain the overflow stack first, to allow stealing from the marking stack. diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -26,9 +26,11 @@ #define SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSCOMPACTIONMANAGER_INLINE_HPP #include "gc_implementation/parallelScavenge/psCompactionManager.hpp" -#include "gc_implementation/parallelScavenge/psParallelCompact.hpp" -#include "oops/objArrayKlass.inline.hpp" -#include "oops/oop.pcgc.inline.hpp" +#include "gc_implementation/parallelScavenge/psParallelCompact.inline.hpp" +#include "oops/objArrayOop.hpp" +#include "oops/oop.inline.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" void ParCompactionManager::push_objarray(oop obj, size_t index) { @@ -49,16 +51,42 @@ } inline void ParCompactionManager::follow_contents(oop obj) { - obj->follow_contents(this); + assert(PSParallelCompact::mark_bitmap()->is_marked(obj), "should be marked"); + obj->pc_follow_contents(this); +} + +template +inline void oop_pc_follow_contents_specialized(objArrayOop obj, int index, ParCompactionManager* cm) { + const size_t len = size_t(obj->length()); + const size_t beg_index = size_t(index); + assert(beg_index < len || len == 0, "index too large"); + + const size_t stride = MIN2(len - beg_index, ObjArrayMarkingStride); + const size_t end_index = beg_index + stride; + T* const base = (T*)obj->base(); + T* const beg = base + beg_index; + T* const end = base + end_index; + + // Push the non-NULL elements of the next stride on the marking stack. + for (T* e = beg; e < end; e++) { + PSParallelCompact::mark_and_push(cm, e); + } + + if (end_index < len) { + cm->push_objarray(obj, end_index); // Push the continuation. + } } inline void ParCompactionManager::follow_contents(objArrayOop obj, int index) { - ObjArrayKlass* k = (ObjArrayKlass*)obj->klass(); - k->oop_follow_contents(this, obj, index); + if (UseCompressedOops) { + oop_pc_follow_contents_specialized(obj, index, this); + } else { + oop_pc_follow_contents_specialized(obj, index, this); + } } inline void ParCompactionManager::update_contents(oop obj) { - obj->update_contents(this); + obj->pc_update_contents(); } #endif // SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSCOMPACTIONMANAGER_INLINE_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Thu May 07 20:51:12 2015 -0700 @@ -59,7 +59,7 @@ CollectorCounters* PSMarkSweep::_counters = NULL; void PSMarkSweep::initialize() { - MemRegion mr = Universe::heap()->reserved_region(); + MemRegion mr = ParallelScavengeHeap::heap()->reserved_region(); _ref_processor = new ReferenceProcessor(mr); // a vanilla ref proc _counters = new CollectorCounters("PSMarkSweep", 1); } @@ -81,9 +81,9 @@ void PSMarkSweep::invoke(bool maximum_heap_compaction) { assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread"); - assert(!Universe::heap()->is_gc_active(), "not reentrant"); + assert(!ParallelScavengeHeap::heap()->is_gc_active(), "not reentrant"); - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); GCCause::Cause gc_cause = heap->gc_cause(); PSAdaptiveSizePolicy* policy = heap->size_policy(); IsGCActiveMark mark; @@ -110,8 +110,7 @@ return false; } - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); GCCause::Cause gc_cause = heap->gc_cause(); _gc_timer->register_gc_start(); @@ -487,9 +486,7 @@ } void PSMarkSweep::allocate_stacks() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSYoungGen* young_gen = heap->young_gen(); MutableSpace* to_space = young_gen->to_space(); @@ -513,10 +510,8 @@ void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) { // Recursively traverse all live objects and mark them GCTraceTime tm("phase 1", PrintGCDetails && Verbose, true, _gc_timer, _gc_tracer->gc_id()); - trace(" 1"); - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); // Need to clear claim bits before the tracing starts. ClassLoaderDataGraph::clear_claimed_marks(); @@ -574,7 +569,6 @@ void PSMarkSweep::mark_sweep_phase2() { GCTraceTime tm("phase 2", PrintGCDetails && Verbose, true, _gc_timer, _gc_tracer->gc_id()); - trace("2"); // Now all live objects are marked, compute the new object addresses. @@ -582,9 +576,7 @@ // phase2, phase3 and phase4, but the ValidateMarkSweep live oops // tracking expects us to do so. See comment under phase4. - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSOldGen* old_gen = heap->old_gen(); // Begin compacting into the old gen @@ -604,11 +596,8 @@ void PSMarkSweep::mark_sweep_phase3() { // Adjust the pointers to reflect the new locations GCTraceTime tm("phase 3", PrintGCDetails && Verbose, true, _gc_timer, _gc_tracer->gc_id()); - trace("3"); - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSYoungGen* young_gen = heap->young_gen(); PSOldGen* old_gen = heap->old_gen(); @@ -647,13 +636,10 @@ void PSMarkSweep::mark_sweep_phase4() { EventMark m("4 compact heap"); GCTraceTime tm("phase 4", PrintGCDetails && Verbose, true, _gc_timer, _gc_tracer->gc_id()); - trace("4"); // All pointers are now adjusted, move objects accordingly - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSYoungGen* young_gen = heap->young_gen(); PSOldGen* old_gen = heap->old_gen(); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp Thu May 07 20:51:12 2015 -0700 @@ -38,15 +38,12 @@ void PSMarkSweepDecorator::set_destination_decorator_tenured() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _destination_decorator = heap->old_gen()->object_mark_sweep(); } void PSMarkSweepDecorator::advance_destination_decorator() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); assert(_destination_decorator != NULL, "Sanity"); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp Thu May 07 20:51:12 2015 -0700 @@ -107,20 +107,22 @@ SpaceMangler::mangle_region(cmr); } - Universe::heap()->barrier_set()->resize_covered_region(cmr); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); + BarrierSet* bs = heap->barrier_set(); - CardTableModRefBS* _ct = - barrier_set_cast(Universe::heap()->barrier_set()); + bs->resize_covered_region(cmr); + + CardTableModRefBS* ct = barrier_set_cast(bs); // Verify that the start and end of this generation is the start of a card. // If this wasn't true, a single card could span more than one generation, // which would cause problems when we commit/uncommit memory, and when we // clear and dirty cards. - guarantee(_ct->is_card_aligned(_reserved.start()), "generation must be card aligned"); - if (_reserved.end() != Universe::heap()->reserved_region().end()) { + guarantee(ct->is_card_aligned(_reserved.start()), "generation must be card aligned"); + if (_reserved.end() != heap->reserved_region().end()) { // Don't check at the very end of the heap as we'll assert that we're probing off // the end if we try. - guarantee(_ct->is_card_aligned(_reserved.end()), "generation must be card aligned"); + guarantee(ct->is_card_aligned(_reserved.end()), "generation must be card aligned"); } // @@ -161,8 +163,7 @@ } void PSOldGen::precompact() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); // Reset start array first. start_array()->reset(); @@ -197,7 +198,7 @@ // Allocations in the old generation need to be reported if (res != NULL) { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); heap->size_policy()->tenured_allocation(word_size); } @@ -376,8 +377,7 @@ } if (PrintAdaptiveSizePolicy) { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); gclog_or_tty->print_cr("AdaptiveSizePolicy::old generation size: " "collection: %d " "(" SIZE_FORMAT ") -> (" SIZE_FORMAT ") ", @@ -397,7 +397,7 @@ size_t new_word_size = new_memregion.word_size(); start_array()->set_covered_region(new_memregion); - Universe::heap()->barrier_set()->resize_covered_region(new_memregion); + ParallelScavengeHeap::heap()->barrier_set()->resize_covered_region(new_memregion); // ALWAYS do this last!! object_space()->initialize(new_memregion, diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,11 +60,29 @@ // Used when initializing the _name field. static inline const char* select_name(); +#ifdef ASSERT + void assert_block_in_covered_region(MemRegion new_memregion) { + // Explictly capture current covered_region in a local + MemRegion covered_region = this->start_array()->covered_region(); + assert(covered_region.contains(new_memregion), + err_msg("new region is not in covered_region [ "PTR_FORMAT", "PTR_FORMAT" ], " + "new region [ "PTR_FORMAT", "PTR_FORMAT" ], " + "object space [ "PTR_FORMAT", "PTR_FORMAT" ]", + p2i(covered_region.start()), + p2i(covered_region.end()), + p2i(new_memregion.start()), + p2i(new_memregion.end()), + p2i(this->object_space()->used_region().start()), + p2i(this->object_space()->used_region().end()))); + } +#endif + HeapWord* allocate_noexpand(size_t word_size) { // We assume the heap lock is held here. assert_locked_or_safepoint(Heap_lock); HeapWord* res = object_space()->allocate(word_size); if (res != NULL) { + DEBUG_ONLY(assert_block_in_covered_region(MemRegion(res, word_size))); _start_array.allocate_block(res); } return res; @@ -77,6 +95,7 @@ assert(SafepointSynchronize::is_at_safepoint(), "Must only be called at safepoint"); HeapWord* res = object_space()->cas_allocate(word_size); if (res != NULL) { + DEBUG_ONLY(assert_block_in_covered_region(MemRegion(res, word_size))); _start_array.allocate_block(res); } return res; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Thu May 07 20:51:12 2015 -0700 @@ -34,7 +34,7 @@ #include "gc_implementation/parallelScavenge/psMarkSweep.hpp" #include "gc_implementation/parallelScavenge/psMarkSweepDecorator.hpp" #include "gc_implementation/parallelScavenge/psOldGen.hpp" -#include "gc_implementation/parallelScavenge/psParallelCompact.hpp" +#include "gc_implementation/parallelScavenge/psParallelCompact.inline.hpp" #include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" #include "gc_implementation/parallelScavenge/psScavenge.hpp" #include "gc_implementation/parallelScavenge/psYoungGen.hpp" @@ -48,7 +48,10 @@ #include "memory/gcLocker.inline.hpp" #include "memory/referencePolicy.hpp" #include "memory/referenceProcessor.hpp" +#include "oops/instanceKlass.inline.hpp" +#include "oops/instanceMirrorKlass.inline.hpp" #include "oops/methodData.hpp" +#include "oops/objArrayKlass.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/fprofiler.hpp" @@ -745,7 +748,7 @@ HeapWord* ParallelCompactData::calc_new_pointer(HeapWord* addr) { assert(addr != NULL, "Should detect NULL oop earlier"); - assert(PSParallelCompact::gc_heap()->is_in(addr), "not in heap"); + assert(ParallelScavengeHeap::heap()->is_in(addr), "not in heap"); assert(PSParallelCompact::mark_bitmap()->is_marked(addr), "not marked"); // Region covering the object. @@ -823,16 +826,8 @@ PSParallelCompact::AdjustPointerClosure PSParallelCompact::_adjust_pointer_closure; PSParallelCompact::AdjustKlassClosure PSParallelCompact::_adjust_klass_closure; -void PSParallelCompact::AdjustPointerClosure::do_oop(oop* p) { adjust_pointer(p); } -void PSParallelCompact::AdjustPointerClosure::do_oop(narrowOop* p) { adjust_pointer(p); } - void PSParallelCompact::FollowStackClosure::do_void() { _compaction_manager->follow_marking_stacks(); } -void PSParallelCompact::MarkAndPushClosure::do_oop(oop* p) { - mark_and_push(_compaction_manager, p); -} -void PSParallelCompact::MarkAndPushClosure::do_oop(narrowOop* p) { mark_and_push(_compaction_manager, p); } - void PSParallelCompact::FollowKlassClosure::do_klass(Klass* klass) { klass->oops_do(_mark_and_push_closure); } @@ -841,9 +836,7 @@ } void PSParallelCompact::post_initialize() { - ParallelScavengeHeap* heap = gc_heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); MemRegion mr = heap->reserved_region(); _ref_processor = new ReferenceProcessor(mr, // span @@ -860,8 +853,7 @@ } bool PSParallelCompact::initialize() { - ParallelScavengeHeap* heap = gc_heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); MemRegion mr = heap->reserved_region(); // Was the old gen get allocated successfully? @@ -895,7 +887,7 @@ { memset(&_space_info, 0, sizeof(_space_info)); - ParallelScavengeHeap* heap = gc_heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSYoungGen* young_gen = heap->young_gen(); _space_info[old_space_id].set_space(heap->old_gen()->object_space()); @@ -978,7 +970,7 @@ // promotion failure does not swap spaces) because an unknown number of minor // collections will have swapped the spaces an unknown number of times. GCTraceTime tm("pre compact", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); - ParallelScavengeHeap* heap = gc_heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _space_info[from_space_id].set_space(heap->young_gen()->from_space()); _space_info[to_space_id].set_space(heap->young_gen()->to_space()); @@ -1033,7 +1025,7 @@ MutableSpace* const from_space = _space_info[from_space_id].space(); MutableSpace* const to_space = _space_info[to_space_id].space(); - ParallelScavengeHeap* heap = gc_heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); bool eden_empty = eden_space->is_empty(); if (!eden_empty) { eden_empty = absorb_live_data_from_eden(heap->size_policy(), @@ -1971,7 +1963,7 @@ assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread"); - ParallelScavengeHeap* heap = gc_heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); GCCause::Cause gc_cause = heap->gc_cause(); assert(!heap->is_gc_active(), "not reentrant"); @@ -1999,7 +1991,7 @@ return false; } - ParallelScavengeHeap* heap = gc_heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _gc_timer.register_gc_start(); _gc_tracer.report_gc_start(heap->gc_cause(), _gc_timer.gc_start()); @@ -2352,7 +2344,7 @@ // Recursively traverse all live objects and mark them GCTraceTime tm("marking phase", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); - ParallelScavengeHeap* heap = gc_heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); uint parallel_gc_threads = heap->gc_task_manager()->workers(); uint active_gc_threads = heap->gc_task_manager()->active_workers(); TaskQueueSetSuper* qset = ParCompactionManager::region_array(); @@ -2692,8 +2684,7 @@ // trace("5"); GCTraceTime tm("compaction phase", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSOldGen* old_gen = heap->old_gen(); old_gen->start_array()->reset(); uint parallel_gc_threads = heap->gc_task_manager()->workers(); @@ -2844,7 +2835,7 @@ // heap, last_space_id is returned. In debug mode it expects the address to be // in the heap and asserts such. PSParallelCompact::SpaceId PSParallelCompact::space_id(HeapWord* addr) { - assert(Universe::heap()->is_in_reserved(addr), "addr not in the heap"); + assert(ParallelScavengeHeap::heap()->is_in_reserved(addr), "addr not in the heap"); for (unsigned int id = old_space_id; id < last_space_id; ++id) { if (_space_info[id].space()->contains(addr)) { @@ -3338,6 +3329,71 @@ update_state(words); } +void InstanceKlass::oop_pc_update_pointers(oop obj) { + oop_oop_iterate_oop_maps(obj, PSParallelCompact::adjust_pointer_closure()); +} + +void InstanceMirrorKlass::oop_pc_update_pointers(oop obj) { + InstanceKlass::oop_pc_update_pointers(obj); + + oop_oop_iterate_statics(obj, PSParallelCompact::adjust_pointer_closure()); +} + +void InstanceClassLoaderKlass::oop_pc_update_pointers(oop obj) { + InstanceKlass::oop_pc_update_pointers(obj); +} + +#ifdef ASSERT +template static void trace_reference_gc(const char *s, oop obj, + T* referent_addr, + T* next_addr, + T* discovered_addr) { + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr("%s obj " PTR_FORMAT, s, p2i(obj)); + gclog_or_tty->print_cr(" referent_addr/* " PTR_FORMAT " / " + PTR_FORMAT, p2i(referent_addr), + referent_addr ? p2i(oopDesc::load_decode_heap_oop(referent_addr)) : NULL); + gclog_or_tty->print_cr(" next_addr/* " PTR_FORMAT " / " + PTR_FORMAT, p2i(next_addr), + next_addr ? p2i(oopDesc::load_decode_heap_oop(next_addr)) : NULL); + gclog_or_tty->print_cr(" discovered_addr/* " PTR_FORMAT " / " + PTR_FORMAT, p2i(discovered_addr), + discovered_addr ? p2i(oopDesc::load_decode_heap_oop(discovered_addr)) : NULL); + } +} +#endif + +template +static void oop_pc_update_pointers_specialized(oop obj) { + T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); + PSParallelCompact::adjust_pointer(referent_addr); + T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); + PSParallelCompact::adjust_pointer(next_addr); + T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); + PSParallelCompact::adjust_pointer(discovered_addr); + debug_only(trace_reference_gc("InstanceRefKlass::oop_update_ptrs", obj, + referent_addr, next_addr, discovered_addr);) +} + +void InstanceRefKlass::oop_pc_update_pointers(oop obj) { + InstanceKlass::oop_pc_update_pointers(obj); + + if (UseCompressedOops) { + oop_pc_update_pointers_specialized(obj); + } else { + oop_pc_update_pointers_specialized(obj); + } +} + +void ObjArrayKlass::oop_pc_update_pointers(oop obj) { + assert(obj->is_objArray(), "obj must be obj array"); + oop_oop_iterate_elements(objArrayOop(obj), PSParallelCompact::adjust_pointer_closure()); +} + +void TypeArrayKlass::oop_pc_update_pointers(oop obj) { + assert(obj->is_typeArray(),"must be a type array"); +} + ParMarkBitMapClosure::IterationStatus MoveAndUpdateClosure::do_addr(HeapWord* addr, size_t words) { assert(destination() != NULL, "sanity"); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Thu May 07 20:51:12 2015 -0700 @@ -26,11 +26,12 @@ #define SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSPARALLELCOMPACT_HPP #include "gc_implementation/parallelScavenge/objectStartArray.hpp" +#include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" #include "gc_implementation/parallelScavenge/parMarkBitMap.hpp" #include "gc_implementation/parallelScavenge/psCompactionManager.hpp" #include "gc_implementation/shared/collectorCounters.hpp" #include "gc_implementation/shared/mutableSpace.hpp" -#include "memory/sharedHeap.hpp" +#include "gc_interface/collectedHeap.hpp" #include "oops/oop.hpp" class ParallelScavengeHeap; @@ -951,12 +952,14 @@ virtual void do_void(); }; - class AdjustPointerClosure: public OopClosure { + class AdjustPointerClosure: public ExtendedOopClosure { public: + template void do_oop_nv(T* p); virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); - // do not walk from thread stacks to the code cache on this phase - virtual void do_code_blob(CodeBlob* cb) const { } + + // This closure provides its own oop verification code. + debug_only(virtual bool should_verify_oops() { return false; }) }; class AdjustKlassClosure : public KlassClosure { @@ -1139,13 +1142,18 @@ static void reset_millis_since_last_gc(); public: - class MarkAndPushClosure: public OopClosure { + class MarkAndPushClosure: public ExtendedOopClosure { private: ParCompactionManager* _compaction_manager; public: MarkAndPushClosure(ParCompactionManager* cm) : _compaction_manager(cm) { } + + template void do_oop_nv(T* p); virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); + + // This closure provides its own oop verification code. + debug_only(virtual bool should_verify_oops() { return false; }) }; // The one and only place to start following the classes. @@ -1161,11 +1169,6 @@ PSParallelCompact(); - // Convenient accessor for Universe::heap(). - static ParallelScavengeHeap* gc_heap() { - return (ParallelScavengeHeap*)Universe::heap(); - } - static void invoke(bool maximum_heap_compaction); static bool invoke_no_policy(bool maximum_heap_compaction); @@ -1177,7 +1180,9 @@ static bool initialize(); // Closure accessors - static OopClosure* adjust_pointer_closure() { return (OopClosure*)&_adjust_pointer_closure; } + static PSParallelCompact::AdjustPointerClosure* adjust_pointer_closure() { + return &_adjust_pointer_closure; + } static KlassClosure* adjust_klass_closure() { return (KlassClosure*)&_adjust_klass_closure; } static BoolObjectClosure* is_alive_closure() { return (BoolObjectClosure*)&_is_alive_closure; } @@ -1333,39 +1338,6 @@ } template -inline void PSParallelCompact::mark_and_push(ParCompactionManager* cm, T* p) { - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop)) { - oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); - if (mark_bitmap()->is_unmarked(obj) && mark_obj(obj)) { - cm->push(obj); - } - } -} - -template -inline void PSParallelCompact::adjust_pointer(T* p) { - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop)) { - oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); - oop new_obj = (oop)summary_data().calc_new_pointer(obj); - assert(new_obj != NULL, // is forwarding ptr? - "should be forwarded"); - // Just always do the update unconditionally? - if (new_obj != NULL) { - assert(Universe::heap()->is_in_reserved(new_obj), - "should be in object space"); - oopDesc::encode_store_heap_oop_not_null(p, new_obj); - } - } -} - -inline void PSParallelCompact::follow_klass(ParCompactionManager* cm, Klass* klass) { - oop holder = klass->klass_holder(); - PSParallelCompact::mark_and_push(cm, &holder); -} - -template inline void PSParallelCompact::KeepAliveClosure::do_oop_work(T* p) { mark_and_push(_compaction_manager, p); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.inline.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSPARALLELCOMPACT_INLINE_HPP +#define SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSPARALLELCOMPACT_INLINE_HPP + +#include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" +#include "gc_implementation/parallelScavenge/psCompactionManager.hpp" +#include "gc_implementation/parallelScavenge/psParallelCompact.hpp" +#include "gc_interface/collectedHeap.hpp" +#include "oops/klass.hpp" +#include "oops/oop.inline.hpp" + +template +inline void PSParallelCompact::mark_and_push(ParCompactionManager* cm, T* p) { + T heap_oop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(heap_oop)) { + oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); + assert(ParallelScavengeHeap::heap()->is_in(obj), "should be in heap"); + + if (mark_bitmap()->is_unmarked(obj) && mark_obj(obj)) { + cm->push(obj); + } + } +} + +template +inline void PSParallelCompact::MarkAndPushClosure::do_oop_nv(T* p) { + mark_and_push(_compaction_manager, p); +} + +inline void PSParallelCompact::MarkAndPushClosure::do_oop(oop* p) { do_oop_nv(p); } +inline void PSParallelCompact::MarkAndPushClosure::do_oop(narrowOop* p) { do_oop_nv(p); } + +inline void PSParallelCompact::follow_klass(ParCompactionManager* cm, Klass* klass) { + oop holder = klass->klass_holder(); + mark_and_push(cm, &holder); +} + +template +inline void PSParallelCompact::adjust_pointer(T* p) { + T heap_oop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(heap_oop)) { + oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); + assert(ParallelScavengeHeap::heap()->is_in(obj), "should be in heap"); + + oop new_obj = (oop)summary_data().calc_new_pointer(obj); + assert(new_obj != NULL, // is forwarding ptr? + "should be forwarded"); + // Just always do the update unconditionally? + if (new_obj != NULL) { + assert(ParallelScavengeHeap::heap()->is_in_reserved(new_obj), + "should be in object space"); + oopDesc::encode_store_heap_oop_not_null(p, new_obj); + } + } +} + +template +void PSParallelCompact::AdjustPointerClosure::do_oop_nv(T* p) { + adjust_pointer(p); +} + +inline void PSParallelCompact::AdjustPointerClosure::do_oop(oop* p) { do_oop_nv(p); } +inline void PSParallelCompact::AdjustPointerClosure::do_oop(narrowOop* p) { do_oop_nv(p); } + +#endif // SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSPARALLELCOMPACT_INLINE_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionLAB.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionLAB.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionLAB.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -103,7 +103,7 @@ } bool PSPromotionLAB::unallocate_object(HeapWord* obj, size_t obj_size) { - assert(Universe::heap()->is_in(obj), "Object outside heap"); + assert(ParallelScavengeHeap::heap()->is_in(obj), "Object outside heap"); if (contains(obj)) { HeapWord* object_end = obj + obj_size; @@ -137,9 +137,7 @@ #ifdef ASSERT bool PSYoungPromotionLAB::lab_is_valid(MemRegion lab) { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); MutableSpace* to_space = heap->young_gen()->to_space(); MemRegion used = to_space->used_region(); if (used.contains(lab)) { @@ -150,10 +148,9 @@ } bool PSOldPromotionLAB::lab_is_valid(MemRegion lab) { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); assert(_start_array->covered_region().contains(lab), "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSOldGen* old_gen = heap->old_gen(); MemRegion used = old_gen->object_space()->used_region(); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionLAB.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionLAB.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionLAB.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ #define SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSPROMOTIONLAB_HPP #include "gc_implementation/parallelScavenge/objectStartArray.hpp" -#include "gc_interface/collectedHeap.inline.hpp" +#include "gc_interface/collectedHeap.hpp" #include "memory/allocation.hpp" // @@ -59,7 +59,7 @@ // The shared initialize code invokes this. debug_only(virtual bool lab_is_valid(MemRegion lab) { return false; }); - PSPromotionLAB() : _top(NULL), _bottom(NULL), _end(NULL) { } + PSPromotionLAB() : _top(NULL), _bottom(NULL), _end(NULL), _state(zero_size) { } public: // Filling and flushing. diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp Thu May 07 20:51:12 2015 -0700 @@ -32,6 +32,9 @@ #include "memory/allocation.inline.hpp" #include "memory/memRegion.hpp" #include "memory/padded.inline.hpp" +#include "oops/instanceKlass.inline.hpp" +#include "oops/instanceMirrorKlass.inline.hpp" +#include "oops/objArrayKlass.inline.hpp" #include "oops/oop.inline.hpp" #include "utilities/stack.inline.hpp" @@ -41,8 +44,7 @@ MutableSpace* PSPromotionManager::_young_space = NULL; void PSPromotionManager::initialize() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _old_gen = heap->old_gen(); _young_space = heap->young_gen()->to_space(); @@ -85,8 +87,7 @@ } void PSPromotionManager::pre_scavenge() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _young_space = heap->young_gen()->to_space(); @@ -129,7 +130,7 @@ void PSPromotionManager::print_taskqueue_stats(outputStream* const out) { out->print_cr("== GC Tasks Stats, GC %3d", - Universe::heap()->total_collections()); + ParallelScavengeHeap::heap()->total_collections()); TaskQueueStats totals; out->print("thr "); TaskQueueStats::print_header(1, out); out->cr(); @@ -157,8 +158,7 @@ #endif // TASKQUEUE_STATS PSPromotionManager::PSPromotionManager() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); // We set the old lab's start array. _old_lab.set_start_array(old_gen()->start_array()); @@ -188,8 +188,7 @@ // We need to get an assert in here to make sure the labs are always flushed. - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); // Do not prefill the LAB's, save heap wastage! HeapWord* lab_base = young_space()->top(); @@ -210,8 +209,7 @@ totally_drain = totally_drain || _totally_drain; #ifdef ASSERT - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); MutableSpace* to_space = heap->young_gen()->to_space(); MutableSpace* old_space = heap->old_gen()->object_space(); #endif /* ASSERT */ @@ -308,6 +306,118 @@ } } +class PushContentsClosure : public ExtendedOopClosure { + PSPromotionManager* _pm; + public: + PushContentsClosure(PSPromotionManager* pm) : _pm(pm) {} + + template void do_oop_nv(T* p) { + if (PSScavenge::should_scavenge(p)) { + _pm->claim_or_forward_depth(p); + } + } + + virtual void do_oop(oop* p) { do_oop_nv(p); } + virtual void do_oop(narrowOop* p) { do_oop_nv(p); } + + // Don't use the oop verification code in the oop_oop_iterate framework. + debug_only(virtual bool should_verify_oops() { return false; }) +}; + +void InstanceKlass::oop_ps_push_contents(oop obj, PSPromotionManager* pm) { + PushContentsClosure cl(pm); + oop_oop_iterate_oop_maps_reverse(obj, &cl); +} + +void InstanceMirrorKlass::oop_ps_push_contents(oop obj, PSPromotionManager* pm) { + // Note that we don't have to follow the mirror -> klass pointer, since all + // klasses that are dirty will be scavenged when we iterate over the + // ClassLoaderData objects. + + InstanceKlass::oop_ps_push_contents(obj, pm); + + PushContentsClosure cl(pm); + oop_oop_iterate_statics(obj, &cl); +} + +void InstanceClassLoaderKlass::oop_ps_push_contents(oop obj, PSPromotionManager* pm) { + InstanceKlass::oop_ps_push_contents(obj, pm); + + // This is called by the young collector. It will already have taken care of + // all class loader data. So, we don't have to follow the class loader -> + // class loader data link. +} + +template +static void oop_ps_push_contents_specialized(oop obj, InstanceRefKlass *klass, PSPromotionManager* pm) { + T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); + if (PSScavenge::should_scavenge(referent_addr)) { + ReferenceProcessor* rp = PSScavenge::reference_processor(); + if (rp->discover_reference(obj, klass->reference_type())) { + // reference already enqueued, referent and next will be traversed later + klass->InstanceKlass::oop_ps_push_contents(obj, pm); + return; + } else { + // treat referent as normal oop + pm->claim_or_forward_depth(referent_addr); + } + } + // Treat discovered as normal oop, if ref is not "active", + // i.e. if next is non-NULL. + T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); + if (ReferenceProcessor::pending_list_uses_discovered_field()) { + T next_oop = oopDesc::load_heap_oop(next_addr); + if (!oopDesc::is_null(next_oop)) { // i.e. ref is not "active" + T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); + debug_only( + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr(" Process discovered as normal " + PTR_FORMAT, p2i(discovered_addr)); + } + ) + if (PSScavenge::should_scavenge(discovered_addr)) { + pm->claim_or_forward_depth(discovered_addr); + } + } + } else { +#ifdef ASSERT + // In the case of older JDKs which do not use the discovered + // field for the pending list, an inactive ref (next != NULL) + // must always have a NULL discovered field. + oop next = oopDesc::load_decode_heap_oop(next_addr); + oop discovered = java_lang_ref_Reference::discovered(obj); + assert(oopDesc::is_null(next) || oopDesc::is_null(discovered), + err_msg("Found an inactive reference " PTR_FORMAT " with a non-NULL discovered field", + p2i(obj))); +#endif + } + + // Treat next as normal oop; next is a link in the reference queue. + if (PSScavenge::should_scavenge(next_addr)) { + pm->claim_or_forward_depth(next_addr); + } + klass->InstanceKlass::oop_ps_push_contents(obj, pm); +} + +void InstanceRefKlass::oop_ps_push_contents(oop obj, PSPromotionManager* pm) { + if (UseCompressedOops) { + oop_ps_push_contents_specialized(obj, this, pm); + } else { + oop_ps_push_contents_specialized(obj, this, pm); + } +} + +void ObjArrayKlass::oop_ps_push_contents(oop obj, PSPromotionManager* pm) { + assert(obj->is_objArray(), "obj must be obj array"); + PushContentsClosure cl(pm); + oop_oop_iterate_elements(objArrayOop(obj), &cl); +} + +void TypeArrayKlass::oop_ps_push_contents(oop obj, PSPromotionManager* pm) { + assert(obj->is_typeArray(),"must be a type array"); + ShouldNotReachHere(); +} + oop PSPromotionManager::oop_promotion_failed(oop obj, markOop obj_mark) { assert(_old_gen_is_full || PromotionFailureALot, "Sanity"); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -25,11 +25,12 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSPROMOTIONMANAGER_INLINE_HPP #define SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSPROMOTIONMANAGER_INLINE_HPP +#include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" #include "gc_implementation/parallelScavenge/psOldGen.hpp" #include "gc_implementation/parallelScavenge/psPromotionManager.hpp" #include "gc_implementation/parallelScavenge/psPromotionLAB.inline.hpp" #include "gc_implementation/parallelScavenge/psScavenge.hpp" -#include "oops/oop.psgc.inline.hpp" +#include "oops/oop.inline.hpp" inline PSPromotionManager* PSPromotionManager::manager_array(int index) { assert(_manager_array != NULL, "access of NULL manager_array"); @@ -57,9 +58,7 @@ template inline void PSPromotionManager::claim_or_forward_depth(T* p) { assert(should_scavenge(p, true), "revisiting object?"); - assert(Universe::heap()->kind() == CollectedHeap::ParallelScavengeHeap, - "Sanity"); - assert(Universe::heap()->is_in(p), "pointer outside heap"); + assert(ParallelScavengeHeap::heap()->is_in(p), "pointer outside heap"); claim_or_forward_internal_depth(p); } @@ -92,7 +91,7 @@ } inline void PSPromotionManager::push_contents(oop obj) { - obj->push_contents(this); + obj->ps_push_contents(this); } // // This method is pretty bulky. It would be nice to split it up @@ -150,7 +149,7 @@ // Otherwise try allocating obj tenured if (new_obj == NULL) { #ifndef PRODUCT - if (Universe::heap()->promotion_should_fail()) { + if (ParallelScavengeHeap::heap()->promotion_should_fail()) { return oop_promotion_failed(o, test_mark); } #endif // #ifndef PRODUCT @@ -296,7 +295,7 @@ // that are outside the heap. These pointers are either from roots // or from metadata. if ((!PSScavenge::is_obj_in_young((HeapWord*)p)) && - Universe::heap()->is_in_reserved(p)) { + ParallelScavengeHeap::heap()->is_in_reserved(p)) { if (PSScavenge::is_obj_in_young(new_obj)) { PSScavenge::card_table()->inline_write_ref_field_gc(p, new_obj); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Thu May 07 20:51:12 2015 -0700 @@ -87,8 +87,7 @@ public: PSKeepAliveClosure(PSPromotionManager* pm) : _promotion_manager(pm) { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _to_space = heap->young_gen()->to_space(); assert(_promotion_manager != NULL, "Sanity"); @@ -218,11 +217,9 @@ bool PSScavenge::invoke() { assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread"); - assert(!Universe::heap()->is_gc_active(), "not reentrant"); + assert(!ParallelScavengeHeap::heap()->is_gc_active(), "not reentrant"); - ParallelScavengeHeap* const heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* const heap = ParallelScavengeHeap::heap(); PSAdaptiveSizePolicy* policy = heap->size_policy(); IsGCActiveMark mark; @@ -273,9 +270,8 @@ return false; } - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); GCCause::Cause gc_cause = heap->gc_cause(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); // Check for potential problems. if (!should_attempt_scavenge()) { @@ -713,9 +709,7 @@ // unforwarding markOops. It then restores any preserved mark oops, // and clears the _preserved_mark_stack. void PSScavenge::clean_up_failed_promotion() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSYoungGen* young_gen = heap->young_gen(); { @@ -742,7 +736,7 @@ } // Reset the PromotionFailureALot counters. - NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();) + NOT_PRODUCT(heap->reset_promotion_should_fail();) } // This method is called whenever an attempt to promote an object @@ -761,8 +755,7 @@ } bool PSScavenge::should_attempt_scavenge() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSGCAdaptivePolicyCounters* counters = heap->gc_policy_counters(); if (UsePerfData) { @@ -838,9 +831,7 @@ MaxTenuringThreshold; } - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSYoungGen* young_gen = heap->young_gen(); PSOldGen* old_gen = heap->old_gen(); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ #include "utilities/globalDefinitions.hpp" inline void PSScavenge::save_to_space_top_before_gc() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _to_space_top_before_gc = heap->young_gen()->to_space()->top(); } @@ -56,7 +56,7 @@ template inline bool PSScavenge::should_scavenge(T* p, bool check_to_space) { if (check_to_space) { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); return should_scavenge(p, heap->young_gen()->to_space()); } return should_scavenge(p); @@ -97,7 +97,6 @@ ParallelScavengeHeap* psh = ParallelScavengeHeap::heap(); assert(!psh->is_in_reserved(p), "GC barrier needed"); if (PSScavenge::should_scavenge(p)) { - assert(!Universe::heap()->is_in_reserved(p), "Not from meta-data?"); assert(PSScavenge::should_scavenge(p, true), "revisiting object?"); oop o = *p; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp Thu May 07 20:51:12 2015 -0700 @@ -47,7 +47,7 @@ // void ScavengeRootsTask::do_it(GCTaskManager* manager, uint which) { - assert(Universe::heap()->is_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(which); PSScavengeRootsClosure roots_closure(pm); @@ -118,7 +118,7 @@ // void ThreadRootsTask::do_it(GCTaskManager* manager, uint which) { - assert(Universe::heap()->is_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(which); PSScavengeRootsClosure roots_closure(pm); @@ -143,7 +143,7 @@ _terminator(t) {} void StealTask::do_it(GCTaskManager* manager, uint which) { - assert(Universe::heap()->is_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(which); @@ -181,10 +181,8 @@ { PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(which); - - assert(Universe::heap()->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); CardTableExtension* card_table = - barrier_set_cast(Universe::heap()->barrier_set()); + barrier_set_cast(ParallelScavengeHeap::heap()->barrier_set()); card_table->scavenge_contents_parallel(_gen->start_array(), _gen->object_space(), diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,8 +24,8 @@ #include "precompiled.hpp" #include "gc_implementation/parallelScavenge/psVirtualspace.hpp" +#include "memory/virtualspace.hpp" #include "runtime/os.hpp" -#include "runtime/virtualspace.hpp" // PSVirtualSpace diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSVIRTUALSPACE_HPP #define SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSVIRTUALSPACE_HPP -#include "runtime/virtualspace.hpp" +#include "memory/virtualspace.hpp" // VirtualSpace for the parallel scavenge collector. // diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ MemRegion cmr((HeapWord*)virtual_space()->low(), (HeapWord*)virtual_space()->high()); - Universe::heap()->barrier_set()->resize_covered_region(cmr); + ParallelScavengeHeap::heap()->barrier_set()->resize_covered_region(cmr); if (ZapUnusedHeapArea) { // Mangle newly committed space immediately because it @@ -103,7 +103,7 @@ _max_gen_size, _virtual_space); // Compute maximum space sizes for performance counters - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); size_t alignment = heap->space_alignment(); size_t size = virtual_space()->reserved_size(); @@ -153,8 +153,7 @@ } void PSYoungGen::compute_initial_space_boundaries() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); // Compute sizes size_t alignment = heap->space_alignment(); @@ -208,7 +207,7 @@ #ifndef PRODUCT void PSYoungGen::space_invariants() { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); const size_t alignment = heap->space_alignment(); // Currently, our eden size cannot shrink to zero @@ -494,7 +493,7 @@ char* to_start = (char*)to_space()->bottom(); char* to_end = (char*)to_space()->end(); - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); const size_t alignment = heap->space_alignment(); const bool maintain_minimum = (requested_eden_size + 2 * requested_survivor_size) <= min_gen_size(); @@ -546,8 +545,6 @@ // Does the optimal to-space overlap from-space? if (to_start < (char*)from_space()->end()) { - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - // Calculate the minimum offset possible for from_end size_t from_size = pointer_delta(from_space()->top(), from_start, sizeof(char)); @@ -708,9 +705,7 @@ assert(from_space()->top() == old_from_top, "from top changed!"); if (PrintAdaptiveSizePolicy) { - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); gclog_or_tty->print("AdaptiveSizePolicy::survivor space sizes: " "collection: %d " "(" SIZE_FORMAT ", " SIZE_FORMAT ") -> " @@ -843,7 +838,7 @@ // from-space. size_t PSYoungGen::available_to_live() { size_t delta_in_survivor = 0; - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); const size_t space_alignment = heap->space_alignment(); const size_t gen_alignment = heap->generation_alignment(); @@ -927,7 +922,7 @@ MemRegion cmr((HeapWord*)virtual_space()->low(), (HeapWord*)virtual_space()->high()); - Universe::heap()->barrier_set()->resize_covered_region(cmr); + ParallelScavengeHeap::heap()->barrier_set()->resize_covered_region(cmr); space_invariants(); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/vmPSOperations.cpp Thu May 07 20:51:12 2015 -0700 @@ -26,7 +26,6 @@ #include "gc_implementation/parallelScavenge/parallelScavengeHeap.inline.hpp" #include "gc_implementation/parallelScavenge/psMarkSweep.hpp" #include "gc_implementation/parallelScavenge/psScavenge.hpp" -#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" #include "gc_implementation/parallelScavenge/vmPSOperations.hpp" #include "memory/gcLocker.inline.hpp" #include "utilities/dtrace.hpp" @@ -41,8 +40,7 @@ void VM_ParallelGCFailedAllocation::doit() { SvcGCMarker sgcm(SvcGCMarker::MINOR); - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "must be a ParallelScavengeHeap"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); GCCauseSetter gccs(heap, _gc_cause); _result = heap->failed_mem_allocate(_word_size); @@ -63,9 +61,7 @@ void VM_ParallelGCSystemGC::doit() { SvcGCMarker sgcm(SvcGCMarker::FULL); - ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, - "must be a ParallelScavengeHeap"); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); GCCauseSetter gccs(heap, _gc_cause); if (_gc_cause == GCCause::_gc_locker || _gc_cause == GCCause::_wb_young_gc diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/parallelScavenge/vmStructs_parallelgc.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/vmStructs_parallelgc.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/vmStructs_parallelgc.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,6 @@ \ static_field(ParallelScavengeHeap, _young_gen, PSYoungGen*) \ static_field(ParallelScavengeHeap, _old_gen, PSOldGen*) \ - static_field(ParallelScavengeHeap, _psh, ParallelScavengeHeap*) \ \ #define VM_TYPES_PARALLELGC(declare_type, \ diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/shared/ageTable.cpp --- a/hotspot/src/share/vm/gc_implementation/shared/ageTable.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/shared/ageTable.cpp Thu May 07 20:51:12 2015 -0700 @@ -25,9 +25,9 @@ #include "precompiled.hpp" #include "gc_implementation/shared/ageTable.hpp" #include "gc_implementation/shared/gcPolicyCounters.hpp" +#include "gc_interface/collectedHeap.hpp" #include "memory/collectorPolicy.hpp" #include "memory/resourceArea.hpp" -#include "memory/sharedHeap.hpp" #include "runtime/atomic.inline.hpp" #include "utilities/copy.hpp" @@ -79,7 +79,7 @@ } } -uint ageTable::compute_tenuring_threshold(size_t survivor_capacity) { +uint ageTable::compute_tenuring_threshold(size_t survivor_capacity, GCPolicyCounters* gc_counters) { size_t desired_survivor_size = (size_t)((((double) survivor_capacity)*TargetSurvivorRatio)/100); uint result; @@ -126,9 +126,6 @@ age++; } if (UsePerfData) { - SharedHeap* sh = SharedHeap::heap(); - CollectorPolicy* policy = sh->collector_policy(); - GCPolicyCounters* gc_counters = policy->counters(); gc_counters->tenuring_threshold()->set_value(result); gc_counters->desired_survivor_size()->set_value( desired_survivor_size*oopSize); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/shared/ageTable.hpp --- a/hotspot/src/share/vm/gc_implementation/shared/ageTable.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/shared/ageTable.hpp Thu May 07 20:51:12 2015 -0700 @@ -29,6 +29,8 @@ #include "oops/oop.hpp" #include "runtime/perfData.hpp" +class GCPolicyCounters; + /* Copyright (c) 1992-2009 Oracle and/or its affiliates, and Stanford University. See the LICENSE file for license information. */ @@ -69,7 +71,7 @@ void merge_par(ageTable* subTable); // calculate new tenuring threshold based on age information - uint compute_tenuring_threshold(size_t survivor_capacity); + uint compute_tenuring_threshold(size_t survivor_capacity, GCPolicyCounters* gc_counters); private: PerfVariable* _perf_sizes[table_size]; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/shared/generationCounters.hpp --- a/hotspot/src/share/vm/gc_implementation/shared/generationCounters.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/shared/generationCounters.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,8 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_GENERATIONCOUNTERS_HPP #define SHARE_VM_GC_IMPLEMENTATION_SHARED_GENERATIONCOUNTERS_HPP +#include "memory/virtualspace.hpp" #include "runtime/perfData.hpp" -#include "runtime/virtualspace.hpp" // A GenerationCounter is a holder class for performance counters // that track a generation diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/shared/markSweep.cpp --- a/hotspot/src/share/vm/gc_implementation/shared/markSweep.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/shared/markSweep.cpp Thu May 07 20:51:12 2015 -0700 @@ -28,6 +28,8 @@ #include "gc_implementation/shared/gcTrace.hpp" #include "gc_implementation/shared/markSweep.inline.hpp" #include "gc_interface/collectedHeap.inline.hpp" +#include "oops/instanceKlass.inline.hpp" +#include "oops/instanceMirrorKlass.inline.hpp" #include "oops/methodData.hpp" #include "oops/objArrayKlass.inline.hpp" #include "oops/oop.inline.hpp" @@ -55,16 +57,183 @@ CLDToOopClosure MarkSweep::follow_cld_closure(&mark_and_push_closure); CLDToOopClosure MarkSweep::adjust_cld_closure(&adjust_pointer_closure); -void MarkSweep::MarkAndPushClosure::do_oop(oop* p) { mark_and_push(p); } -void MarkSweep::MarkAndPushClosure::do_oop(narrowOop* p) { mark_and_push(p); } +template +void MarkSweep::MarkAndPushClosure::do_oop_nv(T* p) { mark_and_push(p); } +void MarkSweep::MarkAndPushClosure::do_oop(oop* p) { do_oop_nv(p); } +void MarkSweep::MarkAndPushClosure::do_oop(narrowOop* p) { do_oop_nv(p); } void MarkSweep::follow_class_loader(ClassLoaderData* cld) { MarkSweep::follow_cld_closure.do_cld(cld); } +void InstanceKlass::oop_ms_follow_contents(oop obj) { + assert(obj != NULL, "can't follow the content of NULL object"); + MarkSweep::follow_klass(this); + + oop_oop_iterate_oop_maps(obj, &MarkSweep::mark_and_push_closure); +} + +void InstanceMirrorKlass::oop_ms_follow_contents(oop obj) { + InstanceKlass::oop_ms_follow_contents(obj); + + // Follow the klass field in the mirror + Klass* klass = java_lang_Class::as_Klass(obj); + if (klass != NULL) { + // An anonymous class doesn't have its own class loader, so the call + // to follow_klass will mark and push its java mirror instead of the + // class loader. When handling the java mirror for an anonymous class + // we need to make sure its class loader data is claimed, this is done + // by calling follow_class_loader explicitly. For non-anonymous classes + // the call to follow_class_loader is made when the class loader itself + // is handled. + if (klass->oop_is_instance() && InstanceKlass::cast(klass)->is_anonymous()) { + MarkSweep::follow_class_loader(klass->class_loader_data()); + } else { + MarkSweep::follow_klass(klass); + } + } else { + // If klass is NULL then this a mirror for a primitive type. + // We don't have to follow them, since they are handled as strong + // roots in Universe::oops_do. + assert(java_lang_Class::is_primitive(obj), "Sanity check"); + } + + oop_oop_iterate_statics(obj, &MarkSweep::mark_and_push_closure); +} + +void InstanceClassLoaderKlass::oop_ms_follow_contents(oop obj) { + InstanceKlass::oop_ms_follow_contents(obj); + + ClassLoaderData * const loader_data = java_lang_ClassLoader::loader_data(obj); + + // We must NULL check here, since the class loader + // can be found before the loader data has been set up. + if(loader_data != NULL) { + MarkSweep::follow_class_loader(loader_data); + } +} + +template +static void oop_ms_follow_contents_specialized(InstanceRefKlass* klass, oop obj) { + T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); + T heap_oop = oopDesc::load_heap_oop(referent_addr); + debug_only( + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr("InstanceRefKlass::oop_ms_follow_contents_specialized " PTR_FORMAT, p2i(obj)); + } + ) + if (!oopDesc::is_null(heap_oop)) { + oop referent = oopDesc::decode_heap_oop_not_null(heap_oop); + if (!referent->is_gc_marked() && + MarkSweep::ref_processor()->discover_reference(obj, klass->reference_type())) { + // reference was discovered, referent will be traversed later + klass->InstanceKlass::oop_ms_follow_contents(obj); + debug_only( + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr(" Non NULL enqueued " PTR_FORMAT, p2i(obj)); + } + ) + return; + } else { + // treat referent as normal oop + debug_only( + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr(" Non NULL normal " PTR_FORMAT, p2i(obj)); + } + ) + MarkSweep::mark_and_push(referent_addr); + } + } + T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); + if (ReferenceProcessor::pending_list_uses_discovered_field()) { + // Treat discovered as normal oop, if ref is not "active", + // i.e. if next is non-NULL. + T next_oop = oopDesc::load_heap_oop(next_addr); + if (!oopDesc::is_null(next_oop)) { // i.e. ref is not "active" + T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); + debug_only( + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr(" Process discovered as normal " + PTR_FORMAT, p2i(discovered_addr)); + } + ) + MarkSweep::mark_and_push(discovered_addr); + } + } else { +#ifdef ASSERT + // In the case of older JDKs which do not use the discovered + // field for the pending list, an inactive ref (next != NULL) + // must always have a NULL discovered field. + oop next = oopDesc::load_decode_heap_oop(next_addr); + oop discovered = java_lang_ref_Reference::discovered(obj); + assert(oopDesc::is_null(next) || oopDesc::is_null(discovered), + err_msg("Found an inactive reference " PTR_FORMAT " with a non-NULL discovered field", + p2i(obj))); +#endif + } + // treat next as normal oop. next is a link in the reference queue. + debug_only( + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr(" Process next as normal " PTR_FORMAT, p2i(next_addr)); + } + ) + MarkSweep::mark_and_push(next_addr); + klass->InstanceKlass::oop_ms_follow_contents(obj); +} + +void InstanceRefKlass::oop_ms_follow_contents(oop obj) { + if (UseCompressedOops) { + oop_ms_follow_contents_specialized(this, obj); + } else { + oop_ms_follow_contents_specialized(this, obj); + } +} + +template +static void oop_ms_follow_contents_specialized(oop obj, int index) { + objArrayOop a = objArrayOop(obj); + const size_t len = size_t(a->length()); + const size_t beg_index = size_t(index); + assert(beg_index < len || len == 0, "index too large"); + + const size_t stride = MIN2(len - beg_index, ObjArrayMarkingStride); + const size_t end_index = beg_index + stride; + T* const base = (T*)a->base(); + T* const beg = base + beg_index; + T* const end = base + end_index; + + // Push the non-NULL elements of the next stride on the marking stack. + for (T* e = beg; e < end; e++) { + MarkSweep::mark_and_push(e); + } + + if (end_index < len) { + MarkSweep::push_objarray(a, end_index); // Push the continuation. + } +} + +void ObjArrayKlass::oop_ms_follow_contents(oop obj) { + assert (obj->is_array(), "obj must be array"); + MarkSweep::follow_klass(this); + if (UseCompressedOops) { + oop_ms_follow_contents_specialized(obj, 0); + } else { + oop_ms_follow_contents_specialized(obj, 0); + } +} + +void TypeArrayKlass::oop_ms_follow_contents(oop obj) { + assert(obj->is_typeArray(),"must be a type array"); + // Performance tweak: We skip iterating over the klass pointer since we + // know that Universe::TypeArrayKlass never moves. +} + void MarkSweep::follow_array(objArrayOop array, int index) { - ObjArrayKlass* k = (ObjArrayKlass*)array->klass(); - k->oop_follow_contents(array, index); + if (UseCompressedOops) { + oop_ms_follow_contents_specialized(array, index); + } else { + oop_ms_follow_contents_specialized(array, index); + } } void MarkSweep::follow_stack() { @@ -112,8 +281,10 @@ MarkSweep::AdjustPointerClosure MarkSweep::adjust_pointer_closure; -void MarkSweep::AdjustPointerClosure::do_oop(oop* p) { adjust_pointer(p); } -void MarkSweep::AdjustPointerClosure::do_oop(narrowOop* p) { adjust_pointer(p); } +template +void MarkSweep::AdjustPointerClosure::do_oop_nv(T* p) { adjust_pointer(p); } +void MarkSweep::AdjustPointerClosure::do_oop(oop* p) { do_oop_nv(p); } +void MarkSweep::AdjustPointerClosure::do_oop(narrowOop* p) { do_oop_nv(p); } void MarkSweep::adjust_marks() { assert( _preserved_oop_stack.size() == _preserved_mark_stack.size(), @@ -167,11 +338,83 @@ MarkSweep::_gc_tracer = new (ResourceObj::C_HEAP, mtGC) SerialOldTracer(); } -#ifndef PRODUCT +int InstanceKlass::oop_ms_adjust_pointers(oop obj) { + int size = size_helper(); + oop_oop_iterate_oop_maps(obj, &MarkSweep::adjust_pointer_closure); + return size; +} -void MarkSweep::trace(const char* msg) { - if (TraceMarkSweep) - gclog_or_tty->print("%s", msg); +int InstanceMirrorKlass::oop_ms_adjust_pointers(oop obj) { + int size = oop_size(obj); + InstanceKlass::oop_ms_adjust_pointers(obj); + + oop_oop_iterate_statics(obj, &MarkSweep::adjust_pointer_closure); + return size; +} + +int InstanceClassLoaderKlass::oop_ms_adjust_pointers(oop obj) { + return InstanceKlass::oop_ms_adjust_pointers(obj); } +#ifdef ASSERT +template static void trace_reference_gc(const char *s, oop obj, + T* referent_addr, + T* next_addr, + T* discovered_addr) { + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr("%s obj " PTR_FORMAT, s, p2i(obj)); + gclog_or_tty->print_cr(" referent_addr/* " PTR_FORMAT " / " + PTR_FORMAT, p2i(referent_addr), + p2i(referent_addr ? + (address)oopDesc::load_decode_heap_oop(referent_addr) : NULL)); + gclog_or_tty->print_cr(" next_addr/* " PTR_FORMAT " / " + PTR_FORMAT, p2i(next_addr), + p2i(next_addr ? (address)oopDesc::load_decode_heap_oop(next_addr) : NULL)); + gclog_or_tty->print_cr(" discovered_addr/* " PTR_FORMAT " / " + PTR_FORMAT, p2i(discovered_addr), + p2i(discovered_addr ? + (address)oopDesc::load_decode_heap_oop(discovered_addr) : NULL)); + } +} #endif + +template void static adjust_object_specialized(oop obj) { + T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); + MarkSweep::adjust_pointer(referent_addr); + T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); + MarkSweep::adjust_pointer(next_addr); + T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); + MarkSweep::adjust_pointer(discovered_addr); + debug_only(trace_reference_gc("InstanceRefKlass::oop_ms_adjust_pointers", obj, + referent_addr, next_addr, discovered_addr);) +} + +int InstanceRefKlass::oop_ms_adjust_pointers(oop obj) { + int size = size_helper(); + InstanceKlass::oop_ms_adjust_pointers(obj); + + if (UseCompressedOops) { + adjust_object_specialized(obj); + } else { + adjust_object_specialized(obj); + } + return size; +} + +int ObjArrayKlass::oop_ms_adjust_pointers(oop obj) { + assert(obj->is_objArray(), "obj must be obj array"); + objArrayOop a = objArrayOop(obj); + // Get size before changing pointers. + // Don't call size() or oop_size() since that is a virtual call. + int size = a->object_size(); + oop_oop_iterate_elements(a, &MarkSweep::adjust_pointer_closure); + return size; +} + +int TypeArrayKlass::oop_ms_adjust_pointers(oop obj) { + assert(obj->is_typeArray(), "must be a type array"); + typeArrayOop t = typeArrayOop(obj); + // Performance tweak: We skip iterating over the klass pointer since we + // know that Universe::TypeArrayKlass never moves. + return t->object_size(); +} diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/shared/markSweep.hpp --- a/hotspot/src/share/vm/gc_implementation/shared/markSweep.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/shared/markSweep.hpp Thu May 07 20:51:12 2015 -0700 @@ -60,8 +60,9 @@ virtual void do_oop(narrowOop* p); }; - class MarkAndPushClosure: public OopClosure { + class MarkAndPushClosure: public ExtendedOopClosure { public: + template void do_oop_nv(T* p); virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); }; @@ -73,8 +74,12 @@ class AdjustPointerClosure: public OopsInGenClosure { public: + template void do_oop_nv(T* p); virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); + + // This closure provides its own oop verification code. + debug_only(virtual bool should_verify_oops() { return false; }) }; // Used for java/lang/ref handling @@ -126,9 +131,6 @@ // Non public closures static KeepAliveClosure keep_alive; - // Debugging - static void trace(const char* msg) PRODUCT_RETURN; - public: // Public closures static IsAliveClosure is_alive; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -28,11 +28,15 @@ #include "gc_implementation/shared/markSweep.hpp" #include "gc_interface/collectedHeap.hpp" #include "oops/markOop.inline.hpp" +#include "oops/instanceKlass.inline.hpp" +#include "oops/instanceClassLoaderKlass.inline.hpp" +#include "oops/instanceMirrorKlass.inline.hpp" +#include "oops/instanceRefKlass.inline.hpp" +#include "oops/objArrayKlass.inline.hpp" #include "utilities/stack.inline.hpp" #include "utilities/macros.hpp" #if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1StringDedup.hpp" -#include "gc_implementation/parallelScavenge/psParallelCompact.hpp" #endif // INCLUDE_ALL_GCS inline void MarkSweep::mark_object(oop obj) { @@ -59,7 +63,9 @@ } inline void MarkSweep::follow_object(oop obj) { - obj->follow_contents(); + assert(obj->is_gc_marked(), "should be marked"); + + obj->ms_follow_contents(); } template inline void MarkSweep::follow_root(T* p) { @@ -95,13 +101,15 @@ } inline int MarkSweep::adjust_pointers(oop obj) { - return obj->adjust_pointers(); + return obj->ms_adjust_pointers(); } template inline void MarkSweep::adjust_pointer(T* p) { T heap_oop = oopDesc::load_heap_oop(p); if (!oopDesc::is_null(heap_oop)) { oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); + assert(Universe::heap()->is_in(obj), "should be in heap"); + oop new_obj = oop(obj->mark()->decode_pointer()); assert(new_obj != NULL || // is forwarding ptr? obj->mark() == markOopDesc::prototype() || // not gc marked? diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp --- a/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp Thu May 07 20:51:12 2015 -0700 @@ -26,7 +26,7 @@ #include "precompiled.hpp" #include "gc_implementation/shared/mutableNUMASpace.hpp" #include "gc_implementation/shared/spaceDecorator.hpp" -#include "memory/sharedHeap.hpp" +#include "gc_interface/collectedHeap.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/thread.inline.hpp" diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/shared/parGCAllocBuffer.cpp --- a/hotspot/src/share/vm/gc_implementation/shared/parGCAllocBuffer.cpp Thu May 07 10:19:31 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "gc_implementation/shared/parGCAllocBuffer.hpp" -#include "memory/threadLocalAllocBuffer.hpp" -#include "oops/arrayOop.hpp" -#include "oops/oop.inline.hpp" - -size_t ParGCAllocBuffer::min_size() { - // Make sure that we return something that is larger than AlignmentReserve - return align_object_size(MAX2(MinTLABSize / HeapWordSize, (uintx)oopDesc::header_size())) + AlignmentReserve; -} - -size_t ParGCAllocBuffer::max_size() { - return ThreadLocalAllocBuffer::max_size(); -} - -ParGCAllocBuffer::ParGCAllocBuffer(size_t desired_plab_sz_) : - _word_sz(desired_plab_sz_), _bottom(NULL), _top(NULL), - _end(NULL), _hard_end(NULL), _allocated(0), _wasted(0) -{ - // ArrayOopDesc::header_size depends on command line initialization. - AlignmentReserve = oopDesc::header_size() > MinObjAlignment ? align_object_size(arrayOopDesc::header_size(T_INT)) : 0; - assert(min_size() > AlignmentReserve, - err_msg("Minimum PLAB size " SIZE_FORMAT" must be larger than alignment reserve " SIZE_FORMAT" " - "to be able to contain objects", min_size(), AlignmentReserve)); -} - -// If the minimum object size is greater than MinObjAlignment, we can -// end up with a shard at the end of the buffer that's smaller than -// the smallest object. We can't allow that because the buffer must -// look like it's full of objects when we retire it, so we make -// sure we have enough space for a filler int array object. -size_t ParGCAllocBuffer::AlignmentReserve; - -void ParGCAllocBuffer::flush_and_retire_stats(PLABStats* stats) { - // Retire the last allocation buffer. - size_t unused = retire_internal(); - - // Now flush the statistics. - stats->add_allocated(_allocated); - stats->add_wasted(_wasted); - stats->add_unused(unused); - - // Since we have flushed the stats we need to clear the _allocated and _wasted - // fields in case somebody retains an instance of this over GCs. Not doing so - // will artifically inflate the values in the statistics. - _allocated = 0; - _wasted = 0; -} - -void ParGCAllocBuffer::retire() { - _wasted += retire_internal(); -} - -size_t ParGCAllocBuffer::retire_internal() { - size_t result = 0; - if (_top < _hard_end) { - CollectedHeap::fill_with_object(_top, _hard_end); - result += invalidate(); - } - return result; -} - -// Compute desired plab size and latch result for later -// use. This should be called once at the end of parallel -// scavenge; it clears the sensor accumulators. -void PLABStats::adjust_desired_plab_sz(uint no_of_gc_workers) { - assert(ResizePLAB, "Not set"); - - assert(is_object_aligned(max_size()) && min_size() <= max_size(), - "PLAB clipping computation may be incorrect"); - - if (_allocated == 0) { - assert(_unused == 0, - err_msg("Inconsistency in PLAB stats: " - "_allocated: "SIZE_FORMAT", " - "_wasted: "SIZE_FORMAT", " - "_unused: "SIZE_FORMAT, - _allocated, _wasted, _unused)); - - _allocated = 1; - } - double wasted_frac = (double)_unused / (double)_allocated; - size_t target_refills = (size_t)((wasted_frac * TargetSurvivorRatio) / TargetPLABWastePct); - if (target_refills == 0) { - target_refills = 1; - } - size_t used = _allocated - _wasted - _unused; - size_t recent_plab_sz = used / (target_refills * no_of_gc_workers); - // Take historical weighted average - _filter.sample(recent_plab_sz); - // Clip from above and below, and align to object boundary - size_t new_plab_sz = MAX2(min_size(), (size_t)_filter.average()); - new_plab_sz = MIN2(max_size(), new_plab_sz); - new_plab_sz = align_object_size(new_plab_sz); - // Latch the result - if (PrintPLAB) { - gclog_or_tty->print(" (plab_sz = " SIZE_FORMAT" desired_plab_sz = " SIZE_FORMAT") ", recent_plab_sz, new_plab_sz); - } - _desired_plab_sz = new_plab_sz; - - reset(); -} - -#ifndef PRODUCT -void ParGCAllocBuffer::print() { - gclog_or_tty->print_cr("parGCAllocBuffer: _bottom: " PTR_FORMAT " _top: " PTR_FORMAT - " _end: " PTR_FORMAT " _hard_end: " PTR_FORMAT ")", - p2i(_bottom), p2i(_top), p2i(_end), p2i(_hard_end)); -} -#endif // !PRODUCT diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp --- a/hotspot/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp Thu May 07 10:19:31 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,197 +0,0 @@ -/* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_VM_GC_IMPLEMENTATION_PARNEW_PARGCALLOCBUFFER_HPP -#define SHARE_VM_GC_IMPLEMENTATION_PARNEW_PARGCALLOCBUFFER_HPP - -#include "gc_implementation/shared/gcUtil.hpp" -#include "memory/allocation.hpp" -#include "runtime/atomic.hpp" -#include "utilities/globalDefinitions.hpp" - -// Forward declarations. -class PLABStats; - -// A per-thread allocation buffer used during GC. -class ParGCAllocBuffer: public CHeapObj { -protected: - char head[32]; - size_t _word_sz; // In HeapWord units - HeapWord* _bottom; - HeapWord* _top; - HeapWord* _end; // Last allocatable address + 1 - HeapWord* _hard_end; // _end + AlignmentReserve - // In support of ergonomic sizing of PLAB's - size_t _allocated; // in HeapWord units - size_t _wasted; // in HeapWord units - char tail[32]; - static size_t AlignmentReserve; - - // Force future allocations to fail and queries for contains() - // to return false. Returns the amount of unused space in this PLAB. - size_t invalidate() { - _end = _hard_end; - size_t remaining = pointer_delta(_end, _top); // Calculate remaining space. - _top = _end; // Force future allocations to fail. - _bottom = _end; // Force future contains() queries to return false. - return remaining; - } - - // Fill in remaining space with a dummy object and invalidate the PLAB. Returns - // the amount of remaining space. - size_t retire_internal(); - -public: - // Initializes the buffer to be empty, but with the given "word_sz". - // Must get initialized with "set_buf" for an allocation to succeed. - ParGCAllocBuffer(size_t word_sz); - virtual ~ParGCAllocBuffer() {} - - // Minimum PLAB size. - static size_t min_size(); - // Maximum PLAB size. - static size_t max_size(); - - // If an allocation of the given "word_sz" can be satisfied within the - // buffer, do the allocation, returning a pointer to the start of the - // allocated block. If the allocation request cannot be satisfied, - // return NULL. - HeapWord* allocate(size_t word_sz) { - HeapWord* res = _top; - if (pointer_delta(_end, _top) >= word_sz) { - _top = _top + word_sz; - return res; - } else { - return NULL; - } - } - - // Allocate the object aligned to "alignment_in_bytes". - HeapWord* allocate_aligned(size_t word_sz, unsigned short alignment_in_bytes); - - // Undo the last allocation in the buffer, which is required to be of the - // "obj" of the given "word_sz". - void undo_allocation(HeapWord* obj, size_t word_sz) { - assert(pointer_delta(_top, _bottom) >= word_sz, "Bad undo"); - assert(pointer_delta(_top, obj) == word_sz, "Bad undo"); - _top = obj; - } - - // The total (word) size of the buffer, including both allocated and - // unallocated space. - size_t word_sz() { return _word_sz; } - - // Should only be done if we are about to reset with a new buffer of the - // given size. - void set_word_size(size_t new_word_sz) { - assert(new_word_sz > AlignmentReserve, "Too small"); - _word_sz = new_word_sz; - } - - // The number of words of unallocated space remaining in the buffer. - size_t words_remaining() { - assert(_end >= _top, "Negative buffer"); - return pointer_delta(_end, _top, HeapWordSize); - } - - bool contains(void* addr) { - return (void*)_bottom <= addr && addr < (void*)_hard_end; - } - - // Sets the space of the buffer to be [buf, space+word_sz()). - virtual void set_buf(HeapWord* buf) { - _bottom = buf; - _top = _bottom; - _hard_end = _bottom + word_sz(); - _end = _hard_end - AlignmentReserve; - assert(_end >= _top, "Negative buffer"); - // In support of ergonomic sizing - _allocated += word_sz(); - } - - // Flush allocation statistics into the given PLABStats supporting ergonomic - // sizing of PLAB's and retire the current buffer. To be called at the end of - // GC. - void flush_and_retire_stats(PLABStats* stats); - - // Fills in the unallocated portion of the buffer with a garbage object and updates - // statistics. To be called during GC. - virtual void retire(); - - void print() PRODUCT_RETURN; -}; - -// PLAB book-keeping. -class PLABStats VALUE_OBJ_CLASS_SPEC { - size_t _allocated; // Total allocated - size_t _wasted; // of which wasted (internal fragmentation) - size_t _unused; // Unused in last buffer - size_t _desired_plab_sz;// Output of filter (below), suitably trimmed and quantized - AdaptiveWeightedAverage - _filter; // Integrator with decay - - void reset() { - _allocated = 0; - _wasted = 0; - _unused = 0; - } - public: - PLABStats(size_t desired_plab_sz_, unsigned wt) : - _allocated(0), - _wasted(0), - _unused(0), - _desired_plab_sz(desired_plab_sz_), - _filter(wt) - { } - - static const size_t min_size() { - return ParGCAllocBuffer::min_size(); - } - - static const size_t max_size() { - return ParGCAllocBuffer::max_size(); - } - - size_t desired_plab_sz() { - return _desired_plab_sz; - } - - // Updates the current desired PLAB size. Computes the new desired PLAB size, - // updates _desired_plab_sz and clears sensor accumulators. - void adjust_desired_plab_sz(uint no_of_gc_workers); - - void add_allocated(size_t v) { - Atomic::add_ptr(v, &_allocated); - } - - void add_unused(size_t v) { - Atomic::add_ptr(v, &_unused); - } - - void add_wasted(size_t v) { - Atomic::add_ptr(v, &_wasted); - } -}; - -#endif // SHARE_VM_GC_IMPLEMENTATION_PARNEW_PARGCALLOCBUFFER_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/shared/parGCAllocBuffer.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/shared/parGCAllocBuffer.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_PARGCALLOCBUFFER_INLINE_HPP -#define SHARE_VM_GC_IMPLEMENTATION_SHARED_PARGCALLOCBUFFER_INLINE_HPP - -#include "gc_implementation/shared/parGCAllocBuffer.hpp" -#include "gc_interface/collectedHeap.inline.hpp" - -HeapWord* ParGCAllocBuffer::allocate_aligned(size_t word_sz, unsigned short alignment_in_bytes) { - - HeapWord* res = CollectedHeap::align_allocation_or_fail(_top, _end, alignment_in_bytes); - if (res == NULL) { - return NULL; - } - - // Set _top so that allocate(), which expects _top to be correctly set, - // can be used below. - _top = res; - return allocate(word_sz); -} - -#endif // SHARE_VM_GC_IMPLEMENTATION_SHARED_PARGCALLOCBUFFER_INLINE_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/shared/plab.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/gc_implementation/shared/plab.cpp Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc_implementation/shared/plab.hpp" +#include "memory/threadLocalAllocBuffer.hpp" +#include "oops/arrayOop.hpp" +#include "oops/oop.inline.hpp" + +size_t PLAB::min_size() { + // Make sure that we return something that is larger than AlignmentReserve + return align_object_size(MAX2(MinTLABSize / HeapWordSize, (uintx)oopDesc::header_size())) + AlignmentReserve; +} + +size_t PLAB::max_size() { + return ThreadLocalAllocBuffer::max_size(); +} + +PLAB::PLAB(size_t desired_plab_sz_) : + _word_sz(desired_plab_sz_), _bottom(NULL), _top(NULL), + _end(NULL), _hard_end(NULL), _allocated(0), _wasted(0) +{ + // ArrayOopDesc::header_size depends on command line initialization. + AlignmentReserve = oopDesc::header_size() > MinObjAlignment ? align_object_size(arrayOopDesc::header_size(T_INT)) : 0; + assert(min_size() > AlignmentReserve, + err_msg("Minimum PLAB size " SIZE_FORMAT" must be larger than alignment reserve " SIZE_FORMAT" " + "to be able to contain objects", min_size(), AlignmentReserve)); +} + +// If the minimum object size is greater than MinObjAlignment, we can +// end up with a shard at the end of the buffer that's smaller than +// the smallest object. We can't allow that because the buffer must +// look like it's full of objects when we retire it, so we make +// sure we have enough space for a filler int array object. +size_t PLAB::AlignmentReserve; + +void PLAB::flush_and_retire_stats(PLABStats* stats) { + // Retire the last allocation buffer. + size_t unused = retire_internal(); + + // Now flush the statistics. + stats->add_allocated(_allocated); + stats->add_wasted(_wasted); + stats->add_unused(unused); + + // Since we have flushed the stats we need to clear the _allocated and _wasted + // fields in case somebody retains an instance of this over GCs. Not doing so + // will artifically inflate the values in the statistics. + _allocated = 0; + _wasted = 0; +} + +void PLAB::retire() { + _wasted += retire_internal(); +} + +size_t PLAB::retire_internal() { + size_t result = 0; + if (_top < _hard_end) { + CollectedHeap::fill_with_object(_top, _hard_end); + result += invalidate(); + } + return result; +} + +// Compute desired plab size and latch result for later +// use. This should be called once at the end of parallel +// scavenge; it clears the sensor accumulators. +void PLABStats::adjust_desired_plab_sz(uint no_of_gc_workers) { + assert(ResizePLAB, "Not set"); + + assert(is_object_aligned(max_size()) && min_size() <= max_size(), + "PLAB clipping computation may be incorrect"); + + if (_allocated == 0) { + assert(_unused == 0, + err_msg("Inconsistency in PLAB stats: " + "_allocated: "SIZE_FORMAT", " + "_wasted: "SIZE_FORMAT", " + "_unused: "SIZE_FORMAT, + _allocated, _wasted, _unused)); + + _allocated = 1; + } + double wasted_frac = (double)_unused / (double)_allocated; + size_t target_refills = (size_t)((wasted_frac * TargetSurvivorRatio) / TargetPLABWastePct); + if (target_refills == 0) { + target_refills = 1; + } + size_t used = _allocated - _wasted - _unused; + size_t recent_plab_sz = used / (target_refills * no_of_gc_workers); + // Take historical weighted average + _filter.sample(recent_plab_sz); + // Clip from above and below, and align to object boundary + size_t new_plab_sz = MAX2(min_size(), (size_t)_filter.average()); + new_plab_sz = MIN2(max_size(), new_plab_sz); + new_plab_sz = align_object_size(new_plab_sz); + // Latch the result + if (PrintPLAB) { + gclog_or_tty->print(" (plab_sz = " SIZE_FORMAT" desired_plab_sz = " SIZE_FORMAT") ", recent_plab_sz, new_plab_sz); + } + _desired_plab_sz = new_plab_sz; + + reset(); +} + +#ifndef PRODUCT +void PLAB::print() { + gclog_or_tty->print_cr("PLAB: _bottom: " PTR_FORMAT " _top: " PTR_FORMAT + " _end: " PTR_FORMAT " _hard_end: " PTR_FORMAT ")", + p2i(_bottom), p2i(_top), p2i(_end), p2i(_hard_end)); +} +#endif // !PRODUCT diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/shared/plab.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/gc_implementation/shared/plab.hpp Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_PLAB_HPP +#define SHARE_VM_GC_IMPLEMENTATION_SHARED_PLAB_HPP + +#include "gc_implementation/shared/gcUtil.hpp" +#include "memory/allocation.hpp" +#include "runtime/atomic.hpp" +#include "utilities/globalDefinitions.hpp" + +// Forward declarations. +class PLABStats; + +// A per-thread allocation buffer used during GC. +class PLAB: public CHeapObj { +protected: + char head[32]; + size_t _word_sz; // In HeapWord units + HeapWord* _bottom; + HeapWord* _top; + HeapWord* _end; // Last allocatable address + 1 + HeapWord* _hard_end; // _end + AlignmentReserve + // In support of ergonomic sizing of PLAB's + size_t _allocated; // in HeapWord units + size_t _wasted; // in HeapWord units + char tail[32]; + static size_t AlignmentReserve; + + // Force future allocations to fail and queries for contains() + // to return false. Returns the amount of unused space in this PLAB. + size_t invalidate() { + _end = _hard_end; + size_t remaining = pointer_delta(_end, _top); // Calculate remaining space. + _top = _end; // Force future allocations to fail. + _bottom = _end; // Force future contains() queries to return false. + return remaining; + } + + // Fill in remaining space with a dummy object and invalidate the PLAB. Returns + // the amount of remaining space. + size_t retire_internal(); + +public: + // Initializes the buffer to be empty, but with the given "word_sz". + // Must get initialized with "set_buf" for an allocation to succeed. + PLAB(size_t word_sz); + virtual ~PLAB() {} + + // Minimum PLAB size. + static size_t min_size(); + // Maximum PLAB size. + static size_t max_size(); + + // If an allocation of the given "word_sz" can be satisfied within the + // buffer, do the allocation, returning a pointer to the start of the + // allocated block. If the allocation request cannot be satisfied, + // return NULL. + HeapWord* allocate(size_t word_sz) { + HeapWord* res = _top; + if (pointer_delta(_end, _top) >= word_sz) { + _top = _top + word_sz; + return res; + } else { + return NULL; + } + } + + // Allocate the object aligned to "alignment_in_bytes". + HeapWord* allocate_aligned(size_t word_sz, unsigned short alignment_in_bytes); + + // Undo the last allocation in the buffer, which is required to be of the + // "obj" of the given "word_sz". + void undo_allocation(HeapWord* obj, size_t word_sz) { + assert(pointer_delta(_top, _bottom) >= word_sz, "Bad undo"); + assert(pointer_delta(_top, obj) == word_sz, "Bad undo"); + _top = obj; + } + + // The total (word) size of the buffer, including both allocated and + // unallocated space. + size_t word_sz() { return _word_sz; } + + // Should only be done if we are about to reset with a new buffer of the + // given size. + void set_word_size(size_t new_word_sz) { + assert(new_word_sz > AlignmentReserve, "Too small"); + _word_sz = new_word_sz; + } + + // The number of words of unallocated space remaining in the buffer. + size_t words_remaining() { + assert(_end >= _top, "Negative buffer"); + return pointer_delta(_end, _top, HeapWordSize); + } + + bool contains(void* addr) { + return (void*)_bottom <= addr && addr < (void*)_hard_end; + } + + // Sets the space of the buffer to be [buf, space+word_sz()). + virtual void set_buf(HeapWord* buf) { + _bottom = buf; + _top = _bottom; + _hard_end = _bottom + word_sz(); + _end = _hard_end - AlignmentReserve; + assert(_end >= _top, "Negative buffer"); + // In support of ergonomic sizing + _allocated += word_sz(); + } + + // Flush allocation statistics into the given PLABStats supporting ergonomic + // sizing of PLAB's and retire the current buffer. To be called at the end of + // GC. + virtual void flush_and_retire_stats(PLABStats* stats); + + // Fills in the unallocated portion of the buffer with a garbage object and updates + // statistics. To be called during GC. + virtual void retire(); + + void print() PRODUCT_RETURN; +}; + +// PLAB book-keeping. +class PLABStats VALUE_OBJ_CLASS_SPEC { + size_t _allocated; // Total allocated + size_t _wasted; // of which wasted (internal fragmentation) + size_t _unused; // Unused in last buffer + size_t _desired_plab_sz;// Output of filter (below), suitably trimmed and quantized + AdaptiveWeightedAverage + _filter; // Integrator with decay + + void reset() { + _allocated = 0; + _wasted = 0; + _unused = 0; + } + public: + PLABStats(size_t desired_plab_sz_, unsigned wt) : + _allocated(0), + _wasted(0), + _unused(0), + _desired_plab_sz(desired_plab_sz_), + _filter(wt) + { } + + static const size_t min_size() { + return PLAB::min_size(); + } + + static const size_t max_size() { + return PLAB::max_size(); + } + + size_t desired_plab_sz() { + return _desired_plab_sz; + } + + // Updates the current desired PLAB size. Computes the new desired PLAB size, + // updates _desired_plab_sz and clears sensor accumulators. + void adjust_desired_plab_sz(uint no_of_gc_workers); + + void add_allocated(size_t v) { + Atomic::add_ptr(v, &_allocated); + } + + void add_unused(size_t v) { + Atomic::add_ptr(v, &_unused); + } + + void add_wasted(size_t v) { + Atomic::add_ptr(v, &_wasted); + } +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_SHARED_PLAB_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/shared/plab.inline.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/gc_implementation/shared/plab.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_PLAB_INLINE_HPP +#define SHARE_VM_GC_IMPLEMENTATION_SHARED_PLAB_INLINE_HPP + +#include "gc_implementation/shared/plab.hpp" +#include "gc_interface/collectedHeap.inline.hpp" + +HeapWord* PLAB::allocate_aligned(size_t word_sz, unsigned short alignment_in_bytes) { + + HeapWord* res = CollectedHeap::align_allocation_or_fail(_top, _end, alignment_in_bytes); + if (res == NULL) { + return NULL; + } + + // Set _top so that allocate(), which expects _top to be correctly set, + // can be used below. + _top = res; + return allocate(word_sz); +} + +#endif // SHARE_VM_GC_IMPLEMENTATION_SHARED_PLAB_INLINE_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp --- a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp Thu May 07 20:51:12 2015 -0700 @@ -116,8 +116,6 @@ _prologue_succeeded = false; } else { _prologue_succeeded = true; - SharedHeap* sh = SharedHeap::heap(); - if (sh != NULL) sh->_thread_holds_heap_lock_for_gc = true; } return _prologue_succeeded; } @@ -126,22 +124,11 @@ void VM_GC_Operation::doit_epilogue() { assert(Thread::current()->is_Java_thread(), "just checking"); // Release the Heap_lock first. - SharedHeap* sh = SharedHeap::heap(); - if (sh != NULL) sh->_thread_holds_heap_lock_for_gc = false; Heap_lock->unlock(); release_and_notify_pending_list_lock(); } -bool VM_GC_HeapInspection::doit_prologue() { - if (Universe::heap()->supports_heap_inspection()) { - return VM_GC_Operation::doit_prologue(); - } else { - return false; - } -} - bool VM_GC_HeapInspection::skip_operation() const { - assert(Universe::heap()->supports_heap_inspection(), "huh?"); return false; } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp --- a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp Thu May 07 20:51:12 2015 -0700 @@ -150,7 +150,6 @@ ~VM_GC_HeapInspection() {} virtual VMOp_Type type() const { return VMOp_GC_HeapInspection; } virtual bool skip_operation() const; - virtual bool doit_prologue(); virtual void doit(); void set_csv_format(bool value) {_csv_format = value;} void set_print_help(bool value) {_print_help = value;} diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_interface/collectedHeap.cpp --- a/hotspot/src/share/vm/gc_interface/collectedHeap.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.cpp Thu May 07 20:51:12 2015 -0700 @@ -220,6 +220,11 @@ } } +void CollectedHeap::set_barrier_set(BarrierSet* barrier_set) { + _barrier_set = barrier_set; + oopDesc::set_bs(_barrier_set); +} + void CollectedHeap::pre_initialize() { // Used for ReduceInitialCardMarks (when COMPILER2 is used); // otherwise remains unused. diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_interface/collectedHeap.hpp --- a/hotspot/src/share/vm/gc_interface/collectedHeap.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.hpp Thu May 07 20:51:12 2015 -0700 @@ -75,9 +75,8 @@ // // CollectedHeap -// SharedHeap -// GenCollectedHeap -// G1CollectedHeap +// GenCollectedHeap +// G1CollectedHeap // ParallelScavengeHeap // class CollectedHeap : public CHeapObj { @@ -205,7 +204,7 @@ // In many heaps, there will be a need to perform some initialization activities // after the Universe is fully formed, but before general heap allocation is allowed. // This is the correct place to place such initialization methods. - virtual void post_initialize() = 0; + virtual void post_initialize(); // Stop any onging concurrent work and prepare for exit. virtual void stop() {} @@ -240,22 +239,11 @@ } // Returns "TRUE" iff "p" points into the committed areas of the heap. - // Since this method can be expensive in general, we restrict its - // use to assertion checking only. + // This method can be expensive so avoid using it in performance critical + // code. virtual bool is_in(const void* p) const = 0; - bool is_in_or_null(const void* p) const { - return p == NULL || is_in(p); - } - - bool is_in_place(Metadata** p) { - return !Universe::heap()->is_in(p); - } - bool is_in_place(oop* p) { return Universe::heap()->is_in(p); } - bool is_in_place(narrowOop* p) { - oop o = oopDesc::load_decode_heap_oop_not_null(p); - return Universe::heap()->is_in((const void*)o); - } + DEBUG_ONLY(bool is_in_or_null(const void* p) const { return p == NULL || is_in(p); }) // Let's define some terms: a "closed" subset of a heap is one that // @@ -451,9 +439,6 @@ // remembered set. virtual void flush_deferred_store_barrier(JavaThread* thread); - // Does this heap support heap inspection (+PrintClassHistogram?) - virtual bool supports_heap_inspection() const = 0; - // Perform a collection of the heap; intended for use in implementing // "System.gc". This probably implies as full a collection as the // "CollectedHeap" supports. @@ -470,6 +455,7 @@ // Returns the barrier set for this heap BarrierSet* barrier_set() { return _barrier_set; } + void set_barrier_set(BarrierSet* barrier_set); // Returns "true" iff there is a stop-world GC in progress. (I assume // that it should answer "false" for the concurrent part of a concurrent @@ -497,12 +483,6 @@ // Return the CollectorPolicy for the heap virtual CollectorPolicy* collector_policy() const = 0; - void oop_iterate_no_header(OopClosure* cl); - - // Iterate over all the ref-containing fields of all objects, calling - // "cl.do_oop" on each. - virtual void oop_iterate(ExtendedOopClosure* cl) = 0; - // Iterate over all objects, calling "cl.do_object" on each. virtual void object_iterate(ObjectClosure* cl) = 0; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp --- a/hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -236,12 +236,6 @@ return (oop)obj; } -inline void CollectedHeap::oop_iterate_no_header(OopClosure* cl) { - NoHeaderExtendedOopClosure no_header_cl(cl); - oop_iterate(&no_header_cl); -} - - inline HeapWord* CollectedHeap::align_allocation_or_fail(HeapWord* addr, HeapWord* end, unsigned short alignment_in_bytes) { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -576,10 +576,10 @@ /* 0xD8 */ &&opc_default, &&opc_default, &&opc_default, &&opc_default, /* 0xDC */ &&opc_default, &&opc_default, &&opc_default, &&opc_default, -/* 0xE0 */ &&opc_default, &&opc_default, &&opc_default, &&opc_default, -/* 0xE4 */ &&opc_default, &&opc_fast_aldc, &&opc_fast_aldc_w, &&opc_return_register_finalizer, -/* 0xE8 */ &&opc_invokehandle,&&opc_default, &&opc_default, &&opc_default, -/* 0xEC */ &&opc_default, &&opc_default, &&opc_default, &&opc_default, +/* 0xE0 */ &&opc_default, &&opc_default, &&opc_default, &&opc_default, +/* 0xE4 */ &&opc_default, &&opc_fast_aldc, &&opc_fast_aldc_w, &&opc_return_register_finalizer, +/* 0xE8 */ &&opc_invokehandle,&&opc_default, &&opc_default, &&opc_default, +/* 0xEC */ &&opc_default, &&opc_default, &&opc_default, &&opc_default, /* 0xF0 */ &&opc_default, &&opc_default, &&opc_default, &&opc_default, /* 0xF4 */ &&opc_default, &&opc_default, &&opc_default, &&opc_default, @@ -1942,7 +1942,7 @@ cache = cp->entry_at(index); if (!cache->is_resolved((Bytecodes::Code)opcode)) { - CALL_VM(InterpreterRuntime::resolve_get_put(THREAD, (Bytecodes::Code)opcode), + CALL_VM(InterpreterRuntime::resolve_from_cache(THREAD, (Bytecodes::Code)opcode), handle_exception); cache = cp->entry_at(index); } @@ -2040,7 +2040,7 @@ u2 index = Bytes::get_native_u2(pc+1); ConstantPoolCacheEntry* cache = cp->entry_at(index); if (!cache->is_resolved((Bytecodes::Code)opcode)) { - CALL_VM(InterpreterRuntime::resolve_get_put(THREAD, (Bytecodes::Code)opcode), + CALL_VM(InterpreterRuntime::resolve_from_cache(THREAD, (Bytecodes::Code)opcode), handle_exception); cache = cp->entry_at(index); } @@ -2416,7 +2416,7 @@ // This kind of CP cache entry does not need to match the flags byte, because // there is a 1-1 relation between bytecode type and CP entry type. if (! cache->is_resolved((Bytecodes::Code) opcode)) { - CALL_VM(InterpreterRuntime::resolve_invokedynamic(THREAD), + CALL_VM(InterpreterRuntime::resolve_from_cache(THREAD, (Bytecodes::Code)opcode), handle_exception); cache = cp->constant_pool()->invokedynamic_cp_cache_entry_at(index); } @@ -2447,7 +2447,7 @@ ConstantPoolCacheEntry* cache = cp->entry_at(index); if (! cache->is_resolved((Bytecodes::Code) opcode)) { - CALL_VM(InterpreterRuntime::resolve_invokehandle(THREAD), + CALL_VM(InterpreterRuntime::resolve_from_cache(THREAD, (Bytecodes::Code)opcode), handle_exception); cache = cp->entry_at(index); } @@ -2480,7 +2480,7 @@ ConstantPoolCacheEntry* cache = cp->entry_at(index); if (!cache->is_resolved((Bytecodes::Code)opcode)) { - CALL_VM(InterpreterRuntime::resolve_invoke(THREAD, (Bytecodes::Code)opcode), + CALL_VM(InterpreterRuntime::resolve_from_cache(THREAD, (Bytecodes::Code)opcode), handle_exception); cache = cp->entry_at(index); } @@ -2571,7 +2571,7 @@ // out so c++ compiler has a chance for constant prop to fold everything possible away. if (!cache->is_resolved((Bytecodes::Code)opcode)) { - CALL_VM(InterpreterRuntime::resolve_invoke(THREAD, (Bytecodes::Code)opcode), + CALL_VM(InterpreterRuntime::resolve_from_cache(THREAD, (Bytecodes::Code)opcode), handle_exception); cache = cp->entry_at(index); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/interpreter/bytecodes.cpp --- a/hotspot/src/share/vm/interpreter/bytecodes.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/interpreter/bytecodes.cpp Thu May 07 20:51:12 2015 -0700 @@ -525,6 +525,12 @@ def(_fast_aldc , "fast_aldc" , "bj" , NULL , T_OBJECT, 1, true, _ldc ); def(_fast_aldc_w , "fast_aldc_w" , "bJJ" , NULL , T_OBJECT, 1, true, _ldc_w ); + def(_nofast_getfield , "nofast_getfield" , "bJJ" , NULL , T_ILLEGAL, 0, true, _getfield ); + def(_nofast_putfield , "nofast_putfield" , "bJJ" , NULL , T_ILLEGAL, -2, true , _putfield ); + + def(_nofast_aload_0 , "nofast_aload_0" , "b" , NULL , T_ILLEGAL, 1, true , _aload_0 ); + def(_nofast_iload , "nofast_iload" , "bi" , NULL , T_ILLEGAL, 1, false, _iload ); + def(_shouldnotreachhere , "_shouldnotreachhere" , "b" , NULL , T_VOID , 0, false); // compare can_trap information for each bytecode with the diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/interpreter/bytecodes.hpp --- a/hotspot/src/share/vm/interpreter/bytecodes.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/interpreter/bytecodes.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -285,7 +285,20 @@ // special handling of signature-polymorphic methods: _invokehandle , - _shouldnotreachhere, // For debugging + // These bytecodes are rewritten at CDS dump time, so that we can prevent them from being + // rewritten at run time. This way, the ConstMethods can be placed in the CDS ReadOnly + // section, and RewriteByteCodes/RewriteFrequentPairs can rewrite non-CDS bytecodes + // at run time. + // + // Rewritten at CDS dump time to | Original bytecode + // _invoke_virtual rewritten on sparc, will be disabled if UseSharedSpaces turned on. + // ------------------------------+------------------ + _nofast_getfield , // <- _getfield + _nofast_putfield , // <- _putfield + _nofast_aload_0 , // <- _aload_0 + _nofast_iload , // <- _iload + + _shouldnotreachhere , // For debugging number_of_codes @@ -401,6 +414,7 @@ static bool is_astore (Code code) { return (code == _astore || code == _astore_0 || code == _astore_1 || code == _astore_2 || code == _astore_3); } + static bool is_store_into_local(Code code){ return (_istore <= code && code <= _astore_3); } static bool is_const (Code code) { return (_aconst_null <= code && code <= _ldc2_w); } static bool is_zero_const (Code code) { return (code == _aconst_null || code == _iconst_0 || code == _fconst_0 || code == _dconst_0); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/interpreter/interpreterRuntime.cpp --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Thu May 07 20:51:12 2015 -0700 @@ -537,11 +537,13 @@ // Fields // -IRT_ENTRY(void, InterpreterRuntime::resolve_get_put(JavaThread* thread, Bytecodes::Code bytecode)) +void InterpreterRuntime::resolve_get_put(JavaThread* thread, Bytecodes::Code bytecode) { + Thread* THREAD = thread; // resolve field fieldDescriptor info; constantPoolHandle pool(thread, method(thread)->constants()); - bool is_put = (bytecode == Bytecodes::_putfield || bytecode == Bytecodes::_putstatic); + bool is_put = (bytecode == Bytecodes::_putfield || bytecode == Bytecodes::_nofast_putfield || + bytecode == Bytecodes::_putstatic); bool is_static = (bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic); { @@ -551,7 +553,8 @@ } // end JvmtiHideSingleStepping // check if link resolution caused cpCache to be updated - if (already_resolved(thread)) return; + ConstantPoolCacheEntry* cp_cache_entry = cache_entry(thread); + if (cp_cache_entry->is_resolved(bytecode)) return; // compute auxiliary field attributes TosState state = as_TosState(info.field_type()); @@ -579,7 +582,7 @@ } } - cache_entry(thread)->set_field( + cp_cache_entry->set_field( get_code, put_code, info.field_holder(), @@ -590,7 +593,7 @@ info.access_flags().is_volatile(), pool->pool_holder() ); -IRT_END +} //------------------------------------------------------------------------------------------------------------------------ @@ -685,7 +688,8 @@ JvmtiExport::post_raw_breakpoint(thread, method, bcp); IRT_END -IRT_ENTRY(void, InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes::Code bytecode)) { +void InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes::Code bytecode) { + Thread* THREAD = thread; // extract receiver from the outgoing argument list if necessary Handle receiver(thread, NULL); if (bytecode == Bytecodes::_invokevirtual || bytecode == Bytecodes::_invokeinterface) { @@ -709,7 +713,8 @@ { JvmtiHideSingleStepping jhss(thread); LinkResolver::resolve_invoke(info, receiver, pool, - get_index_u2_cpcache(thread, bytecode), bytecode, CHECK); + get_index_u2_cpcache(thread, bytecode), bytecode, + CHECK); if (JvmtiExport::can_hotswap_or_post_breakpoint()) { int retry_count = 0; while (info.resolved_method()->is_old()) { @@ -720,13 +725,15 @@ "Could not resolve to latest version of redefined method"); // method is redefined in the middle of resolve so re-try. LinkResolver::resolve_invoke(info, receiver, pool, - get_index_u2_cpcache(thread, bytecode), bytecode, CHECK); + get_index_u2_cpcache(thread, bytecode), bytecode, + CHECK); } } } // end JvmtiHideSingleStepping // check if link resolution caused cpCache to be updated - if (already_resolved(thread)) return; + ConstantPoolCacheEntry* cp_cache_entry = cache_entry(thread); + if (cp_cache_entry->is_resolved(bytecode)) return; if (bytecode == Bytecodes::_invokeinterface) { if (TraceItables && Verbose) { @@ -761,18 +768,18 @@ #endif switch (info.call_kind()) { case CallInfo::direct_call: - cache_entry(thread)->set_direct_call( + cp_cache_entry->set_direct_call( bytecode, info.resolved_method()); break; case CallInfo::vtable_call: - cache_entry(thread)->set_vtable_call( + cp_cache_entry->set_vtable_call( bytecode, info.resolved_method(), info.vtable_index()); break; case CallInfo::itable_call: - cache_entry(thread)->set_itable_call( + cp_cache_entry->set_itable_call( bytecode, info.resolved_method(), info.itable_index()); @@ -780,30 +787,30 @@ default: ShouldNotReachHere(); } } -IRT_END // First time execution: Resolve symbols, create a permanent MethodType object. -IRT_ENTRY(void, InterpreterRuntime::resolve_invokehandle(JavaThread* thread)) { +void InterpreterRuntime::resolve_invokehandle(JavaThread* thread) { + Thread* THREAD = thread; const Bytecodes::Code bytecode = Bytecodes::_invokehandle; // resolve method CallInfo info; constantPoolHandle pool(thread, method(thread)->constants()); - { JvmtiHideSingleStepping jhss(thread); LinkResolver::resolve_invoke(info, Handle(), pool, - get_index_u2_cpcache(thread, bytecode), bytecode, CHECK); + get_index_u2_cpcache(thread, bytecode), bytecode, + CHECK); } // end JvmtiHideSingleStepping - cache_entry(thread)->set_method_handle(pool, info); + ConstantPoolCacheEntry* cp_cache_entry = cache_entry(thread); + cp_cache_entry->set_method_handle(pool, info); } -IRT_END - // First time execution: Resolve symbols, create a permanent CallSite object. -IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) { +void InterpreterRuntime::resolve_invokedynamic(JavaThread* thread) { + Thread* THREAD = thread; const Bytecodes::Code bytecode = Bytecodes::_invokedynamic; //TO DO: consider passing BCI to Java. @@ -822,9 +829,37 @@ ConstantPoolCacheEntry* cp_cache_entry = pool->invokedynamic_cp_cache_entry_at(index); cp_cache_entry->set_dynamic_call(pool, info); } + +// This function is the interface to the assembly code. It returns the resolved +// cpCache entry. This doesn't safepoint, but the helper routines safepoint. +// This function will check for redefinition! +IRT_ENTRY(void, InterpreterRuntime::resolve_from_cache(JavaThread* thread, Bytecodes::Code bytecode)) { + switch (bytecode) { + case Bytecodes::_getstatic: + case Bytecodes::_putstatic: + case Bytecodes::_getfield: + case Bytecodes::_putfield: + resolve_get_put(thread, bytecode); + break; + case Bytecodes::_invokevirtual: + case Bytecodes::_invokespecial: + case Bytecodes::_invokestatic: + case Bytecodes::_invokeinterface: + resolve_invoke(thread, bytecode); + break; + case Bytecodes::_invokehandle: + resolve_invokehandle(thread); + break; + case Bytecodes::_invokedynamic: + resolve_invokedynamic(thread); + break; + default: + fatal(err_msg("unexpected bytecode: %s", Bytecodes::name(bytecode))); + break; + } +} IRT_END - //------------------------------------------------------------------------------------------------------------------------ // Miscellaneous diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/interpreter/interpreterRuntime.hpp --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,6 @@ // pass method to avoid calling unsafe bcp_to_method (partial fix 4926272) return Bytecodes::code_at(method(thread), bcp(thread)); } - static bool already_resolved(JavaThread *thread) { return cache_entry(thread)->is_resolved(code(thread)); } static Bytecode bytecode(JavaThread *thread) { return Bytecode(method(thread), bcp(thread)); } static int get_index_u1(JavaThread *thread, Bytecodes::Code bc) { return bytecode(thread).get_index_u1(bc); } @@ -117,9 +116,17 @@ static void note_no_trap(JavaThread* thread, Method *method, int trap_bci) {} #endif // CC_INTERP + static void resolve_from_cache(JavaThread* thread, Bytecodes::Code bytecode); + private: // Statics & fields - static void resolve_get_put(JavaThread* thread, Bytecodes::Code bytecode); + static void resolve_get_put(JavaThread* thread, Bytecodes::Code bytecode); + // Calls + static void resolve_invoke(JavaThread* thread, Bytecodes::Code bytecode); + static void resolve_invokehandle (JavaThread* thread); + static void resolve_invokedynamic(JavaThread* thread); + + public: // Synchronization static void monitorenter(JavaThread* thread, BasicObjectLock* elem); static void monitorexit (JavaThread* thread, BasicObjectLock* elem); @@ -127,11 +134,6 @@ static void throw_illegal_monitor_state_exception(JavaThread* thread); static void new_illegal_monitor_state_exception(JavaThread* thread); - // Calls - static void resolve_invoke (JavaThread* thread, Bytecodes::Code bytecode); - static void resolve_invokehandle (JavaThread* thread); - static void resolve_invokedynamic(JavaThread* thread); - // Breakpoints static void _breakpoint(JavaThread* thread, Method* method, address bcp); static Bytecodes::Code get_original_bytecode_at(JavaThread* thread, Method* method, address bcp); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/interpreter/linkResolver.cpp --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp Thu May 07 20:51:12 2015 -0700 @@ -777,11 +777,11 @@ TRAPS) { assert(byte == Bytecodes::_getstatic || byte == Bytecodes::_putstatic || byte == Bytecodes::_getfield || byte == Bytecodes::_putfield || + byte == Bytecodes::_nofast_getfield || byte == Bytecodes::_nofast_putfield || (byte == Bytecodes::_nop && !check_access), "bad field access bytecode"); bool is_static = (byte == Bytecodes::_getstatic || byte == Bytecodes::_putstatic); - bool is_put = (byte == Bytecodes::_putfield || byte == Bytecodes::_putstatic); - + bool is_put = (byte == Bytecodes::_putfield || byte == Bytecodes::_putstatic || byte == Bytecodes::_nofast_putfield); // Check if there's a resolved klass containing the field if (resolved_klass.is_null()) { ResourceMark rm(THREAD); @@ -1406,10 +1406,11 @@ KlassHandle resolved_klass, Symbol* name, Symbol* signature, - KlassHandle current_klass) { + KlassHandle current_klass, + bool check_access) { EXCEPTION_MARK; CallInfo info; - resolve_virtual_call(info, Handle(), receiver_klass, resolved_klass, name, signature, current_klass, true, false, THREAD); + resolve_virtual_call(info, Handle(), receiver_klass, resolved_klass, name, signature, current_klass, check_access, false, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return methodHandle(); @@ -1422,10 +1423,11 @@ KlassHandle resolved_klass, Symbol* name, Symbol* signature, - KlassHandle current_klass) { + KlassHandle current_klass, + bool check_access) { EXCEPTION_MARK; CallInfo info; - resolve_interface_call(info, Handle(), receiver_klass, resolved_klass, name, signature, current_klass, true, false, THREAD); + resolve_interface_call(info, Handle(), receiver_klass, resolved_klass, name, signature, current_klass, check_access, false, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return methodHandle(); @@ -1453,10 +1455,11 @@ KlassHandle resolved_klass, Symbol* name, Symbol* signature, - KlassHandle current_klass) { + KlassHandle current_klass, + bool check_access) { EXCEPTION_MARK; CallInfo info; - resolve_static_call(info, resolved_klass, name, signature, current_klass, true, false, THREAD); + resolve_static_call(info, resolved_klass, name, signature, current_klass, check_access, false, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return methodHandle(); @@ -1464,11 +1467,15 @@ return info.selected_method(); } -methodHandle LinkResolver::resolve_special_call_or_null(KlassHandle resolved_klass, Symbol* name, Symbol* signature, - KlassHandle current_klass) { +methodHandle LinkResolver::resolve_special_call_or_null( + KlassHandle resolved_klass, + Symbol* name, + Symbol* signature, + KlassHandle current_klass, + bool check_access) { EXCEPTION_MARK; CallInfo info; - resolve_special_call(info, resolved_klass, name, signature, current_klass, true, THREAD); + resolve_special_call(info, resolved_klass, name, signature, current_klass, check_access, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return methodHandle(); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/interpreter/linkResolver.hpp --- a/hotspot/src/share/vm/interpreter/linkResolver.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/interpreter/linkResolver.hpp Thu May 07 20:51:12 2015 -0700 @@ -181,10 +181,10 @@ // same as above for compile-time resolution; but returns null handle instead of throwing an exception on error // also, does not initialize klass (i.e., no side effects) - static methodHandle resolve_virtual_call_or_null (KlassHandle receiver_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass); - static methodHandle resolve_interface_call_or_null(KlassHandle receiver_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass); - static methodHandle resolve_static_call_or_null (KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass); - static methodHandle resolve_special_call_or_null (KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass); + static methodHandle resolve_virtual_call_or_null (KlassHandle receiver_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access = true); + static methodHandle resolve_interface_call_or_null(KlassHandle receiver_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access = true); + static methodHandle resolve_static_call_or_null (KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access = true); + static methodHandle resolve_special_call_or_null (KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access = true); static int vtable_index_of_interface_method(KlassHandle klass, methodHandle resolved_method); // same as above for compile-time resolution; returns vtable_index if current_klass if linked diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/interpreter/rewriter.cpp --- a/hotspot/src/share/vm/interpreter/rewriter.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/interpreter/rewriter.cpp Thu May 07 20:51:12 2015 -0700 @@ -26,6 +26,7 @@ #include "interpreter/bytecodes.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/rewriter.hpp" +#include "memory/metaspaceShared.hpp" #include "memory/gcLocker.hpp" #include "memory/resourceArea.hpp" #include "oops/generateOopMap.hpp" @@ -167,12 +168,12 @@ if (!reverse) { int cp_index = Bytes::get_Java_u2(p); if (_pool->tag_at(cp_index).is_interface_method()) { - int cache_index = add_invokespecial_cp_cache_entry(cp_index); - if (cache_index != (int)(jushort) cache_index) { - *invokespecial_error = true; - } - Bytes::put_native_u2(p, cache_index); - } else { + int cache_index = add_invokespecial_cp_cache_entry(cp_index); + if (cache_index != (int)(jushort) cache_index) { + *invokespecial_error = true; + } + Bytes::put_native_u2(p, cache_index); + } else { rewrite_member_reference(bcp, offset, reverse); } } else { @@ -500,12 +501,14 @@ } void Rewriter::rewrite(instanceKlassHandle klass, TRAPS) { + if (!DumpSharedSpaces) { + assert(!MetaspaceShared::is_in_shared_space(klass()), "archive methods must not be rewritten at run time"); + } ResourceMark rm(THREAD); Rewriter rw(klass, klass->constants(), klass->methods(), CHECK); // (That's all, folks.) } - Rewriter::Rewriter(instanceKlassHandle klass, constantPoolHandle cpool, Array* methods, TRAPS) : _klass(klass), _pool(cpool), diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/interpreter/templateTable.cpp --- a/hotspot/src/share/vm/interpreter/templateTable.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/interpreter/templateTable.cpp Thu May 07 20:51:12 2015 -0700 @@ -517,6 +517,12 @@ def(Bytecodes::_invokehandle , ubcp|disp|clvm|____, vtos, vtos, invokehandle , f1_byte ); + def(Bytecodes::_nofast_getfield , ubcp|____|clvm|____, vtos, vtos, nofast_getfield , f1_byte ); + def(Bytecodes::_nofast_putfield , ubcp|____|clvm|____, vtos, vtos, nofast_putfield , f2_byte ); + + def(Bytecodes::_nofast_aload_0 , ____|____|clvm|____, vtos, atos, nofast_aload_0 , _ ); + def(Bytecodes::_nofast_iload , ubcp|____|clvm|____, vtos, itos, nofast_iload , _ ); + def(Bytecodes::_shouldnotreachhere , ____|____|____|____, vtos, vtos, shouldnotreachhere , _ ); // platform specific bytecodes pd_initialize(); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/interpreter/templateTable.hpp --- a/hotspot/src/share/vm/interpreter/templateTable.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/interpreter/templateTable.hpp Thu May 07 20:51:12 2015 -0700 @@ -82,6 +82,7 @@ enum Operation { add, sub, mul, div, rem, _and, _or, _xor, shl, shr, ushr }; enum Condition { equal, not_equal, less, less_equal, greater, greater_equal }; enum CacheByte { f1_byte = 1, f2_byte = 2 }; // byte_no codes + enum RewriteControl { may_rewrite, may_not_rewrite }; // control for fast code under CDS private: static bool _is_initialized; // true if TemplateTable has been initialized @@ -165,6 +166,10 @@ static void dload(int n); static void aload(int n); static void aload_0(); + static void nofast_aload_0(); + static void nofast_iload(); + static void iload_internal(RewriteControl rc = may_rewrite); + static void aload_0_internal(RewriteControl rc = may_rewrite); static void istore(); static void lstore(); @@ -279,10 +284,13 @@ static void invokehandle(int byte_no); static void fast_invokevfinal(int byte_no); - static void getfield_or_static(int byte_no, bool is_static); - static void putfield_or_static(int byte_no, bool is_static); + static void getfield_or_static(int byte_no, bool is_static, RewriteControl rc = may_rewrite); + static void putfield_or_static(int byte_no, bool is_static, RewriteControl rc = may_rewrite); + static void getfield(int byte_no); static void putfield(int byte_no); + static void nofast_getfield(int byte_no); + static void nofast_putfield(int byte_no); static void getstatic(int byte_no); static void putstatic(int byte_no); static void pop_and_check_object(Register obj); @@ -343,10 +351,8 @@ // Platform specifics #if defined TEMPLATETABLE_MD_HPP # include TEMPLATETABLE_MD_HPP -#elif defined TARGET_ARCH_MODEL_x86_32 -# include "templateTable_x86_32.hpp" -#elif defined TARGET_ARCH_MODEL_x86_64 -# include "templateTable_x86_64.hpp" +#elif defined (TARGET_ARCH_MODEL_x86_32) || defined (TARGET_ARCH_MODEL_x86_64) +# include "templateTable_x86.hpp" #elif defined TARGET_ARCH_MODEL_sparc # include "templateTable_sparc.hpp" #elif defined TARGET_ARCH_MODEL_zero diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/libadt/set.cpp --- a/hotspot/src/share/vm/libadt/set.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/libadt/set.cpp Thu May 07 20:51:12 2015 -0700 @@ -57,7 +57,7 @@ // The caller must deallocate the string. char *Set::setstr() const { - if( !this ) return os::strdup("{no set}"); + if( this == NULL ) return os::strdup("{no set}"); Set &set = clone(); // Virtually copy the basic set. set.Sort(); // Sort elements for in-order retrieval diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/allocation.inline.hpp --- a/hotspot/src/share/vm/memory/allocation.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/allocation.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -62,11 +62,18 @@ } return p; } + +#ifdef __GNUC__ +__attribute__((always_inline)) +#endif inline char* AllocateHeap(size_t size, MEMFLAGS flags, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) { return AllocateHeap(size, flags, CURRENT_PC, alloc_failmode); } +#ifdef __GNUC__ +__attribute__((always_inline)) +#endif inline char* ReallocateHeap(char *old, size_t size, MEMFLAGS flag, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) { char* p = (char*) os::realloc(old, size, flag, CURRENT_PC); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/blockOffsetTable.hpp --- a/hotspot/src/share/vm/memory/blockOffsetTable.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/blockOffsetTable.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ #define SHARE_VM_MEMORY_BLOCKOFFSETTABLE_HPP #include "memory/memRegion.hpp" -#include "runtime/virtualspace.hpp" +#include "memory/virtualspace.hpp" #include "utilities/globalDefinitions.hpp" // The CollectedHeap type requires subtypes to implement a method diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/cardGeneration.cpp --- a/hotspot/src/share/vm/memory/cardGeneration.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/cardGeneration.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,7 +60,7 @@ // which would cause problems when we commit/uncommit memory, and when we // clear and dirty cards. guarantee(_rs->is_aligned(reserved_mr.start()), "generation must be card aligned"); - if (reserved_mr.end() != Universe::heap()->reserved_region().end()) { + if (reserved_mr.end() != GenCollectedHeap::heap()->reserved_region().end()) { // Don't check at the very end of the heap as we'll assert that we're probing off // the end if we try. guarantee(_rs->is_aligned(reserved_mr.end()), "generation must be card aligned"); @@ -78,7 +78,7 @@ heap_word_size(_virtual_space.committed_size()); MemRegion mr(space()->bottom(), new_word_size); // Expand card table - Universe::heap()->barrier_set()->resize_covered_region(mr); + GenCollectedHeap::heap()->barrier_set()->resize_covered_region(mr); // Expand shared block offset array _bts->resize(new_word_size); @@ -170,7 +170,7 @@ _bts->resize(new_word_size); MemRegion mr(space()->bottom(), new_word_size); // Shrink the card table - Universe::heap()->barrier_set()->resize_covered_region(mr); + GenCollectedHeap::heap()->barrier_set()->resize_covered_region(mr); if (Verbose && PrintGC) { size_t new_mem_size = _virtual_space.committed_size(); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/cardTableModRefBS.cpp --- a/hotspot/src/share/vm/memory/cardTableModRefBS.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/cardTableModRefBS.cpp Thu May 07 20:51:12 2015 -0700 @@ -23,16 +23,17 @@ */ #include "precompiled.hpp" +#include "gc_interface/collectedHeap.hpp" #include "memory/allocation.inline.hpp" #include "memory/cardTableModRefBS.inline.hpp" #include "memory/cardTableRS.hpp" -#include "memory/sharedHeap.hpp" +#include "memory/genCollectedHeap.hpp" #include "memory/space.hpp" #include "memory/space.inline.hpp" #include "memory/universe.hpp" +#include "memory/virtualspace.hpp" #include "runtime/java.hpp" #include "runtime/mutexLocker.hpp" -#include "runtime/virtualspace.hpp" #include "services/memTracker.hpp" #include "utilities/macros.hpp" #ifdef COMPILER1 @@ -450,21 +451,20 @@ // This is an example of where n_par_threads() is used instead // of workers()->active_workers(). n_par_threads can be set to 0 to // turn off parallelism. For example when this code is called as - // part of verification and SharedHeap::process_roots() is being - // used, then n_par_threads() may have been set to 0. active_workers - // is not overloaded with the meaning that it is a switch to disable - // parallelism and so keeps the meaning of the number of - // active gc workers. If parallelism has not been shut off by - // setting n_par_threads to 0, then n_par_threads should be - // equal to active_workers. When a different mechanism for shutting - // off parallelism is used, then active_workers can be used in + // part of verification during root processing then n_par_threads() + // may have been set to 0. active_workers is not overloaded with + // the meaning that it is a switch to disable parallelism and so keeps + // the meaning of the number of active gc workers. If parallelism has + // not been shut off by setting n_par_threads to 0, then n_par_threads + // should be equal to active_workers. When a different mechanism for + // shutting off parallelism is used, then active_workers can be used in // place of n_par_threads. - int n_threads = SharedHeap::heap()->n_par_threads(); + int n_threads = GenCollectedHeap::heap()->n_par_threads(); bool is_par = n_threads > 0; if (is_par) { #if INCLUDE_ALL_GCS - assert(SharedHeap::heap()->n_par_threads() == - SharedHeap::heap()->workers()->active_workers(), "Mismatch"); + assert(GenCollectedHeap::heap()->n_par_threads() == + GenCollectedHeap::heap()->workers()->active_workers(), "Mismatch"); non_clean_card_iterate_parallel_work(sp, mr, cl, ct, n_threads); #else // INCLUDE_ALL_GCS fatal("Parallel gc not supported here."); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/cardTableRS.cpp --- a/hotspot/src/share/vm/memory/cardTableRS.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/cardTableRS.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,16 +38,18 @@ GenRemSet(), _cur_youngergen_card_val(youngergenP1_card) { - guarantee(Universe::heap()->kind() == CollectedHeap::GenCollectedHeap, "sanity"); _ct_bs = new CardTableModRefBSForCTRS(whole_heap); _ct_bs->initialize(); set_bs(_ct_bs); - _last_cur_val_in_gen = NEW_C_HEAP_ARRAY3(jbyte, GenCollectedHeap::max_gens + 1, + // max_gens is really GenCollectedHeap::heap()->gen_policy()->number_of_generations() + // (which is always 2, young & old), but GenCollectedHeap has not been initialized yet. + uint max_gens = 2; + _last_cur_val_in_gen = NEW_C_HEAP_ARRAY3(jbyte, max_gens + 1, mtGC, CURRENT_PC, AllocFailStrategy::RETURN_NULL); if (_last_cur_val_in_gen == NULL) { vm_exit_during_initialization("Could not create last_cur_val_in_gen array."); } - for (int i = 0; i < GenCollectedHeap::max_gens + 1; i++) { + for (uint i = 0; i < max_gens + 1; i++) { _last_cur_val_in_gen[i] = clean_card_val(); } _ct_bs->set_CTRS(this); @@ -167,16 +169,20 @@ // Cannot yet substitute active_workers for n_par_threads // in the case where parallelism is being turned off by // setting n_par_threads to 0. - _is_par = (SharedHeap::heap()->n_par_threads() > 0); + _is_par = (GenCollectedHeap::heap()->n_par_threads() > 0); assert(!_is_par || - (SharedHeap::heap()->n_par_threads() == - SharedHeap::heap()->workers()->active_workers()), "Mismatch"); + (GenCollectedHeap::heap()->n_par_threads() == + GenCollectedHeap::heap()->workers()->active_workers()), "Mismatch"); } bool ClearNoncleanCardWrapper::is_word_aligned(jbyte* entry) { return (((intptr_t)entry) & (BytesPerWord-1)) == 0; } +// The regions are visited in *decreasing* address order. +// This order aids with imprecise card marking, where a dirty +// card may cause scanning, and summarization marking, of objects +// that extend onto subsequent cards. void ClearNoncleanCardWrapper::do_MemRegion(MemRegion mr) { assert(mr.word_size() > 0, "Error"); assert(_ct->is_aligned(mr.start()), "mr.start() should be card aligned"); @@ -591,10 +597,6 @@ // At present, we only know how to verify the card table RS for // generational heaps. VerifyCTGenClosure blk(this); - CollectedHeap* ch = Universe::heap(); - - if (ch->kind() == CollectedHeap::GenCollectedHeap) { - GenCollectedHeap::heap()->generation_iterate(&blk, false); - _ct_bs->verify(); - } - } + GenCollectedHeap::heap()->generation_iterate(&blk, false); + _ct_bs->verify(); +} diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/collectorPolicy.cpp --- a/hotspot/src/share/vm/memory/collectorPolicy.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/collectorPolicy.cpp Thu May 07 20:51:12 2015 -0700 @@ -669,7 +669,7 @@ } // Read the gc count while the heap lock is held. - gc_count_before = Universe::heap()->total_collections(); + gc_count_before = gch->total_collections(); } VM_GenCollectForAllocation op(size, is_tlab, gc_count_before); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/defNewGeneration.cpp --- a/hotspot/src/share/vm/memory/defNewGeneration.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/defNewGeneration.cpp Thu May 07 20:51:12 2015 -0700 @@ -48,6 +48,9 @@ #include "utilities/copy.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/stack.inline.hpp" +#if INCLUDE_ALL_GCS +#include "gc_implementation/parNew/parOopClosures.hpp" +#endif // // DefNewGeneration functions. @@ -190,7 +193,9 @@ { MemRegion cmr((HeapWord*)_virtual_space.low(), (HeapWord*)_virtual_space.high()); - Universe::heap()->barrier_set()->resize_covered_region(cmr); + GenCollectedHeap* gch = GenCollectedHeap::heap(); + + gch->barrier_set()->resize_covered_region(cmr); _eden_space = new ContiguousSpace(); _from_space = new ContiguousSpace(); @@ -202,13 +207,13 @@ // Compute the maximum eden and survivor space sizes. These sizes // are computed assuming the entire reserved space is committed. // These values are exported as performance counters. - uintx alignment = GenCollectedHeap::heap()->collector_policy()->space_alignment(); + uintx alignment = gch->collector_policy()->space_alignment(); uintx size = _virtual_space.reserved_size(); _max_survivor_size = compute_survivor_size(size, alignment); _max_eden_size = size - (2*_max_survivor_size); // allocate the performance counters - GenCollectorPolicy* gcp = (GenCollectorPolicy*) GenCollectedHeap::heap()->collector_policy(); + GenCollectorPolicy* gcp = (GenCollectorPolicy*)gch->collector_policy(); // Generation counters -- generation 0, 3 subspaces _gen_counters = new GenerationCounters("new", 0, 3, @@ -378,8 +383,7 @@ int next_level = level() + 1; GenCollectedHeap* gch = GenCollectedHeap::heap(); - assert(next_level < gch->n_gens(), - "DefNewGeneration cannot be an oldest gen"); + assert(next_level == 1, "DefNewGeneration must be a young gen"); Generation* old_gen = gch->old_gen(); size_t old_size = old_gen->capacity(); @@ -431,7 +435,7 @@ SpaceDecorator::DontMangle); MemRegion cmr((HeapWord*)_virtual_space.low(), (HeapWord*)_virtual_space.high()); - Universe::heap()->barrier_set()->resize_covered_region(cmr); + gch->barrier_set()->resize_covered_region(cmr); if (Verbose && PrintGC) { size_t new_size_after = _virtual_space.committed_size(); size_t eden_size_after = eden()->capacity(); @@ -550,8 +554,9 @@ void DefNewGeneration::adjust_desired_tenuring_threshold() { // Set the desired survivor size to half the real survivor space + GCPolicyCounters* gc_counters = GenCollectedHeap::heap()->collector_policy()->counters(); _tenuring_threshold = - age_table()->compute_tenuring_threshold(to()->capacity()/HeapWordSize); + age_table()->compute_tenuring_threshold(to()->capacity()/HeapWordSize, gc_counters); } void DefNewGeneration::collect(bool full, @@ -688,7 +693,7 @@ gc_tracer.report_promotion_failed(_promotion_failed_info); // Reset the PromotionFailureALot counters. - NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();) + NOT_PRODUCT(gch->reset_promotion_should_fail();) } if (PrintGC && !PrintGCDetails) { gch->print_heap_change(gch_prev_used); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/defNewGeneration.inline.hpp --- a/hotspot/src/share/vm/memory/defNewGeneration.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/defNewGeneration.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -25,9 +25,9 @@ #ifndef SHARE_VM_MEMORY_DEFNEWGENERATION_INLINE_HPP #define SHARE_VM_MEMORY_DEFNEWGENERATION_INLINE_HPP -#include "gc_interface/collectedHeap.hpp" #include "memory/cardTableRS.hpp" #include "memory/defNewGeneration.hpp" +#include "memory/genCollectedHeap.hpp" #include "memory/genOopClosures.inline.hpp" #include "memory/space.hpp" @@ -60,7 +60,7 @@ // We could check that p is also in an older generation, but // dirty cards in the youngest gen are never scanned, so the // extra check probably isn't worthwhile. - if (Universe::heap()->is_in_reserved(p)) { + if (GenCollectedHeap::heap()->is_in_reserved(p)) { oop obj = oopDesc::load_decode_heap_oop_not_null(p); _rs->inline_write_ref_field_gc(p, obj); } @@ -84,7 +84,7 @@ // we set a younger_gen card if we have an older->youngest // generation pointer. oop obj = oopDesc::load_decode_heap_oop_not_null(p); - if (((HeapWord*)obj < _boundary) && Universe::heap()->is_in_reserved(p)) { + if (((HeapWord*)obj < _boundary) && GenCollectedHeap::heap()->is_in_reserved(p)) { _rs->inline_write_ref_field_gc(p, obj); } } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/freeList.cpp --- a/hotspot/src/share/vm/memory/freeList.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/freeList.cpp Thu May 07 20:51:12 2015 -0700 @@ -23,10 +23,10 @@ */ #include "precompiled.hpp" +#include "gc_interface/collectedHeap.hpp" #include "memory/freeBlockDictionary.hpp" #include "memory/freeList.hpp" #include "memory/metachunk.hpp" -#include "memory/sharedHeap.hpp" #include "runtime/globals.hpp" #include "runtime/mutex.hpp" #include "runtime/vmThread.hpp" diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/gcLocker.cpp --- a/hotspot/src/share/vm/memory/gcLocker.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/gcLocker.cpp Thu May 07 20:51:12 2015 -0700 @@ -23,9 +23,9 @@ */ #include "precompiled.hpp" +#include "gc_interface/collectedHeap.hpp" #include "memory/gcLocker.inline.hpp" #include "memory/resourceArea.hpp" -#include "memory/sharedHeap.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/thread.inline.hpp" diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/genCollectedHeap.cpp --- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp Thu May 07 20:51:12 2015 -0700 @@ -39,7 +39,7 @@ #include "memory/genOopClosures.inline.hpp" #include "memory/generationSpec.hpp" #include "memory/resourceArea.hpp" -#include "memory/sharedHeap.hpp" +#include "memory/strongRootsScope.hpp" #include "memory/space.hpp" #include "oops/oop.inline.hpp" #include "runtime/biasedLocking.hpp" @@ -50,15 +50,15 @@ #include "runtime/vmThread.hpp" #include "services/management.hpp" #include "services/memoryService.hpp" +#include "utilities/macros.hpp" +#include "utilities/stack.inline.hpp" #include "utilities/vmError.hpp" #include "utilities/workgroup.hpp" -#include "utilities/macros.hpp" #if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp" #include "gc_implementation/concurrentMarkSweep/vmCMSOperations.hpp" #endif // INCLUDE_ALL_GCS -GenCollectedHeap* GenCollectedHeap::_gch; NOT_PRODUCT(size_t GenCollectedHeap::_skip_header_HeapWords = 0;) // The set of potentially parallel tasks in root scanning. @@ -78,21 +78,27 @@ }; GenCollectedHeap::GenCollectedHeap(GenCollectorPolicy *policy) : - SharedHeap(), + CollectedHeap(), _rem_set(NULL), _gen_policy(policy), _process_strong_tasks(new SubTasksDone(GCH_PS_NumElements)), _full_collections_completed(0) { assert(policy != NULL, "Sanity check"); + if (UseConcMarkSweepGC) { + _workers = new FlexibleWorkGang("GC Thread", ParallelGCThreads, + /* are_GC_task_threads */true, + /* are_ConcurrentGC_threads */false); + _workers->initialize_workers(); + } else { + // Serial GC does not use workers. + _workers = NULL; + } } jint GenCollectedHeap::initialize() { CollectedHeap::pre_initialize(); - _n_gens = gen_policy()->number_of_generations(); - assert(_n_gens == 2, "There is no support for more than two generations"); - // While there are no constraints in the GC code that HeapWordSize // be any particular value, there are multiple other areas in the // system which believe this to be true (e.g. oop->object_size in some @@ -120,8 +126,6 @@ _rem_set = collector_policy()->create_rem_set(reserved_region()); set_barrier_set(rem_set()->bs()); - _gch = this; - ReservedSpace young_rs = heap_rs.first_part(gen_policy()->young_gen_spec()->max_size(), false, false); _young_gen = gen_policy()->young_gen_spec()->init(young_rs, 0, rem_set()); heap_rs = heap_rs.last_part(gen_policy()->young_gen_spec()->max_size()); @@ -166,7 +170,8 @@ } void GenCollectedHeap::post_initialize() { - SharedHeap::post_initialize(); + CollectedHeap::post_initialize(); + ref_processing_init(); GenCollectorPolicy *policy = (GenCollectorPolicy *)collector_policy(); guarantee(policy->is_generation_policy(), "Illegal policy type"); assert((_young_gen->kind() == Generation::DefNew) || @@ -185,7 +190,6 @@ } void GenCollectedHeap::ref_processing_init() { - SharedHeap::ref_processing_init(); _young_gen->ref_processor_init(); _old_gen->ref_processor_init(); } @@ -200,8 +204,7 @@ // Save the "used_region" for generations level and lower. void GenCollectedHeap::save_used_regions(int level) { - assert(level >= 0, "Illegal level parameter"); - assert(level < _n_gens, "Illegal level parameter"); + assert(level == 0 || level == 1, "Illegal level parameter"); if (level == 1) { _old_gen->save_used_region(); } @@ -417,7 +420,6 @@ assert(Heap_lock->is_locked(), "the requesting thread should have the Heap_lock"); guarantee(!is_gc_active(), "collection is not reentrant"); - assert(max_level < n_gens(), "sanity check"); if (GC_locker::check_active_before_gc()) { return; // GC is disabled (e.g. JNI GetXXXCritical operation) @@ -435,7 +437,7 @@ { FlagSetting fl(_is_gc_active, true); - bool complete = full && (max_level == (n_gens()-1)); + bool complete = full && (max_level == 1 /* old */); const char* gc_cause_prefix = complete ? "Full GC" : "GC"; TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); // The PrintGCDetails logging starts before we have incremented the GC id. We will do that later @@ -507,7 +509,7 @@ // Update "complete" boolean wrt what actually transpired -- // for instance, a promotion failure could have led to // a whole heap collection. - complete = complete || (max_level_collected == n_gens() - 1); + complete = complete || (max_level_collected == 1 /* old */); if (complete) { // We did a "major" collection // FIXME: See comment at pre_full_gc_dump call @@ -524,7 +526,7 @@ } // Adjust generation sizes. - if (max_level_collected == 1) { + if (max_level_collected == 1 /* old */) { _old_gen->compute_new_size(); } _young_gen->compute_new_size(); @@ -560,7 +562,8 @@ } void GenCollectedHeap::set_par_threads(uint t) { - SharedHeap::set_par_threads(t); + assert(t == 0 || !UseSerialGC, "Cannot have parallel threads"); + CollectedHeap::set_par_threads(t); set_n_termination(t); } @@ -586,7 +589,7 @@ CLDClosure* strong_cld_closure, CLDClosure* weak_cld_closure, CodeBlobClosure* code_roots) { - StrongRootsScope srs(this, activate_scope); + StrongRootsScope srs(activate_scope); // General roots. assert(Threads::thread_claim_parity() != 0, "must have called prologue code"); @@ -606,7 +609,8 @@ // Only process code roots from thread stacks if we aren't visiting the entire CodeCache anyway CodeBlobClosure* roots_from_code_p = (so & SO_AllCodeCache) ? NULL : code_roots; - Threads::possibly_parallel_oops_do(strong_roots, roots_from_clds_p, roots_from_code_p); + bool is_par = n_par_threads() > 0; + Threads::possibly_parallel_oops_do(is_par, strong_roots, roots_from_clds_p, roots_from_code_p); if (!_process_strong_tasks->is_task_claimed(GCH_PS_Universe_oops_do)) { Universe::oops_do(strong_roots); @@ -771,19 +775,19 @@ #endif // INCLUDE_ALL_GCS } else if (cause == GCCause::_wb_young_gc) { // minor collection for WhiteBox API - collect(cause, 0); + collect(cause, 0 /* young */); } else { #ifdef ASSERT if (cause == GCCause::_scavenge_alot) { // minor collection only - collect(cause, 0); + collect(cause, 0 /* young */); } else { // Stop-the-world full collection - collect(cause, n_gens() - 1); + collect(cause, 1 /* old */); } #else // Stop-the-world full collection - collect(cause, n_gens() - 1); + collect(cause, 1 /* old */); #endif } } @@ -798,7 +802,7 @@ void GenCollectedHeap::collect_locked(GCCause::Cause cause) { // The caller has the Heap_lock assert(Heap_lock->owned_by_self(), "this thread should own the Heap_lock"); - collect_locked(cause, n_gens() - 1); + collect_locked(cause, 1 /* old */); } // this is the private collection interface @@ -854,7 +858,7 @@ #endif // INCLUDE_ALL_GCS void GenCollectedHeap::do_full_collection(bool clear_all_soft_refs) { - do_full_collection(clear_all_soft_refs, _n_gens - 1); + do_full_collection(clear_all_soft_refs, 1 /* old */); } void GenCollectedHeap::do_full_collection(bool clear_all_soft_refs, @@ -886,7 +890,7 @@ clear_all_soft_refs /* clear_all_soft_refs */, 0 /* size */, false /* is_tlab */, - n_gens() - 1 /* max_level */); + 1 /* old */ /* max_level */); } } @@ -899,17 +903,6 @@ // Returns "TRUE" iff "p" points into the committed areas of the heap. bool GenCollectedHeap::is_in(const void* p) const { - #ifndef ASSERT - guarantee(VerifyBeforeGC || - VerifyDuringGC || - VerifyBeforeExit || - VerifyDuringStartup || - PrintAssembly || - tty->count() != 0 || // already printing - VerifyAfterGC || - VMError::fatal_error_in_progress(), "too expensive"); - - #endif return _young_gen->is_in(p) || _old_gen->is_in(p); } @@ -923,6 +916,11 @@ } #endif +void GenCollectedHeap::oop_iterate_no_header(OopClosure* cl) { + NoHeaderExtendedOopClosure no_header_cl(cl); + oop_iterate(&no_header_cl); +} + void GenCollectedHeap::oop_iterate(ExtendedOopClosure* cl) { _young_gen->oop_iterate(cl); _old_gen->oop_iterate(cl); @@ -1092,11 +1090,6 @@ } } -void GenCollectedHeap::space_iterate(SpaceClosure* cl) { - _young_gen->space_iterate(cl, true); - _old_gen->space_iterate(cl, true); -} - bool GenCollectedHeap::is_maximal_no_gc() const { return _young_gen->is_maximal_no_gc() && _old_gen->is_maximal_no_gc(); } @@ -1107,14 +1100,13 @@ } GenCollectedHeap* GenCollectedHeap::heap() { - assert(_gch != NULL, "Uninitialized access to GenCollectedHeap::heap()"); - assert(_gch->kind() == CollectedHeap::GenCollectedHeap, "not a generational heap"); - return _gch; + CollectedHeap* heap = Universe::heap(); + assert(heap != NULL, "Uninitialized access to GenCollectedHeap::heap()"); + assert(heap->kind() == CollectedHeap::GenCollectedHeap, "Not a GenCollectedHeap"); + return (GenCollectedHeap*)heap; } - void GenCollectedHeap::prepare_for_compaction() { - guarantee(_n_gens = 2, "Wrong number of generations"); // Start by compacting into same gen. CompactPoint cp(_old_gen); _old_gen->prepare_for_compaction(&cp); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/genCollectedHeap.hpp --- a/hotspot/src/share/vm/memory/genCollectedHeap.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/genCollectedHeap.hpp Thu May 07 20:51:12 2015 -0700 @@ -26,15 +26,16 @@ #define SHARE_VM_MEMORY_GENCOLLECTEDHEAP_HPP #include "gc_implementation/shared/adaptiveSizePolicy.hpp" +#include "gc_interface/collectedHeap.hpp" #include "memory/collectorPolicy.hpp" #include "memory/generation.hpp" -#include "memory/sharedHeap.hpp" class SubTasksDone; +class FlexibleWorkGang; -// A "GenCollectedHeap" is a SharedHeap that uses generational +// A "GenCollectedHeap" is a CollectedHeap that uses generational // collection. It has two generations, young and old. -class GenCollectedHeap : public SharedHeap { +class GenCollectedHeap : public CollectedHeap { friend class GenCollectorPolicy; friend class Generation; friend class DefNewGeneration; @@ -51,19 +52,9 @@ friend class GCCauseSetter; friend class VMStructs; public: - enum SomeConstants { - max_gens = 10 - }; - friend class VM_PopulateDumpSharedSpace; - protected: - // Fields: - static GenCollectedHeap* _gch; - - private: - int _n_gens; - +private: Generation* _young_gen; Generation* _old_gen; @@ -93,6 +84,8 @@ // In block contents verification, the number of header words to skip NOT_PRODUCT(static size_t _skip_header_HeapWords;) + FlexibleWorkGang* _workers; + protected: // Helper functions for allocation HeapWord* attempt_allocation(size_t size, @@ -125,6 +118,8 @@ public: GenCollectedHeap(GenCollectorPolicy *policy); + FlexibleWorkGang* workers() const { return _workers; } + GCStats* gc_stats(int level) const; // Returns JNI_OK on success @@ -178,9 +173,6 @@ HeapWord** top_addr() const; HeapWord** end_addr() const; - // Does this heap support heap inspection? (+PrintClassHistogram) - virtual bool supports_heap_inspection() const { return true; } - // Perform a full collection of the heap; intended for use in implementing // "System.gc". This implies as full a collection as the CollectedHeap // supports. Caller does not hold the Heap_lock on entry. @@ -223,6 +215,7 @@ } // Iteration functions. + void oop_iterate_no_header(OopClosure* cl); void oop_iterate(ExtendedOopClosure* cl); void object_iterate(ObjectClosure* cl); void safe_object_iterate(ObjectClosure* cl); @@ -280,11 +273,6 @@ // only and may need to be re-examined in case other // kinds of collectors are implemented in the future. virtual bool can_elide_initializing_store_barrier(oop new_obj) { - // We wanted to assert that:- - // assert(UseSerialGC || UseConcMarkSweepGC, - // "Check can_elide_initializing_store_barrier() for this collector"); - // but unfortunately the flag UseSerialGC need not necessarily always - // be set when DefNew+Tenured are being used. return is_in_young(new_obj); } @@ -331,7 +319,6 @@ _old_gen->update_gc_stats(current_level, full); } - // Override. bool no_gc_in_progress() { return !is_gc_active(); } // Override. @@ -363,18 +350,11 @@ // If "old_to_young" determines the order. void generation_iterate(GenClosure* cl, bool old_to_young); - void space_iterate(SpaceClosure* cl); - // Return "true" if all generations have reached the // maximal committed limit that they can reach, without a garbage // collection. virtual bool is_maximal_no_gc() const; - int n_gens() const { - assert(_n_gens == gen_policy()->number_of_generations(), "Sanity"); - return _n_gens; - } - // This function returns the "GenRemSet" object that allows us to scan // generations in a fully generational heap. GenRemSet* rem_set() { return _rem_set; } @@ -531,8 +511,8 @@ void record_gen_tops_before_GC() PRODUCT_RETURN; protected: - virtual void gc_prologue(bool full); - virtual void gc_epilogue(bool full); + void gc_prologue(bool full); + void gc_epilogue(bool full); }; #endif // SHARE_VM_MEMORY_GENCOLLECTEDHEAP_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/genMarkSweep.cpp --- a/hotspot/src/share/vm/memory/genMarkSweep.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/genMarkSweep.cpp Thu May 07 20:51:12 2015 -0700 @@ -187,7 +187,6 @@ bool clear_all_softrefs) { // Recursively traverse all live objects and mark them GCTraceTime tm("phase 1", PrintGC && Verbose, true, _gc_timer, _gc_tracer->gc_id()); - trace(" 1"); GenCollectedHeap* gch = GenCollectedHeap::heap(); @@ -258,7 +257,6 @@ GenCollectedHeap* gch = GenCollectedHeap::heap(); GCTraceTime tm("phase 2", PrintGC && Verbose, true, _gc_timer, _gc_tracer->gc_id()); - trace("2"); gch->prepare_for_compaction(); } @@ -275,7 +273,6 @@ // Adjust the pointers to reflect the new locations GCTraceTime tm("phase 3", PrintGC && Verbose, true, _gc_timer, _gc_tracer->gc_id()); - trace("3"); // Need new claim bits for the pointer adjustment tracing. ClassLoaderDataGraph::clear_claimed_marks(); @@ -325,7 +322,6 @@ GenCollectedHeap* gch = GenCollectedHeap::heap(); GCTraceTime tm("phase 4", PrintGC && Verbose, true, _gc_timer, _gc_tracer->gc_id()); - trace("4"); GenCompactClosure blk; gch->generation_iterate(&blk, true); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/genOopClosures.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/memory/genOopClosures.cpp Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,30 @@ +/* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "memory/genOopClosures.inline.hpp" +#include "memory/iterator.inline.hpp" +#include "memory/specialized_oop_closures.hpp" + +// Generate Serial GC specialized oop_oop_iterate functions. +SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_S(ALL_KLASS_OOP_OOP_ITERATE_DEFN) diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/genOopClosures.inline.hpp --- a/hotspot/src/share/vm/memory/genOopClosures.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/genOopClosures.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -31,7 +31,6 @@ #include "memory/genOopClosures.hpp" #include "memory/genRemSet.hpp" #include "memory/generation.hpp" -#include "memory/sharedHeap.hpp" #include "memory/space.hpp" inline OopsInGenClosure::OopsInGenClosure(Generation* gen) : diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/generation.cpp --- a/hotspot/src/share/vm/memory/generation.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/generation.cpp Thu May 07 20:51:12 2015 -0700 @@ -187,7 +187,7 @@ assert(obj_size == (size_t)obj->size(), "bad obj_size passed in"); #ifndef PRODUCT - if (Universe::heap()->promotion_should_fail()) { + if (GenCollectedHeap::heap()->promotion_should_fail()) { return NULL; } #endif // #ifndef PRODUCT diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/generation.hpp --- a/hotspot/src/share/vm/memory/generation.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/generation.hpp Thu May 07 20:51:12 2015 -0700 @@ -30,10 +30,10 @@ #include "memory/memRegion.hpp" #include "memory/referenceProcessor.hpp" #include "memory/universe.hpp" +#include "memory/virtualspace.hpp" #include "memory/watermark.hpp" #include "runtime/mutex.hpp" #include "runtime/perfData.hpp" -#include "runtime/virtualspace.hpp" // A Generation models a heap area for similarly-aged objects. // It will contain one ore more spaces holding the actual objects. diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/heap.hpp --- a/hotspot/src/share/vm/memory/heap.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/heap.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ #include "code/codeBlob.hpp" #include "memory/allocation.hpp" -#include "runtime/virtualspace.hpp" +#include "memory/virtualspace.hpp" // Blocks diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/iterator.cpp --- a/hotspot/src/share/vm/memory/iterator.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/iterator.cpp Thu May 07 20:51:12 2015 -0700 @@ -23,8 +23,11 @@ */ #include "precompiled.hpp" -#include "memory/iterator.hpp" +#include "memory/iterator.inline.hpp" +#include "memory/universe.hpp" #include "oops/oop.inline.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" void KlassToOopClosure::do_klass(Klass* k) { assert(_oop_closure != NULL, "Not initialized?"); @@ -61,19 +64,18 @@ } } -MarkingCodeBlobClosure::MarkScope::MarkScope(bool activate) - : _active(activate) -{ - if (_active) nmethod::oops_do_marking_prologue(); -} - -MarkingCodeBlobClosure::MarkScope::~MarkScope() { - if (_active) nmethod::oops_do_marking_epilogue(); -} - void MarkingCodeBlobClosure::do_code_blob(CodeBlob* cb) { nmethod* nm = cb->as_nmethod_or_null(); if (nm != NULL && !nm->test_set_oops_do_mark()) { do_nmethod(nm); } } + +// Generate the *Klass::oop_oop_iterate functions for the base class +// of the oop closures. These versions use the virtual do_oop calls, +// instead of the devirtualized do_oop_nv version. +ALL_KLASS_OOP_OOP_ITERATE_DEFN(ExtendedOopClosure, _v) + +// Generate the *Klass::oop_oop_iterate functions +// for the NoHeaderExtendedOopClosure helper class. +ALL_KLASS_OOP_OOP_ITERATE_DEFN(NoHeaderExtendedOopClosure, _nv) diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/iterator.hpp --- a/hotspot/src/share/vm/memory/iterator.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/iterator.hpp Thu May 07 20:51:12 2015 -0700 @@ -44,9 +44,7 @@ class OopClosure : public Closure { public: virtual void do_oop(oop* o) = 0; - virtual void do_oop_v(oop* o) { do_oop(o); } virtual void do_oop(narrowOop* o) = 0; - virtual void do_oop_v(narrowOop* o) { do_oop(o); } }; // ExtendedOopClosure adds extra code to be run during oop iterations. @@ -74,11 +72,9 @@ // Currently, only CMS and G1 need these. virtual bool do_metadata() { return do_metadata_nv(); } - bool do_metadata_v() { return do_metadata(); } bool do_metadata_nv() { return false; } virtual void do_klass(Klass* k) { do_klass_nv(k); } - void do_klass_v(Klass* k) { do_klass(k); } void do_klass_nv(Klass* k) { ShouldNotReachHere(); } virtual void do_class_loader_data(ClassLoaderData* cld) { ShouldNotReachHere(); } @@ -87,6 +83,14 @@ // location without an intervening "major reset" (like the end of a GC). virtual bool idempotent() { return false; } virtual bool apply_to_weak_ref_discovered_field() { return false; } + +#ifdef ASSERT + // Default verification of each visited oop field. + template void verify(T* p); + + // Can be used by subclasses to turn off the default verification of oop fields. + virtual bool should_verify_oops() { return true; } +#endif }; // Wrapper closure only used to implement oop_iterate_no_header(). @@ -147,7 +151,6 @@ }; class CLDToKlassAndOopClosure : public CLDClosure { - friend class SharedHeap; friend class G1CollectedHeap; protected: OopClosure* _oop_closure; @@ -284,16 +287,6 @@ // Called for each code blob, but at most once per unique blob. virtual void do_code_blob(CodeBlob* cb); - - class MarkScope : public StackObj { - protected: - bool _active; - public: - MarkScope(bool activate = true); - // = { if (active) nmethod::oops_do_marking_prologue(); } - ~MarkScope(); - // = { if (active) nmethod::oops_do_marking_epilogue(); } - }; }; // MonitorClosure is used for iterating over monitors in the monitors cache @@ -364,16 +357,33 @@ } }; +// The two class template specializations are used to dispatch calls +// to the ExtendedOopClosure functions. If use_non_virtual_call is true, +// the non-virtual versions are called (E.g. do_oop_nv), otherwise the +// virtual versions are called (E.g. do_oop). -// Helper defines for ExtendOopClosure +template +class Devirtualizer {}; -#define if_do_metadata_checked(closure, nv_suffix) \ - /* Make sure the non-virtual and the virtual versions match. */ \ - assert(closure->do_metadata##nv_suffix() == closure->do_metadata(), \ - "Inconsistency in do_metadata"); \ - if (closure->do_metadata##nv_suffix()) +// Dispatches to the non-virtual functions. +template <> class Devirtualizer { + public: + template static void do_oop(OopClosureType* closure, T* p); + template static void do_klass(OopClosureType* closure, Klass* k); + template static bool do_metadata(OopClosureType* closure); +}; -#define assert_should_ignore_metadata(closure, nv_suffix) \ - assert(!closure->do_metadata##nv_suffix(), "Code to handle metadata is not implemented") +// Dispatches to the virtual functions. +template <> class Devirtualizer { + public: + template static void do_oop(OopClosureType* closure, T* p); + template static void do_klass(OopClosureType* closure, Klass* k); + template static bool do_metadata(OopClosureType* closure); +}; + +// Helper to convert the oop iterate macro suffixes into bool values that can be used by template functions. +#define nvs_nv_to_bool true +#define nvs_v_to_bool false +#define nvs_to_bool(nv_suffix) nvs##nv_suffix##_to_bool #endif // SHARE_VM_MEMORY_ITERATOR_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/iterator.inline.hpp --- a/hotspot/src/share/vm/memory/iterator.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/iterator.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -28,6 +28,12 @@ #include "classfile/classLoaderData.hpp" #include "memory/iterator.hpp" #include "oops/klass.hpp" +#include "oops/instanceKlass.inline.hpp" +#include "oops/instanceMirrorKlass.inline.hpp" +#include "oops/instanceClassLoaderKlass.inline.hpp" +#include "oops/instanceRefKlass.inline.hpp" +#include "oops/objArrayKlass.inline.hpp" +#include "oops/typeArrayKlass.inline.hpp" #include "utilities/debug.hpp" inline void MetadataAwareOopClosure::do_class_loader_data(ClassLoaderData* cld) { @@ -44,4 +50,63 @@ inline void MetadataAwareOopClosure::do_klass(Klass* k) { do_klass_nv(k); } +#ifdef ASSERT +// This verification is applied to all visited oops. +// The closures can turn is off by overriding should_verify_oops(). +template +void ExtendedOopClosure::verify(T* p) { + if (should_verify_oops()) { + T heap_oop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(heap_oop)) { + oop o = oopDesc::decode_heap_oop_not_null(heap_oop); + assert(Universe::heap()->is_in_closed_subset(o), + err_msg("should be in closed *p " PTR_FORMAT " " PTR_FORMAT, p2i(p), p2i(o))); + } + } +} +#endif + +// Implementation of the non-virtual do_oop dispatch. + +template +inline void Devirtualizer::do_oop(OopClosureType* closure, T* p) { + debug_only(closure->verify(p)); + closure->do_oop_nv(p); +} +template +inline void Devirtualizer::do_klass(OopClosureType* closure, Klass* k) { + closure->do_klass_nv(k); +} +template +inline bool Devirtualizer::do_metadata(OopClosureType* closure) { + // Make sure the non-virtual and the virtual versions match. + assert(closure->do_metadata_nv() == closure->do_metadata(), "Inconsistency in do_metadata"); + return closure->do_metadata_nv(); +} + +// Implementation of the virtual do_oop dispatch. + +template +void Devirtualizer::do_oop(OopClosureType* closure, T* p) { + debug_only(closure->verify(p)); + closure->do_oop(p); +} +template +void Devirtualizer::do_klass(OopClosureType* closure, Klass* k) { + closure->do_klass(k); +} +template +bool Devirtualizer::do_metadata(OopClosureType* closure) { + return closure->do_metadata(); +} + +// The list of all "specializable" oop_oop_iterate function definitions. +#define ALL_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + ALL_INSTANCE_KLASS_OOP_OOP_ITERATE_DEFN( OopClosureType, nv_suffix) \ + ALL_INSTANCE_REF_KLASS_OOP_OOP_ITERATE_DEFN( OopClosureType, nv_suffix) \ + ALL_INSTANCE_MIRROR_KLASS_OOP_OOP_ITERATE_DEFN( OopClosureType, nv_suffix) \ + ALL_INSTANCE_CLASS_LOADER_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + ALL_OBJ_ARRAY_KLASS_OOP_OOP_ITERATE_DEFN( OopClosureType, nv_suffix) \ + ALL_TYPE_ARRAY_KLASS_OOP_OOP_ITERATE_DEFN( OopClosureType, nv_suffix) + #endif // SHARE_VM_MEMORY_ITERATOR_INLINE_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/metaspace.hpp --- a/hotspot/src/share/vm/memory/metaspace.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/metaspace.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ #include "memory/allocation.hpp" #include "memory/memRegion.hpp" #include "memory/metaspaceChunkFreeListSummary.hpp" -#include "runtime/virtualspace.hpp" +#include "memory/virtualspace.hpp" #include "utilities/exceptions.hpp" // Metaspace diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/metaspaceShared.cpp --- a/hotspot/src/share/vm/memory/metaspaceShared.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp Thu May 07 20:51:12 2015 -0700 @@ -30,6 +30,8 @@ #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" +#include "interpreter/bytecodes.hpp" +#include "interpreter/bytecodeStream.hpp" #include "memory/filemap.hpp" #include "memory/gcLocker.hpp" #include "memory/metaspace.hpp" @@ -104,15 +106,33 @@ } } -// Walk all methods in the class list and assign a fingerprint. -// so that this part of the ConstMethod* is read only. -static void calculate_fingerprints() { +static void rewrite_nofast_bytecode(Method* method) { + RawBytecodeStream bcs(method); + while (!bcs.is_last_bytecode()) { + Bytecodes::Code opcode = bcs.raw_next(); + switch (opcode) { + case Bytecodes::_getfield: *bcs.bcp() = Bytecodes::_nofast_getfield; break; + case Bytecodes::_putfield: *bcs.bcp() = Bytecodes::_nofast_putfield; break; + case Bytecodes::_aload_0: *bcs.bcp() = Bytecodes::_nofast_aload_0; break; + case Bytecodes::_iload: *bcs.bcp() = Bytecodes::_nofast_iload; break; + default: break; + } + } +} + +// Walk all methods in the class list to ensure that they won't be modified at +// run time. This includes: +// [1] Rewrite all bytecodes as needed, so that the ConstMethod* will not be modified +// at run time by RewriteBytecodes/RewriteFrequentPairs +// [2] Assign a fingerprint, so one doesn't need to be assigned at run-time. +static void rewrite_nofast_bytecodes_and_calculate_fingerprints() { for (int i = 0; i < _global_klass_objects->length(); i++) { Klass* k = _global_klass_objects->at(i); if (k->oop_is_instance()) { InstanceKlass* ik = InstanceKlass::cast(k); for (int i = 0; i < ik->methods()->length(); i++) { Method* m = ik->methods()->at(i); + rewrite_nofast_bytecode(m); Fingerprinter fp(m); // The side effect of this call sets method's fingerprint field. fp.fingerprint(); @@ -476,9 +496,10 @@ tty->print_cr(" type array classes = %5d", num_type_array); } - // Update all the fingerprints in the shared methods. - tty->print("Calculating fingerprints ... "); - calculate_fingerprints(); + + // Ensure the ConstMethods won't be modified at run-time + tty->print("Updating ConstMethods ... "); + rewrite_nofast_bytecodes_and_calculate_fingerprints(); tty->print_cr("done. "); // Remove all references outside the metadata diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/metaspaceShared.hpp --- a/hotspot/src/share/vm/memory/metaspaceShared.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ #include "classfile/compactHashtable.hpp" #include "memory/allocation.hpp" #include "memory/memRegion.hpp" -#include "runtime/virtualspace.hpp" +#include "memory/virtualspace.hpp" #include "utilities/exceptions.hpp" #include "utilities/macros.hpp" diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/sharedHeap.cpp --- a/hotspot/src/share/vm/memory/sharedHeap.cpp Thu May 07 10:19:31 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "classfile/stringTable.hpp" -#include "classfile/systemDictionary.hpp" -#include "code/codeCache.hpp" -#include "gc_interface/collectedHeap.inline.hpp" -#include "memory/sharedHeap.hpp" -#include "oops/oop.inline.hpp" -#include "runtime/atomic.inline.hpp" -#include "runtime/fprofiler.hpp" -#include "runtime/java.hpp" -#include "utilities/copy.hpp" -#include "utilities/workgroup.hpp" - -SharedHeap* SharedHeap::_sh; - -SharedHeap::SharedHeap() : - CollectedHeap(), - _workers(NULL) -{ - _sh = this; // ch is static, should be set only once. - if (UseConcMarkSweepGC || UseG1GC) { - _workers = new FlexibleWorkGang("GC Thread", ParallelGCThreads, - /* are_GC_task_threads */true, - /* are_ConcurrentGC_threads */false); - if (_workers == NULL) { - vm_exit_during_initialization("Failed necessary allocation."); - } else { - _workers->initialize_workers(); - } - } -} - -bool SharedHeap::heap_lock_held_for_gc() { - Thread* t = Thread::current(); - return Heap_lock->owned_by_self() - || ( (t->is_GC_task_thread() || t->is_VM_thread()) - && _thread_holds_heap_lock_for_gc); -} - -void SharedHeap::set_par_threads(uint t) { - assert(t == 0 || !UseSerialGC, "Cannot have parallel threads"); - _n_par_threads = t; -} - -SharedHeap::StrongRootsScope::StrongRootsScope(SharedHeap* heap, bool activate) - : MarkScope(activate), _sh(heap) -{ - if (_active) { - Threads::change_thread_claim_parity(); - // Zero the claimed high water mark in the StringTable - StringTable::clear_parallel_claimed_index(); - } -} - -SharedHeap::StrongRootsScope::~StrongRootsScope() { - Threads::assert_all_threads_claimed(); -} - -void SharedHeap::set_barrier_set(BarrierSet* bs) { - _barrier_set = bs; - // Cached barrier set for fast access in oops - oopDesc::set_bs(bs); -} - -void SharedHeap::post_initialize() { - CollectedHeap::post_initialize(); - ref_processing_init(); -} - -void SharedHeap::ref_processing_init() {} diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/sharedHeap.hpp --- a/hotspot/src/share/vm/memory/sharedHeap.hpp Thu May 07 10:19:31 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,213 +0,0 @@ -/* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_VM_MEMORY_SHAREDHEAP_HPP -#define SHARE_VM_MEMORY_SHAREDHEAP_HPP - -#include "gc_interface/collectedHeap.hpp" -#include "memory/generation.hpp" - -// A "SharedHeap" is an implementation of a java heap for HotSpot. This -// is an abstract class: there may be many different kinds of heaps. This -// class defines the functions that a heap must implement, and contains -// infrastructure common to all heaps. - -class Generation; -class BarrierSet; -class GenRemSet; -class Space; -class SpaceClosure; -class OopClosure; -class OopsInGenClosure; -class ObjectClosure; -class SubTasksDone; -class WorkGang; -class FlexibleWorkGang; -class CollectorPolicy; -class KlassClosure; - -// Note on use of FlexibleWorkGang's for GC. -// There are three places where task completion is determined. -// In -// 1) ParallelTaskTerminator::offer_termination() where _n_threads -// must be set to the correct value so that count of workers that -// have offered termination will exactly match the number -// working on the task. Tasks such as those derived from GCTask -// use ParallelTaskTerminator's. Tasks that want load balancing -// by work stealing use this method to gauge completion. -// 2) SubTasksDone has a variable _n_threads that is used in -// all_tasks_completed() to determine completion. all_tasks_complete() -// counts the number of tasks that have been done and then reset -// the SubTasksDone so that it can be used again. When the number of -// tasks is set to the number of GC workers, then _n_threads must -// be set to the number of active GC workers. G1RootProcessor and -// GenCollectedHeap have SubTasksDone. -// 3) SequentialSubTasksDone has an _n_threads that is used in -// a way similar to SubTasksDone and has the same dependency on the -// number of active GC workers. CompactibleFreeListSpace and Space -// have SequentialSubTasksDone's. -// -// Examples of using SubTasksDone and SequentialSubTasksDone: -// G1RootProcessor and GenCollectedHeap::process_roots() use -// SubTasksDone* _process_strong_tasks to claim tasks for workers -// -// GenCollectedHeap::gen_process_roots() calls -// rem_set()->younger_refs_iterate() -// to scan the card table and which eventually calls down into -// CardTableModRefBS::par_non_clean_card_iterate_work(). This method -// uses SequentialSubTasksDone* _pst to claim tasks. -// Both SubTasksDone and SequentialSubTasksDone call their method -// all_tasks_completed() to count the number of GC workers that have -// finished their work. That logic is "when all the workers are -// finished the tasks are finished". -// -// The pattern that appears in the code is to set _n_threads -// to a value > 1 before a task that you would like executed in parallel -// and then to set it to 0 after that task has completed. A value of -// 0 is a "special" value in set_n_threads() which translates to -// setting _n_threads to 1. -// -// Some code uses _n_termination to decide if work should be done in -// parallel. The notorious possibly_parallel_oops_do() in threads.cpp -// is an example of such code. Look for variable "is_par" for other -// examples. -// -// The active_workers is not reset to 0 after a parallel phase. It's -// value may be used in later phases and in one instance at least -// (the parallel remark) it has to be used (the parallel remark depends -// on the partitioning done in the previous parallel scavenge). - -class SharedHeap : public CollectedHeap { - friend class VMStructs; - - friend class VM_GC_Operation; - friend class VM_CGC_Operation; - -protected: - // There should be only a single instance of "SharedHeap" in a program. - // This is enforced with the protected constructor below, which will also - // set the static pointer "_sh" to that instance. - static SharedHeap* _sh; - - // If we're doing parallel GC, use this gang of threads. - FlexibleWorkGang* _workers; - - // Full initialization is done in a concrete subtype's "initialize" - // function. - SharedHeap(); - - // Returns true if the calling thread holds the heap lock, - // or the calling thread is a par gc thread and the heap_lock is held - // by the vm thread doing a gc operation. - bool heap_lock_held_for_gc(); - // True if the heap_lock is held by the a non-gc thread invoking a gc - // operation. - bool _thread_holds_heap_lock_for_gc; - -public: - static SharedHeap* heap() { return _sh; } - - void set_barrier_set(BarrierSet* bs); - - // Does operations required after initialization has been done. - virtual void post_initialize(); - - // Initialization of ("weak") reference processing support - virtual void ref_processing_init(); - - // Iteration functions. - void oop_iterate(ExtendedOopClosure* cl) = 0; - - // Iterate over all spaces in use in the heap, in an undefined order. - virtual void space_iterate(SpaceClosure* cl) = 0; - - // A SharedHeap will contain some number of spaces. This finds the - // space whose reserved area contains the given address, or else returns - // NULL. - virtual Space* space_containing(const void* addr) const = 0; - - bool no_gc_in_progress() { return !is_gc_active(); } - - // Note, the below comment needs to be updated to reflect the changes - // introduced by JDK-8076225. This should be done as part of JDK-8076289. - // - //Some collectors will perform "process_strong_roots" in parallel. - // Such a call will involve claiming some fine-grained tasks, such as - // scanning of threads. To make this process simpler, we provide the - // "strong_roots_parity()" method. Collectors that start parallel tasks - // whose threads invoke "process_strong_roots" must - // call "change_strong_roots_parity" in sequential code starting such a - // task. (This also means that a parallel thread may only call - // process_strong_roots once.) - // - // For calls to process_roots by sequential code, the parity is - // updated automatically. - // - // The idea is that objects representing fine-grained tasks, such as - // threads, will contain a "parity" field. A task will is claimed in the - // current "process_roots" call only if its parity field is the - // same as the "strong_roots_parity"; task claiming is accomplished by - // updating the parity field to the strong_roots_parity with a CAS. - // - // If the client meats this spec, then strong_roots_parity() will have - // the following properties: - // a) to return a different value than was returned before the last - // call to change_strong_roots_parity, and - // c) to never return a distinguished value (zero) with which such - // task-claiming variables may be initialized, to indicate "never - // claimed". - public: - - // Call these in sequential code around process_roots. - // strong_roots_prologue calls change_strong_roots_parity, if - // parallel tasks are enabled. - class StrongRootsScope : public MarkingCodeBlobClosure::MarkScope { - SharedHeap* _sh; - - public: - StrongRootsScope(SharedHeap* heap, bool activate = true); - ~StrongRootsScope(); - }; - - private: - - public: - FlexibleWorkGang* workers() const { return _workers; } - - // The functions below are helper functions that a subclass of - // "SharedHeap" can use in the implementation of its virtual - // functions. - -public: - - // Do anything common to GC's. - virtual void gc_prologue(bool full) = 0; - virtual void gc_epilogue(bool full) = 0; - - // Sets the number of parallel threads that will be doing tasks - // (such as process roots) subsequently. - virtual void set_par_threads(uint t); -}; - -#endif // SHARE_VM_MEMORY_SHAREDHEAP_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/space.cpp --- a/hotspot/src/share/vm/memory/space.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/space.cpp Thu May 07 20:51:12 2015 -0700 @@ -31,6 +31,7 @@ #include "memory/blockOffsetTable.inline.hpp" #include "memory/defNewGeneration.hpp" #include "memory/genCollectedHeap.hpp" +#include "memory/genOopClosures.inline.hpp" #include "memory/space.hpp" #include "memory/space.inline.hpp" #include "memory/universe.inline.hpp" diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/strongRootsScope.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/memory/strongRootsScope.cpp Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "classfile/stringTable.hpp" +#include "code/nmethod.hpp" +#include "memory/strongRootsScope.hpp" +#include "runtime/thread.hpp" + +MarkScope::MarkScope(bool activate) : _active(activate) { + if (_active) { + nmethod::oops_do_marking_prologue(); + } +} + +MarkScope::~MarkScope() { + if (_active) { + nmethod::oops_do_marking_epilogue(); + } +} + +StrongRootsScope::StrongRootsScope(bool activate) : MarkScope(activate) { + if (_active) { + Threads::change_thread_claim_parity(); + // Zero the claimed high water mark in the StringTable + StringTable::clear_parallel_claimed_index(); + } +} + +StrongRootsScope::~StrongRootsScope() { + Threads::assert_all_threads_claimed(); +} diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/strongRootsScope.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/memory/strongRootsScope.hpp Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_MEMORY_STRONGROOTSSCOPE_HPP +#define SHARE_VM_MEMORY_STRONGROOTSSCOPE_HPP + +#include "memory/allocation.hpp" + +class MarkScope : public StackObj { + protected: + bool _active; + public: + MarkScope(bool activate = true); + ~MarkScope(); +}; + +// Sets up and tears down the required state for parallel root processing. + +class StrongRootsScope : public MarkScope { + public: + StrongRootsScope(bool activate = true); + ~StrongRootsScope(); +}; + +#endif // SHARE_VM_MEMORY_STRONGROOTSSCOPE_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/tenuredGeneration.cpp --- a/hotspot/src/share/vm/memory/tenuredGeneration.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/tenuredGeneration.cpp Thu May 07 20:51:12 2015 -0700 @@ -36,6 +36,9 @@ #include "oops/oop.inline.hpp" #include "runtime/java.hpp" #include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS +#include "gc_implementation/parNew/parOopClosures.hpp" +#endif TenuredGeneration::TenuredGeneration(ReservedSpace rs, size_t initial_byte_size, int level, diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/universe.cpp --- a/hotspot/src/share/vm/memory/universe.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/universe.cpp Thu May 07 20:51:12 2015 -0700 @@ -687,6 +687,15 @@ return JNI_OK; } +template +jint Universe::create_heap() { + assert(_collectedHeap == NULL, "Heap already created"); + Policy* policy = new Policy(); + policy->initialize_all(); + _collectedHeap = new Heap(policy); + return _collectedHeap->initialize(); +} + // Choose the heap base address and oop encoding mode // when compressed oops are used: // Unscaled - Use 32-bits oops without encoding when @@ -696,50 +705,35 @@ // HeapBased - Use compressed oops with heap base + encoding. jint Universe::initialize_heap() { - - if (UseParallelGC) { -#if INCLUDE_ALL_GCS - Universe::_collectedHeap = new ParallelScavengeHeap(); -#else // INCLUDE_ALL_GCS - fatal("UseParallelGC not supported in this VM."); -#endif // INCLUDE_ALL_GCS - - } else if (UseG1GC) { -#if INCLUDE_ALL_GCS - G1CollectorPolicyExt* g1p = new G1CollectorPolicyExt(); - g1p->initialize_all(); - G1CollectedHeap* g1h = new G1CollectedHeap(g1p); - Universe::_collectedHeap = g1h; -#else // INCLUDE_ALL_GCS - fatal("UseG1GC not supported in java kernel vm."); -#endif // INCLUDE_ALL_GCS + jint status = JNI_ERR; +#if !INCLUDE_ALL_GCS + if (UseParallelGC) { + fatal("UseParallelGC not supported in this VM."); + } else if (UseG1GC) { + fatal("UseG1GC not supported in this VM."); + } else if (UseConcMarkSweepGC) { + fatal("UseConcMarkSweepGC not supported in this VM."); +#else + if (UseParallelGC) { + status = Universe::create_heap(); + } else if (UseG1GC) { + status = Universe::create_heap(); + } else if (UseConcMarkSweepGC) { + status = Universe::create_heap(); +#endif + } else if (UseSerialGC) { + status = Universe::create_heap(); } else { - GenCollectorPolicy *gc_policy; + ShouldNotReachHere(); + } - if (UseSerialGC) { - gc_policy = new MarkSweepPolicy(); - } else if (UseConcMarkSweepGC) { -#if INCLUDE_ALL_GCS - gc_policy = new ConcurrentMarkSweepPolicy(); -#else // INCLUDE_ALL_GCS - fatal("UseConcMarkSweepGC not supported in this VM."); -#endif // INCLUDE_ALL_GCS - } else { // default old generation - gc_policy = new MarkSweepPolicy(); - } - gc_policy->initialize_all(); - - Universe::_collectedHeap = new GenCollectedHeap(gc_policy); + if (status != JNI_OK) { + return status; } ThreadLocalAllocBuffer::set_max_size(Universe::heap()->max_tlab_size()); - jint status = Universe::heap()->initialize(); - if (status != JNI_OK) { - return status; - } - #ifdef _LP64 if (UseCompressedOops) { // Subtract a page because something can get allocated at heap base. @@ -1063,7 +1057,7 @@ MemoryService::add_metaspace_memory_pools(); - MemoryService::set_universe_heap(Universe::_collectedHeap); + MemoryService::set_universe_heap(Universe::heap()); #if INCLUDE_CDS SharedClassUtil::initialize(CHECK_false); #endif diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/universe.hpp --- a/hotspot/src/share/vm/memory/universe.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/memory/universe.hpp Thu May 07 20:51:12 2015 -0700 @@ -214,6 +214,7 @@ static size_t _heap_capacity_at_last_gc; static size_t _heap_used_at_last_gc; + template static jint create_heap(); static jint initialize_heap(); static void initialize_basic_type_mirrors(TRAPS); static void fixup_mirrors(TRAPS); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/virtualspace.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/memory/virtualspace.cpp Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,1381 @@ +/* + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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/virtualspace.hpp" +#include "oops/markOop.hpp" +#include "oops/oop.inline.hpp" +#include "services/memTracker.hpp" + +PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC + +// ReservedSpace + +// Dummy constructor +ReservedSpace::ReservedSpace() : _base(NULL), _size(0), _noaccess_prefix(0), + _alignment(0), _special(false), _executable(false) { +} + +ReservedSpace::ReservedSpace(size_t size, size_t preferred_page_size) { + bool has_preferred_page_size = preferred_page_size != 0; + // Want to use large pages where possible and pad with small pages. + size_t page_size = has_preferred_page_size ? preferred_page_size : os::page_size_for_region_unaligned(size, 1); + bool large_pages = page_size != (size_t)os::vm_page_size(); + size_t alignment; + if (large_pages && has_preferred_page_size) { + alignment = MAX2(page_size, (size_t)os::vm_allocation_granularity()); + // ReservedSpace initialization requires size to be aligned to the given + // alignment. Align the size up. + size = align_size_up(size, alignment); + } else { + // Don't force the alignment to be large page aligned, + // since that will waste memory. + alignment = os::vm_allocation_granularity(); + } + initialize(size, alignment, large_pages, NULL, false); +} + +ReservedSpace::ReservedSpace(size_t size, size_t alignment, + bool large, + char* requested_address) { + initialize(size, alignment, large, requested_address, false); +} + +ReservedSpace::ReservedSpace(size_t size, size_t alignment, + bool large, + bool executable) { + initialize(size, alignment, large, NULL, executable); +} + +// Helper method. +static bool failed_to_reserve_as_requested(char* base, char* requested_address, + const size_t size, bool special) +{ + if (base == requested_address || requested_address == NULL) + return false; // did not fail + + if (base != NULL) { + // Different reserve address may be acceptable in other cases + // but for compressed oops heap should be at requested address. + assert(UseCompressedOops, "currently requested address used only for compressed oops"); + if (PrintCompressedOopsMode) { + tty->cr(); + tty->print_cr("Reserved memory not at requested address: " PTR_FORMAT " vs " PTR_FORMAT, base, requested_address); + } + // OS ignored requested address. Try different address. + if (special) { + if (!os::release_memory_special(base, size)) { + fatal("os::release_memory_special failed"); + } + } else { + if (!os::release_memory(base, size)) { + fatal("os::release_memory failed"); + } + } + } + return true; +} + +void ReservedSpace::initialize(size_t size, size_t alignment, bool large, + char* requested_address, + bool executable) { + const size_t granularity = os::vm_allocation_granularity(); + assert((size & (granularity - 1)) == 0, + "size not aligned to os::vm_allocation_granularity()"); + assert((alignment & (granularity - 1)) == 0, + "alignment not aligned to os::vm_allocation_granularity()"); + assert(alignment == 0 || is_power_of_2((intptr_t)alignment), + "not a power of 2"); + + alignment = MAX2(alignment, (size_t)os::vm_page_size()); + + _base = NULL; + _size = 0; + _special = false; + _executable = executable; + _alignment = 0; + _noaccess_prefix = 0; + if (size == 0) { + return; + } + + // If OS doesn't support demand paging for large page memory, we need + // to use reserve_memory_special() to reserve and pin the entire region. + bool special = large && !os::can_commit_large_page_memory(); + char* base = NULL; + + if (special) { + + base = os::reserve_memory_special(size, alignment, requested_address, executable); + + if (base != NULL) { + if (failed_to_reserve_as_requested(base, requested_address, size, true)) { + // OS ignored requested address. Try different address. + return; + } + // Check alignment constraints. + assert((uintptr_t) base % alignment == 0, + err_msg("Large pages returned a non-aligned address, base: " + PTR_FORMAT " alignment: " PTR_FORMAT, + base, (void*)(uintptr_t)alignment)); + _special = true; + } else { + // failed; try to reserve regular memory below + if (UseLargePages && (!FLAG_IS_DEFAULT(UseLargePages) || + !FLAG_IS_DEFAULT(LargePageSizeInBytes))) { + if (PrintCompressedOopsMode) { + tty->cr(); + tty->print_cr("Reserve regular memory without large pages."); + } + } + } + } + + if (base == NULL) { + // Optimistically assume that the OSes returns an aligned base pointer. + // When reserving a large address range, most OSes seem to align to at + // least 64K. + + // If the memory was requested at a particular address, use + // os::attempt_reserve_memory_at() to avoid over mapping something + // important. If available space is not detected, return NULL. + + if (requested_address != 0) { + base = os::attempt_reserve_memory_at(size, requested_address); + if (failed_to_reserve_as_requested(base, requested_address, size, false)) { + // OS ignored requested address. Try different address. + base = NULL; + } + } else { + base = os::reserve_memory(size, NULL, alignment); + } + + if (base == NULL) return; + + // Check alignment constraints + if ((((size_t)base) & (alignment - 1)) != 0) { + // Base not aligned, retry + if (!os::release_memory(base, size)) fatal("os::release_memory failed"); + // Make sure that size is aligned + size = align_size_up(size, alignment); + base = os::reserve_memory_aligned(size, alignment); + + if (requested_address != 0 && + failed_to_reserve_as_requested(base, requested_address, size, false)) { + // As a result of the alignment constraints, the allocated base differs + // from the requested address. Return back to the caller who can + // take remedial action (like try again without a requested address). + assert(_base == NULL, "should be"); + return; + } + } + } + // Done + _base = base; + _size = size; + _alignment = alignment; +} + + +ReservedSpace::ReservedSpace(char* base, size_t size, size_t alignment, + bool special, bool executable) { + assert((size % os::vm_allocation_granularity()) == 0, + "size not allocation aligned"); + _base = base; + _size = size; + _alignment = alignment; + _noaccess_prefix = 0; + _special = special; + _executable = executable; +} + + +ReservedSpace ReservedSpace::first_part(size_t partition_size, size_t alignment, + bool split, bool realloc) { + assert(partition_size <= size(), "partition failed"); + if (split) { + os::split_reserved_memory(base(), size(), partition_size, realloc); + } + ReservedSpace result(base(), partition_size, alignment, special(), + executable()); + return result; +} + + +ReservedSpace +ReservedSpace::last_part(size_t partition_size, size_t alignment) { + assert(partition_size <= size(), "partition failed"); + ReservedSpace result(base() + partition_size, size() - partition_size, + alignment, special(), executable()); + return result; +} + + +size_t ReservedSpace::page_align_size_up(size_t size) { + return align_size_up(size, os::vm_page_size()); +} + + +size_t ReservedSpace::page_align_size_down(size_t size) { + return align_size_down(size, os::vm_page_size()); +} + + +size_t ReservedSpace::allocation_align_size_up(size_t size) { + return align_size_up(size, os::vm_allocation_granularity()); +} + + +size_t ReservedSpace::allocation_align_size_down(size_t size) { + return align_size_down(size, os::vm_allocation_granularity()); +} + + +void ReservedSpace::release() { + if (is_reserved()) { + char *real_base = _base - _noaccess_prefix; + const size_t real_size = _size + _noaccess_prefix; + if (special()) { + os::release_memory_special(real_base, real_size); + } else{ + os::release_memory(real_base, real_size); + } + _base = NULL; + _size = 0; + _noaccess_prefix = 0; + _alignment = 0; + _special = false; + _executable = false; + } +} + +static size_t noaccess_prefix_size(size_t alignment) { + return lcm(os::vm_page_size(), alignment); +} + +void ReservedHeapSpace::establish_noaccess_prefix() { + assert(_alignment >= (size_t)os::vm_page_size(), "must be at least page size big"); + _noaccess_prefix = noaccess_prefix_size(_alignment); + + if (base() && base() + _size > (char *)OopEncodingHeapMax) { + if (true + WIN64_ONLY(&& !UseLargePages) + AIX_ONLY(&& os::vm_page_size() != SIZE_64K)) { + // Protect memory at the base of the allocated region. + // If special, the page was committed (only matters on windows) + if (!os::protect_memory(_base, _noaccess_prefix, os::MEM_PROT_NONE, _special)) { + fatal("cannot protect protection page"); + } + if (PrintCompressedOopsMode) { + tty->cr(); + tty->print_cr("Protected page at the reserved heap base: " + PTR_FORMAT " / " INTX_FORMAT " bytes", _base, _noaccess_prefix); + } + assert(Universe::narrow_oop_use_implicit_null_checks() == true, "not initialized?"); + } else { + Universe::set_narrow_oop_use_implicit_null_checks(false); + } + } + + _base += _noaccess_prefix; + _size -= _noaccess_prefix; + assert(((uintptr_t)_base % _alignment == 0), "must be exactly of required alignment"); +} + +// Tries to allocate memory of size 'size' at address requested_address with alignment 'alignment'. +// Does not check whether the reserved memory actually is at requested_address, as the memory returned +// might still fulfill the wishes of the caller. +// Assures the memory is aligned to 'alignment'. +// NOTE: If ReservedHeapSpace already points to some reserved memory this is freed, first. +void ReservedHeapSpace::try_reserve_heap(size_t size, + size_t alignment, + bool large, + char* requested_address) { + if (_base != NULL) { + // We tried before, but we didn't like the address delivered. + release(); + } + + // If OS doesn't support demand paging for large page memory, we need + // to use reserve_memory_special() to reserve and pin the entire region. + bool special = large && !os::can_commit_large_page_memory(); + char* base = NULL; + + if (PrintCompressedOopsMode && Verbose) { + tty->print("Trying to allocate at address " PTR_FORMAT " heap of size " PTR_FORMAT ".\n", + requested_address, (address)size); + } + + if (special) { + base = os::reserve_memory_special(size, alignment, requested_address, false); + + if (base != NULL) { + // Check alignment constraints. + assert((uintptr_t) base % alignment == 0, + err_msg("Large pages returned a non-aligned address, base: " + PTR_FORMAT " alignment: " PTR_FORMAT, + base, (void*)(uintptr_t)alignment)); + _special = true; + } + } + + if (base == NULL) { + // Failed; try to reserve regular memory below + if (UseLargePages && (!FLAG_IS_DEFAULT(UseLargePages) || + !FLAG_IS_DEFAULT(LargePageSizeInBytes))) { + if (PrintCompressedOopsMode) { + tty->cr(); + tty->print_cr("Reserve regular memory without large pages."); + } + } + + // Optimistically assume that the OSes returns an aligned base pointer. + // When reserving a large address range, most OSes seem to align to at + // least 64K. + + // If the memory was requested at a particular address, use + // os::attempt_reserve_memory_at() to avoid over mapping something + // important. If available space is not detected, return NULL. + + if (requested_address != 0) { + base = os::attempt_reserve_memory_at(size, requested_address); + } else { + base = os::reserve_memory(size, NULL, alignment); + } + } + if (base == NULL) { return; } + + // Done + _base = base; + _size = size; + _alignment = alignment; + + // Check alignment constraints + if ((((size_t)base) & (alignment - 1)) != 0) { + // Base not aligned, retry. + release(); + } +} + +void ReservedHeapSpace::try_reserve_range(char *highest_start, + char *lowest_start, + size_t attach_point_alignment, + char *aligned_heap_base_min_address, + char *upper_bound, + size_t size, + size_t alignment, + bool large) { + const size_t attach_range = highest_start - lowest_start; + // Cap num_attempts at possible number. + // At least one is possible even for 0 sized attach range. + const uint64_t num_attempts_possible = (attach_range / attach_point_alignment) + 1; + const uint64_t num_attempts_to_try = MIN2((uint64_t)HeapSearchSteps, num_attempts_possible); + + const size_t stepsize = (attach_range == 0) ? // Only one try. + (size_t) highest_start : align_size_up(attach_range / num_attempts_to_try, attach_point_alignment); + + // Try attach points from top to bottom. + char* attach_point = highest_start; + while (attach_point >= lowest_start && + attach_point <= highest_start && // Avoid wrap around. + ((_base == NULL) || + (_base < aligned_heap_base_min_address || _base + size > upper_bound))) { + try_reserve_heap(size, alignment, large, attach_point); + attach_point -= stepsize; + } +} + +#define SIZE_64K ((uint64_t) UCONST64( 0x10000)) +#define SIZE_256M ((uint64_t) UCONST64( 0x10000000)) +#define SIZE_32G ((uint64_t) UCONST64( 0x800000000)) + +// Helper for heap allocation. Returns an array with addresses +// (OS-specific) which are suited for disjoint base mode. Array is +// NULL terminated. +static char** get_attach_addresses_for_disjoint_mode() { + static uint64_t addresses[] = { + 2 * SIZE_32G, + 3 * SIZE_32G, + 4 * SIZE_32G, + 8 * SIZE_32G, + 10 * SIZE_32G, + 1 * SIZE_64K * SIZE_32G, + 2 * SIZE_64K * SIZE_32G, + 3 * SIZE_64K * SIZE_32G, + 4 * SIZE_64K * SIZE_32G, + 16 * SIZE_64K * SIZE_32G, + 32 * SIZE_64K * SIZE_32G, + 34 * SIZE_64K * SIZE_32G, + 0 + }; + + // Sort out addresses smaller than HeapBaseMinAddress. This assumes + // the array is sorted. + uint i = 0; + while (addresses[i] != 0 && + (addresses[i] < OopEncodingHeapMax || addresses[i] < HeapBaseMinAddress)) { + i++; + } + uint start = i; + + // Avoid more steps than requested. + i = 0; + while (addresses[start+i] != 0) { + if (i == HeapSearchSteps) { + addresses[start+i] = 0; + break; + } + i++; + } + + return (char**) &addresses[start]; +} + +void ReservedHeapSpace::initialize_compressed_heap(const size_t size, size_t alignment, bool large) { + guarantee(size + noaccess_prefix_size(alignment) <= OopEncodingHeapMax, + "can not allocate compressed oop heap for this size"); + guarantee(alignment == MAX2(alignment, (size_t)os::vm_page_size()), "alignment too small"); + assert(HeapBaseMinAddress > 0, "sanity"); + + const size_t granularity = os::vm_allocation_granularity(); + assert((size & (granularity - 1)) == 0, + "size not aligned to os::vm_allocation_granularity()"); + assert((alignment & (granularity - 1)) == 0, + "alignment not aligned to os::vm_allocation_granularity()"); + assert(alignment == 0 || is_power_of_2((intptr_t)alignment), + "not a power of 2"); + + // The necessary attach point alignment for generated wish addresses. + // This is needed to increase the chance of attaching for mmap and shmat. + const size_t os_attach_point_alignment = + AIX_ONLY(SIZE_256M) // Known shm boundary alignment. + NOT_AIX(os::vm_allocation_granularity()); + const size_t attach_point_alignment = lcm(alignment, os_attach_point_alignment); + + char *aligned_heap_base_min_address = (char *)align_ptr_up((void *)HeapBaseMinAddress, alignment); + size_t noaccess_prefix = ((aligned_heap_base_min_address + size) > (char*)OopEncodingHeapMax) ? + noaccess_prefix_size(alignment) : 0; + + // Attempt to alloc at user-given address. + if (!FLAG_IS_DEFAULT(HeapBaseMinAddress)) { + try_reserve_heap(size + noaccess_prefix, alignment, large, aligned_heap_base_min_address); + if (_base != aligned_heap_base_min_address) { // Enforce this exact address. + release(); + } + } + + // Keep heap at HeapBaseMinAddress. + if (_base == NULL) { + + // Try to allocate the heap at addresses that allow efficient oop compression. + // Different schemes are tried, in order of decreasing optimization potential. + // + // For this, try_reserve_heap() is called with the desired heap base addresses. + // A call into the os layer to allocate at a given address can return memory + // at a different address than requested. Still, this might be memory at a useful + // address. try_reserve_heap() always returns this allocated memory, as only here + // the criteria for a good heap are checked. + + // Attempt to allocate so that we can run without base and scale (32-Bit unscaled compressed oops). + // Give it several tries from top of range to bottom. + if (aligned_heap_base_min_address + size <= (char *)UnscaledOopHeapMax) { + + // Calc address range within we try to attach (range of possible start addresses). + char* const highest_start = (char *)align_ptr_down((char *)UnscaledOopHeapMax - size, attach_point_alignment); + char* const lowest_start = (char *)align_ptr_up ( aligned_heap_base_min_address , attach_point_alignment); + try_reserve_range(highest_start, lowest_start, attach_point_alignment, + aligned_heap_base_min_address, (char *)UnscaledOopHeapMax, size, alignment, large); + } + + // zerobased: Attempt to allocate in the lower 32G. + // But leave room for the compressed class pointers, which is allocated above + // the heap. + char *zerobased_max = (char *)OopEncodingHeapMax; + const size_t class_space = align_size_up(CompressedClassSpaceSize, alignment); + // For small heaps, save some space for compressed class pointer + // space so it can be decoded with no base. + if (UseCompressedClassPointers && !UseSharedSpaces && + OopEncodingHeapMax <= KlassEncodingMetaspaceMax && + (uint64_t)(aligned_heap_base_min_address + size + class_space) <= KlassEncodingMetaspaceMax) { + zerobased_max = (char *)OopEncodingHeapMax - class_space; + } + + // Give it several tries from top of range to bottom. + if (aligned_heap_base_min_address + size <= zerobased_max && // Zerobased theoretical possible. + ((_base == NULL) || // No previous try succeeded. + (_base + size > zerobased_max))) { // Unscaled delivered an arbitrary address. + + // Calc address range within we try to attach (range of possible start addresses). + char *const highest_start = (char *)align_ptr_down(zerobased_max - size, attach_point_alignment); + // Need to be careful about size being guaranteed to be less + // than UnscaledOopHeapMax due to type constraints. + char *lowest_start = aligned_heap_base_min_address; + uint64_t unscaled_end = UnscaledOopHeapMax - size; + if (unscaled_end < UnscaledOopHeapMax) { // unscaled_end wrapped if size is large + lowest_start = MAX2(lowest_start, (char*)unscaled_end); + } + lowest_start = (char *)align_ptr_up(lowest_start, attach_point_alignment); + try_reserve_range(highest_start, lowest_start, attach_point_alignment, + aligned_heap_base_min_address, zerobased_max, size, alignment, large); + } + + // Now we go for heaps with base != 0. We need a noaccess prefix to efficiently + // implement null checks. + noaccess_prefix = noaccess_prefix_size(alignment); + + // Try to attach at addresses that are aligned to OopEncodingHeapMax. Disjointbase mode. + char** addresses = get_attach_addresses_for_disjoint_mode(); + int i = 0; + while (addresses[i] && // End of array not yet reached. + ((_base == NULL) || // No previous try succeeded. + (_base + size > (char *)OopEncodingHeapMax && // Not zerobased or unscaled address. + !Universe::is_disjoint_heap_base_address((address)_base)))) { // Not disjoint address. + char* const attach_point = addresses[i]; + assert(attach_point >= aligned_heap_base_min_address, "Flag support broken"); + try_reserve_heap(size + noaccess_prefix, alignment, large, attach_point); + i++; + } + + // Last, desperate try without any placement. + if (_base == NULL) { + if (PrintCompressedOopsMode && Verbose) { + tty->print("Trying to allocate at address NULL heap of size " PTR_FORMAT ".\n", (address)size + noaccess_prefix); + } + initialize(size + noaccess_prefix, alignment, large, NULL, false); + } + } +} + +ReservedHeapSpace::ReservedHeapSpace(size_t size, size_t alignment, bool large) : ReservedSpace() { + + if (size == 0) { + return; + } + + // Heap size should be aligned to alignment, too. + guarantee(is_size_aligned(size, alignment), "set by caller"); + + if (UseCompressedOops) { + initialize_compressed_heap(size, alignment, large); + if (_size > size) { + // We allocated heap with noaccess prefix. + // It can happen we get a zerobased/unscaled heap with noaccess prefix, + // if we had to try at arbitrary address. + establish_noaccess_prefix(); + } + } else { + initialize(size, alignment, large, NULL, false); + } + + assert(markOopDesc::encode_pointer_as_mark(_base)->decode_pointer() == _base, + "area must be distinguishable from marks for mark-sweep"); + assert(markOopDesc::encode_pointer_as_mark(&_base[size])->decode_pointer() == &_base[size], + "area must be distinguishable from marks for mark-sweep"); + + if (base() > 0) { + MemTracker::record_virtual_memory_type((address)base(), mtJavaHeap); + } +} + +// Reserve space for code segment. Same as Java heap only we mark this as +// executable. +ReservedCodeSpace::ReservedCodeSpace(size_t r_size, + size_t rs_align, + bool large) : + ReservedSpace(r_size, rs_align, large, /*executable*/ true) { + MemTracker::record_virtual_memory_type((address)base(), mtCode); +} + +// VirtualSpace + +VirtualSpace::VirtualSpace() { + _low_boundary = NULL; + _high_boundary = NULL; + _low = NULL; + _high = NULL; + _lower_high = NULL; + _middle_high = NULL; + _upper_high = NULL; + _lower_high_boundary = NULL; + _middle_high_boundary = NULL; + _upper_high_boundary = NULL; + _lower_alignment = 0; + _middle_alignment = 0; + _upper_alignment = 0; + _special = false; + _executable = false; +} + + +bool VirtualSpace::initialize(ReservedSpace rs, size_t committed_size) { + const size_t max_commit_granularity = os::page_size_for_region_unaligned(rs.size(), 1); + return initialize_with_granularity(rs, committed_size, max_commit_granularity); +} + +bool VirtualSpace::initialize_with_granularity(ReservedSpace rs, size_t committed_size, size_t max_commit_granularity) { + if(!rs.is_reserved()) return false; // allocation failed. + assert(_low_boundary == NULL, "VirtualSpace already initialized"); + assert(max_commit_granularity > 0, "Granularity must be non-zero."); + + _low_boundary = rs.base(); + _high_boundary = low_boundary() + rs.size(); + + _low = low_boundary(); + _high = low(); + + _special = rs.special(); + _executable = rs.executable(); + + // When a VirtualSpace begins life at a large size, make all future expansion + // and shrinking occur aligned to a granularity of large pages. This avoids + // fragmentation of physical addresses that inhibits the use of large pages + // by the OS virtual memory system. Empirically, we see that with a 4MB + // page size, the only spaces that get handled this way are codecache and + // the heap itself, both of which provide a substantial performance + // boost in many benchmarks when covered by large pages. + // + // No attempt is made to force large page alignment at the very top and + // bottom of the space if they are not aligned so already. + _lower_alignment = os::vm_page_size(); + _middle_alignment = max_commit_granularity; + _upper_alignment = os::vm_page_size(); + + // End of each region + _lower_high_boundary = (char*) round_to((intptr_t) low_boundary(), middle_alignment()); + _middle_high_boundary = (char*) round_down((intptr_t) high_boundary(), middle_alignment()); + _upper_high_boundary = high_boundary(); + + // High address of each region + _lower_high = low_boundary(); + _middle_high = lower_high_boundary(); + _upper_high = middle_high_boundary(); + + // commit to initial size + if (committed_size > 0) { + if (!expand_by(committed_size)) { + return false; + } + } + return true; +} + + +VirtualSpace::~VirtualSpace() { + release(); +} + + +void VirtualSpace::release() { + // This does not release memory it never reserved. + // Caller must release via rs.release(); + _low_boundary = NULL; + _high_boundary = NULL; + _low = NULL; + _high = NULL; + _lower_high = NULL; + _middle_high = NULL; + _upper_high = NULL; + _lower_high_boundary = NULL; + _middle_high_boundary = NULL; + _upper_high_boundary = NULL; + _lower_alignment = 0; + _middle_alignment = 0; + _upper_alignment = 0; + _special = false; + _executable = false; +} + + +size_t VirtualSpace::committed_size() const { + return pointer_delta(high(), low(), sizeof(char)); +} + + +size_t VirtualSpace::reserved_size() const { + return pointer_delta(high_boundary(), low_boundary(), sizeof(char)); +} + + +size_t VirtualSpace::uncommitted_size() const { + return reserved_size() - committed_size(); +} + +size_t VirtualSpace::actual_committed_size() const { + // Special VirtualSpaces commit all reserved space up front. + if (special()) { + return reserved_size(); + } + + size_t committed_low = pointer_delta(_lower_high, _low_boundary, sizeof(char)); + size_t committed_middle = pointer_delta(_middle_high, _lower_high_boundary, sizeof(char)); + size_t committed_high = pointer_delta(_upper_high, _middle_high_boundary, sizeof(char)); + +#ifdef ASSERT + size_t lower = pointer_delta(_lower_high_boundary, _low_boundary, sizeof(char)); + size_t middle = pointer_delta(_middle_high_boundary, _lower_high_boundary, sizeof(char)); + size_t upper = pointer_delta(_upper_high_boundary, _middle_high_boundary, sizeof(char)); + + if (committed_high > 0) { + assert(committed_low == lower, "Must be"); + assert(committed_middle == middle, "Must be"); + } + + if (committed_middle > 0) { + assert(committed_low == lower, "Must be"); + } + if (committed_middle < middle) { + assert(committed_high == 0, "Must be"); + } + + if (committed_low < lower) { + assert(committed_high == 0, "Must be"); + assert(committed_middle == 0, "Must be"); + } +#endif + + return committed_low + committed_middle + committed_high; +} + + +bool VirtualSpace::contains(const void* p) const { + return low() <= (const char*) p && (const char*) p < high(); +} + +/* + First we need to determine if a particular virtual space is using large + pages. This is done at the initialize function and only virtual spaces + that are larger than LargePageSizeInBytes use large pages. Once we + have determined this, all expand_by and shrink_by calls must grow and + shrink by large page size chunks. If a particular request + is within the current large page, the call to commit and uncommit memory + can be ignored. In the case that the low and high boundaries of this + space is not large page aligned, the pages leading to the first large + page address and the pages after the last large page address must be + allocated with default pages. +*/ +bool VirtualSpace::expand_by(size_t bytes, bool pre_touch) { + if (uncommitted_size() < bytes) return false; + + if (special()) { + // don't commit memory if the entire space is pinned in memory + _high += bytes; + return true; + } + + char* previous_high = high(); + char* unaligned_new_high = high() + bytes; + assert(unaligned_new_high <= high_boundary(), + "cannot expand by more than upper boundary"); + + // Calculate where the new high for each of the regions should be. If + // the low_boundary() and high_boundary() are LargePageSizeInBytes aligned + // then the unaligned lower and upper new highs would be the + // lower_high() and upper_high() respectively. + char* unaligned_lower_new_high = + MIN2(unaligned_new_high, lower_high_boundary()); + char* unaligned_middle_new_high = + MIN2(unaligned_new_high, middle_high_boundary()); + char* unaligned_upper_new_high = + MIN2(unaligned_new_high, upper_high_boundary()); + + // Align the new highs based on the regions alignment. lower and upper + // alignment will always be default page size. middle alignment will be + // LargePageSizeInBytes if the actual size of the virtual space is in + // fact larger than LargePageSizeInBytes. + char* aligned_lower_new_high = + (char*) round_to((intptr_t) unaligned_lower_new_high, lower_alignment()); + char* aligned_middle_new_high = + (char*) round_to((intptr_t) unaligned_middle_new_high, middle_alignment()); + char* aligned_upper_new_high = + (char*) round_to((intptr_t) unaligned_upper_new_high, upper_alignment()); + + // Determine which regions need to grow in this expand_by call. + // If you are growing in the lower region, high() must be in that + // region so calculate the size based on high(). For the middle and + // upper regions, determine the starting point of growth based on the + // location of high(). By getting the MAX of the region's low address + // (or the previous region's high address) and high(), we can tell if it + // is an intra or inter region growth. + size_t lower_needs = 0; + if (aligned_lower_new_high > lower_high()) { + lower_needs = + pointer_delta(aligned_lower_new_high, lower_high(), sizeof(char)); + } + size_t middle_needs = 0; + if (aligned_middle_new_high > middle_high()) { + middle_needs = + pointer_delta(aligned_middle_new_high, middle_high(), sizeof(char)); + } + size_t upper_needs = 0; + if (aligned_upper_new_high > upper_high()) { + upper_needs = + pointer_delta(aligned_upper_new_high, upper_high(), sizeof(char)); + } + + // Check contiguity. + assert(low_boundary() <= lower_high() && + lower_high() <= lower_high_boundary(), + "high address must be contained within the region"); + assert(lower_high_boundary() <= middle_high() && + middle_high() <= middle_high_boundary(), + "high address must be contained within the region"); + assert(middle_high_boundary() <= upper_high() && + upper_high() <= upper_high_boundary(), + "high address must be contained within the region"); + + // Commit regions + if (lower_needs > 0) { + assert(low_boundary() <= lower_high() && + lower_high() + lower_needs <= lower_high_boundary(), + "must not expand beyond region"); + if (!os::commit_memory(lower_high(), lower_needs, _executable)) { + debug_only(warning("INFO: os::commit_memory(" PTR_FORMAT + ", lower_needs=" SIZE_FORMAT ", %d) failed", + lower_high(), lower_needs, _executable);) + return false; + } else { + _lower_high += lower_needs; + } + } + if (middle_needs > 0) { + assert(lower_high_boundary() <= middle_high() && + middle_high() + middle_needs <= middle_high_boundary(), + "must not expand beyond region"); + if (!os::commit_memory(middle_high(), middle_needs, middle_alignment(), + _executable)) { + debug_only(warning("INFO: os::commit_memory(" PTR_FORMAT + ", middle_needs=" SIZE_FORMAT ", " SIZE_FORMAT + ", %d) failed", middle_high(), middle_needs, + middle_alignment(), _executable);) + return false; + } + _middle_high += middle_needs; + } + if (upper_needs > 0) { + assert(middle_high_boundary() <= upper_high() && + upper_high() + upper_needs <= upper_high_boundary(), + "must not expand beyond region"); + if (!os::commit_memory(upper_high(), upper_needs, _executable)) { + debug_only(warning("INFO: os::commit_memory(" PTR_FORMAT + ", upper_needs=" SIZE_FORMAT ", %d) failed", + upper_high(), upper_needs, _executable);) + return false; + } else { + _upper_high += upper_needs; + } + } + + if (pre_touch || AlwaysPreTouch) { + os::pretouch_memory(previous_high, unaligned_new_high); + } + + _high += bytes; + return true; +} + +// A page is uncommitted if the contents of the entire page is deemed unusable. +// Continue to decrement the high() pointer until it reaches a page boundary +// in which case that particular page can now be uncommitted. +void VirtualSpace::shrink_by(size_t size) { + if (committed_size() < size) + fatal("Cannot shrink virtual space to negative size"); + + if (special()) { + // don't uncommit if the entire space is pinned in memory + _high -= size; + return; + } + + char* unaligned_new_high = high() - size; + assert(unaligned_new_high >= low_boundary(), "cannot shrink past lower boundary"); + + // Calculate new unaligned address + char* unaligned_upper_new_high = + MAX2(unaligned_new_high, middle_high_boundary()); + char* unaligned_middle_new_high = + MAX2(unaligned_new_high, lower_high_boundary()); + char* unaligned_lower_new_high = + MAX2(unaligned_new_high, low_boundary()); + + // Align address to region's alignment + char* aligned_upper_new_high = + (char*) round_to((intptr_t) unaligned_upper_new_high, upper_alignment()); + char* aligned_middle_new_high = + (char*) round_to((intptr_t) unaligned_middle_new_high, middle_alignment()); + char* aligned_lower_new_high = + (char*) round_to((intptr_t) unaligned_lower_new_high, lower_alignment()); + + // Determine which regions need to shrink + size_t upper_needs = 0; + if (aligned_upper_new_high < upper_high()) { + upper_needs = + pointer_delta(upper_high(), aligned_upper_new_high, sizeof(char)); + } + size_t middle_needs = 0; + if (aligned_middle_new_high < middle_high()) { + middle_needs = + pointer_delta(middle_high(), aligned_middle_new_high, sizeof(char)); + } + size_t lower_needs = 0; + if (aligned_lower_new_high < lower_high()) { + lower_needs = + pointer_delta(lower_high(), aligned_lower_new_high, sizeof(char)); + } + + // Check contiguity. + assert(middle_high_boundary() <= upper_high() && + upper_high() <= upper_high_boundary(), + "high address must be contained within the region"); + assert(lower_high_boundary() <= middle_high() && + middle_high() <= middle_high_boundary(), + "high address must be contained within the region"); + assert(low_boundary() <= lower_high() && + lower_high() <= lower_high_boundary(), + "high address must be contained within the region"); + + // Uncommit + if (upper_needs > 0) { + assert(middle_high_boundary() <= aligned_upper_new_high && + aligned_upper_new_high + upper_needs <= upper_high_boundary(), + "must not shrink beyond region"); + if (!os::uncommit_memory(aligned_upper_new_high, upper_needs)) { + debug_only(warning("os::uncommit_memory failed")); + return; + } else { + _upper_high -= upper_needs; + } + } + if (middle_needs > 0) { + assert(lower_high_boundary() <= aligned_middle_new_high && + aligned_middle_new_high + middle_needs <= middle_high_boundary(), + "must not shrink beyond region"); + if (!os::uncommit_memory(aligned_middle_new_high, middle_needs)) { + debug_only(warning("os::uncommit_memory failed")); + return; + } else { + _middle_high -= middle_needs; + } + } + if (lower_needs > 0) { + assert(low_boundary() <= aligned_lower_new_high && + aligned_lower_new_high + lower_needs <= lower_high_boundary(), + "must not shrink beyond region"); + if (!os::uncommit_memory(aligned_lower_new_high, lower_needs)) { + debug_only(warning("os::uncommit_memory failed")); + return; + } else { + _lower_high -= lower_needs; + } + } + + _high -= size; +} + +#ifndef PRODUCT +void VirtualSpace::check_for_contiguity() { + // Check contiguity. + assert(low_boundary() <= lower_high() && + lower_high() <= lower_high_boundary(), + "high address must be contained within the region"); + assert(lower_high_boundary() <= middle_high() && + middle_high() <= middle_high_boundary(), + "high address must be contained within the region"); + assert(middle_high_boundary() <= upper_high() && + upper_high() <= upper_high_boundary(), + "high address must be contained within the region"); + assert(low() >= low_boundary(), "low"); + assert(low_boundary() <= lower_high_boundary(), "lower high boundary"); + assert(upper_high_boundary() <= high_boundary(), "upper high boundary"); + assert(high() <= upper_high(), "upper high"); +} + +void VirtualSpace::print_on(outputStream* out) { + out->print ("Virtual space:"); + if (special()) out->print(" (pinned in memory)"); + out->cr(); + out->print_cr(" - committed: " SIZE_FORMAT, committed_size()); + out->print_cr(" - reserved: " SIZE_FORMAT, reserved_size()); + out->print_cr(" - [low, high]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]", low(), high()); + out->print_cr(" - [low_b, high_b]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]", low_boundary(), high_boundary()); +} + +void VirtualSpace::print() { + print_on(tty); +} + +/////////////// Unit tests /////////////// + +#ifndef PRODUCT + +#define test_log(...) \ + do {\ + if (VerboseInternalVMTests) { \ + tty->print_cr(__VA_ARGS__); \ + tty->flush(); \ + }\ + } while (false) + +class TestReservedSpace : AllStatic { + public: + static void small_page_write(void* addr, size_t size) { + size_t page_size = os::vm_page_size(); + + char* end = (char*)addr + size; + for (char* p = (char*)addr; p < end; p += page_size) { + *p = 1; + } + } + + static void release_memory_for_test(ReservedSpace rs) { + if (rs.special()) { + guarantee(os::release_memory_special(rs.base(), rs.size()), "Shouldn't fail"); + } else { + guarantee(os::release_memory(rs.base(), rs.size()), "Shouldn't fail"); + } + } + + static void test_reserved_space1(size_t size, size_t alignment) { + test_log("test_reserved_space1(%p)", (void*) (uintptr_t) size); + + assert(is_size_aligned(size, alignment), "Incorrect input parameters"); + + ReservedSpace rs(size, // size + alignment, // alignment + UseLargePages, // large + (char *)NULL); // requested_address + + test_log(" rs.special() == %d", rs.special()); + + assert(rs.base() != NULL, "Must be"); + assert(rs.size() == size, "Must be"); + + assert(is_ptr_aligned(rs.base(), alignment), "aligned sizes should always give aligned addresses"); + assert(is_size_aligned(rs.size(), alignment), "aligned sizes should always give aligned addresses"); + + if (rs.special()) { + small_page_write(rs.base(), size); + } + + release_memory_for_test(rs); + } + + static void test_reserved_space2(size_t size) { + test_log("test_reserved_space2(%p)", (void*)(uintptr_t)size); + + assert(is_size_aligned(size, os::vm_allocation_granularity()), "Must be at least AG aligned"); + + ReservedSpace rs(size); + + test_log(" rs.special() == %d", rs.special()); + + assert(rs.base() != NULL, "Must be"); + assert(rs.size() == size, "Must be"); + + if (rs.special()) { + small_page_write(rs.base(), size); + } + + release_memory_for_test(rs); + } + + static void test_reserved_space3(size_t size, size_t alignment, bool maybe_large) { + test_log("test_reserved_space3(%p, %p, %d)", + (void*)(uintptr_t)size, (void*)(uintptr_t)alignment, maybe_large); + + assert(is_size_aligned(size, os::vm_allocation_granularity()), "Must be at least AG aligned"); + assert(is_size_aligned(size, alignment), "Must be at least aligned against alignment"); + + bool large = maybe_large && UseLargePages && size >= os::large_page_size(); + + ReservedSpace rs(size, alignment, large, false); + + test_log(" rs.special() == %d", rs.special()); + + assert(rs.base() != NULL, "Must be"); + assert(rs.size() == size, "Must be"); + + if (rs.special()) { + small_page_write(rs.base(), size); + } + + release_memory_for_test(rs); + } + + + static void test_reserved_space1() { + size_t size = 2 * 1024 * 1024; + size_t ag = os::vm_allocation_granularity(); + + test_reserved_space1(size, ag); + test_reserved_space1(size * 2, ag); + test_reserved_space1(size * 10, ag); + } + + static void test_reserved_space2() { + size_t size = 2 * 1024 * 1024; + size_t ag = os::vm_allocation_granularity(); + + test_reserved_space2(size * 1); + test_reserved_space2(size * 2); + test_reserved_space2(size * 10); + test_reserved_space2(ag); + test_reserved_space2(size - ag); + test_reserved_space2(size); + test_reserved_space2(size + ag); + test_reserved_space2(size * 2); + test_reserved_space2(size * 2 - ag); + test_reserved_space2(size * 2 + ag); + test_reserved_space2(size * 3); + test_reserved_space2(size * 3 - ag); + test_reserved_space2(size * 3 + ag); + test_reserved_space2(size * 10); + test_reserved_space2(size * 10 + size / 2); + } + + static void test_reserved_space3() { + size_t ag = os::vm_allocation_granularity(); + + test_reserved_space3(ag, ag , false); + test_reserved_space3(ag * 2, ag , false); + test_reserved_space3(ag * 3, ag , false); + test_reserved_space3(ag * 2, ag * 2, false); + test_reserved_space3(ag * 4, ag * 2, false); + test_reserved_space3(ag * 8, ag * 2, false); + test_reserved_space3(ag * 4, ag * 4, false); + test_reserved_space3(ag * 8, ag * 4, false); + test_reserved_space3(ag * 16, ag * 4, false); + + if (UseLargePages) { + size_t lp = os::large_page_size(); + + // Without large pages + test_reserved_space3(lp, ag * 4, false); + test_reserved_space3(lp * 2, ag * 4, false); + test_reserved_space3(lp * 4, ag * 4, false); + test_reserved_space3(lp, lp , false); + test_reserved_space3(lp * 2, lp , false); + test_reserved_space3(lp * 3, lp , false); + test_reserved_space3(lp * 2, lp * 2, false); + test_reserved_space3(lp * 4, lp * 2, false); + test_reserved_space3(lp * 8, lp * 2, false); + + // With large pages + test_reserved_space3(lp, ag * 4 , true); + test_reserved_space3(lp * 2, ag * 4, true); + test_reserved_space3(lp * 4, ag * 4, true); + test_reserved_space3(lp, lp , true); + test_reserved_space3(lp * 2, lp , true); + test_reserved_space3(lp * 3, lp , true); + test_reserved_space3(lp * 2, lp * 2, true); + test_reserved_space3(lp * 4, lp * 2, true); + test_reserved_space3(lp * 8, lp * 2, true); + } + } + + static void test_reserved_space() { + test_reserved_space1(); + test_reserved_space2(); + test_reserved_space3(); + } +}; + +void TestReservedSpace_test() { + TestReservedSpace::test_reserved_space(); +} + +#define assert_equals(actual, expected) \ + assert(actual == expected, \ + err_msg("Got " SIZE_FORMAT " expected " \ + SIZE_FORMAT, actual, expected)); + +#define assert_ge(value1, value2) \ + assert(value1 >= value2, \ + err_msg("'" #value1 "': " SIZE_FORMAT " '" \ + #value2 "': " SIZE_FORMAT, value1, value2)); + +#define assert_lt(value1, value2) \ + assert(value1 < value2, \ + err_msg("'" #value1 "': " SIZE_FORMAT " '" \ + #value2 "': " SIZE_FORMAT, value1, value2)); + + +class TestVirtualSpace : AllStatic { + enum TestLargePages { + Default, + Disable, + Reserve, + Commit + }; + + static ReservedSpace reserve_memory(size_t reserve_size_aligned, TestLargePages mode) { + switch(mode) { + default: + case Default: + case Reserve: + return ReservedSpace(reserve_size_aligned); + case Disable: + case Commit: + return ReservedSpace(reserve_size_aligned, + os::vm_allocation_granularity(), + /* large */ false, /* exec */ false); + } + } + + static bool initialize_virtual_space(VirtualSpace& vs, ReservedSpace rs, TestLargePages mode) { + switch(mode) { + default: + case Default: + case Reserve: + return vs.initialize(rs, 0); + case Disable: + return vs.initialize_with_granularity(rs, 0, os::vm_page_size()); + case Commit: + return vs.initialize_with_granularity(rs, 0, os::page_size_for_region_unaligned(rs.size(), 1)); + } + } + + public: + static void test_virtual_space_actual_committed_space(size_t reserve_size, size_t commit_size, + TestLargePages mode = Default) { + size_t granularity = os::vm_allocation_granularity(); + size_t reserve_size_aligned = align_size_up(reserve_size, granularity); + + ReservedSpace reserved = reserve_memory(reserve_size_aligned, mode); + + assert(reserved.is_reserved(), "Must be"); + + VirtualSpace vs; + bool initialized = initialize_virtual_space(vs, reserved, mode); + assert(initialized, "Failed to initialize VirtualSpace"); + + vs.expand_by(commit_size, false); + + if (vs.special()) { + assert_equals(vs.actual_committed_size(), reserve_size_aligned); + } else { + assert_ge(vs.actual_committed_size(), commit_size); + // Approximate the commit granularity. + // Make sure that we don't commit using large pages + // if large pages has been disabled for this VirtualSpace. + size_t commit_granularity = (mode == Disable || !UseLargePages) ? + os::vm_page_size() : os::large_page_size(); + assert_lt(vs.actual_committed_size(), commit_size + commit_granularity); + } + + reserved.release(); + } + + static void test_virtual_space_actual_committed_space_one_large_page() { + if (!UseLargePages) { + return; + } + + size_t large_page_size = os::large_page_size(); + + ReservedSpace reserved(large_page_size, large_page_size, true, false); + + assert(reserved.is_reserved(), "Must be"); + + VirtualSpace vs; + bool initialized = vs.initialize(reserved, 0); + assert(initialized, "Failed to initialize VirtualSpace"); + + vs.expand_by(large_page_size, false); + + assert_equals(vs.actual_committed_size(), large_page_size); + + reserved.release(); + } + + static void test_virtual_space_actual_committed_space() { + test_virtual_space_actual_committed_space(4 * K, 0); + test_virtual_space_actual_committed_space(4 * K, 4 * K); + test_virtual_space_actual_committed_space(8 * K, 0); + test_virtual_space_actual_committed_space(8 * K, 4 * K); + test_virtual_space_actual_committed_space(8 * K, 8 * K); + test_virtual_space_actual_committed_space(12 * K, 0); + test_virtual_space_actual_committed_space(12 * K, 4 * K); + test_virtual_space_actual_committed_space(12 * K, 8 * K); + test_virtual_space_actual_committed_space(12 * K, 12 * K); + test_virtual_space_actual_committed_space(64 * K, 0); + test_virtual_space_actual_committed_space(64 * K, 32 * K); + test_virtual_space_actual_committed_space(64 * K, 64 * K); + test_virtual_space_actual_committed_space(2 * M, 0); + test_virtual_space_actual_committed_space(2 * M, 4 * K); + test_virtual_space_actual_committed_space(2 * M, 64 * K); + test_virtual_space_actual_committed_space(2 * M, 1 * M); + test_virtual_space_actual_committed_space(2 * M, 2 * M); + test_virtual_space_actual_committed_space(10 * M, 0); + test_virtual_space_actual_committed_space(10 * M, 4 * K); + test_virtual_space_actual_committed_space(10 * M, 8 * K); + test_virtual_space_actual_committed_space(10 * M, 1 * M); + test_virtual_space_actual_committed_space(10 * M, 2 * M); + test_virtual_space_actual_committed_space(10 * M, 5 * M); + test_virtual_space_actual_committed_space(10 * M, 10 * M); + } + + static void test_virtual_space_disable_large_pages() { + if (!UseLargePages) { + return; + } + // These test cases verify that if we force VirtualSpace to disable large pages + test_virtual_space_actual_committed_space(10 * M, 0, Disable); + test_virtual_space_actual_committed_space(10 * M, 4 * K, Disable); + test_virtual_space_actual_committed_space(10 * M, 8 * K, Disable); + test_virtual_space_actual_committed_space(10 * M, 1 * M, Disable); + test_virtual_space_actual_committed_space(10 * M, 2 * M, Disable); + test_virtual_space_actual_committed_space(10 * M, 5 * M, Disable); + test_virtual_space_actual_committed_space(10 * M, 10 * M, Disable); + + test_virtual_space_actual_committed_space(10 * M, 0, Reserve); + test_virtual_space_actual_committed_space(10 * M, 4 * K, Reserve); + test_virtual_space_actual_committed_space(10 * M, 8 * K, Reserve); + test_virtual_space_actual_committed_space(10 * M, 1 * M, Reserve); + test_virtual_space_actual_committed_space(10 * M, 2 * M, Reserve); + test_virtual_space_actual_committed_space(10 * M, 5 * M, Reserve); + test_virtual_space_actual_committed_space(10 * M, 10 * M, Reserve); + + test_virtual_space_actual_committed_space(10 * M, 0, Commit); + test_virtual_space_actual_committed_space(10 * M, 4 * K, Commit); + test_virtual_space_actual_committed_space(10 * M, 8 * K, Commit); + test_virtual_space_actual_committed_space(10 * M, 1 * M, Commit); + test_virtual_space_actual_committed_space(10 * M, 2 * M, Commit); + test_virtual_space_actual_committed_space(10 * M, 5 * M, Commit); + test_virtual_space_actual_committed_space(10 * M, 10 * M, Commit); + } + + static void test_virtual_space() { + test_virtual_space_actual_committed_space(); + test_virtual_space_actual_committed_space_one_large_page(); + test_virtual_space_disable_large_pages(); + } +}; + +void TestVirtualSpace_test() { + TestVirtualSpace::test_virtual_space(); +} + +#endif // PRODUCT + +#endif diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/memory/virtualspace.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/memory/virtualspace.hpp Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,222 @@ +/* + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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_RUNTIME_VIRTUALSPACE_HPP +#define SHARE_VM_RUNTIME_VIRTUALSPACE_HPP + +#include "memory/allocation.hpp" + +// ReservedSpace is a data structure for reserving a contiguous address range. + +class ReservedSpace VALUE_OBJ_CLASS_SPEC { + friend class VMStructs; + protected: + char* _base; + size_t _size; + size_t _noaccess_prefix; + size_t _alignment; + bool _special; + private: + bool _executable; + + // ReservedSpace + ReservedSpace(char* base, size_t size, size_t alignment, bool special, + bool executable); + protected: + void initialize(size_t size, size_t alignment, bool large, + char* requested_address, + bool executable); + + public: + // Constructor + ReservedSpace(); + // Initialize the reserved space with the given size. If preferred_page_size + // is set, use this as minimum page size/alignment. This may waste some space + // if the given size is not aligned to that value, as the reservation will be + // aligned up to the final alignment in this case. + ReservedSpace(size_t size, size_t preferred_page_size = 0); + ReservedSpace(size_t size, size_t alignment, bool large, + char* requested_address = NULL); + ReservedSpace(size_t size, size_t alignment, bool large, bool executable); + + // Accessors + char* base() const { return _base; } + size_t size() const { return _size; } + size_t alignment() const { return _alignment; } + bool special() const { return _special; } + bool executable() const { return _executable; } + size_t noaccess_prefix() const { return _noaccess_prefix; } + bool is_reserved() const { return _base != NULL; } + void release(); + + // Splitting + ReservedSpace first_part(size_t partition_size, size_t alignment, + bool split = false, bool realloc = true); + ReservedSpace last_part (size_t partition_size, size_t alignment); + + // These simply call the above using the default alignment. + inline ReservedSpace first_part(size_t partition_size, + bool split = false, bool realloc = true); + inline ReservedSpace last_part (size_t partition_size); + + // Alignment + static size_t page_align_size_up(size_t size); + static size_t page_align_size_down(size_t size); + static size_t allocation_align_size_up(size_t size); + static size_t allocation_align_size_down(size_t size); +}; + +ReservedSpace +ReservedSpace::first_part(size_t partition_size, bool split, bool realloc) +{ + return first_part(partition_size, alignment(), split, realloc); +} + +ReservedSpace ReservedSpace::last_part(size_t partition_size) +{ + return last_part(partition_size, alignment()); +} + +// Class encapsulating behavior specific of memory space reserved for Java heap. +class ReservedHeapSpace : public ReservedSpace { + private: + void try_reserve_heap(size_t size, size_t alignment, bool large, + char *requested_address); + void try_reserve_range(char *highest_start, char *lowest_start, + size_t attach_point_alignment, char *aligned_HBMA, + char *upper_bound, size_t size, size_t alignment, bool large); + void initialize_compressed_heap(const size_t size, size_t alignment, bool large); + // Create protection page at the beginning of the space. + void establish_noaccess_prefix(); + public: + // Constructor. Tries to find a heap that is good for compressed oops. + ReservedHeapSpace(size_t size, size_t forced_base_alignment, bool large); + // Returns the base to be used for compression, i.e. so that null can be + // encoded safely and implicit null checks can work. + char *compressed_oop_base() { return _base - _noaccess_prefix; } +}; + +// Class encapsulating behavior specific memory space for Code +class ReservedCodeSpace : public ReservedSpace { + public: + // Constructor + ReservedCodeSpace(size_t r_size, size_t rs_align, bool large); +}; + +// VirtualSpace is data structure for committing a previously reserved address range in smaller chunks. + +class VirtualSpace VALUE_OBJ_CLASS_SPEC { + friend class VMStructs; + private: + // Reserved area + char* _low_boundary; + char* _high_boundary; + + // Committed area + char* _low; + char* _high; + + // The entire space has been committed and pinned in memory, no + // os::commit_memory() or os::uncommit_memory(). + bool _special; + + // Need to know if commit should be executable. + bool _executable; + + // MPSS Support + // Each virtualspace region has a lower, middle, and upper region. + // Each region has an end boundary and a high pointer which is the + // high water mark for the last allocated byte. + // The lower and upper unaligned to LargePageSizeInBytes uses default page. + // size. The middle region uses large page size. + char* _lower_high; + char* _middle_high; + char* _upper_high; + + char* _lower_high_boundary; + char* _middle_high_boundary; + char* _upper_high_boundary; + + size_t _lower_alignment; + size_t _middle_alignment; + size_t _upper_alignment; + + // MPSS Accessors + char* lower_high() const { return _lower_high; } + char* middle_high() const { return _middle_high; } + char* upper_high() const { return _upper_high; } + + char* lower_high_boundary() const { return _lower_high_boundary; } + char* middle_high_boundary() const { return _middle_high_boundary; } + char* upper_high_boundary() const { return _upper_high_boundary; } + + size_t lower_alignment() const { return _lower_alignment; } + size_t middle_alignment() const { return _middle_alignment; } + size_t upper_alignment() const { return _upper_alignment; } + + public: + // Committed area + char* low() const { return _low; } + char* high() const { return _high; } + + // Reserved area + char* low_boundary() const { return _low_boundary; } + char* high_boundary() const { return _high_boundary; } + + bool special() const { return _special; } + + public: + // Initialization + VirtualSpace(); + bool initialize_with_granularity(ReservedSpace rs, size_t committed_byte_size, size_t max_commit_ganularity); + bool initialize(ReservedSpace rs, size_t committed_byte_size); + + // Destruction + ~VirtualSpace(); + + // Reserved memory + size_t reserved_size() const; + // Actually committed OS memory + size_t actual_committed_size() const; + // Memory used/expanded in this virtual space + size_t committed_size() const; + // Memory left to use/expand in this virtual space + size_t uncommitted_size() const; + + bool contains(const void* p) const; + + // Operations + // returns true on success, false otherwise + bool expand_by(size_t bytes, bool pre_touch = false); + void shrink_by(size_t bytes); + void release(); + + void check_for_contiguity() PRODUCT_RETURN; + + // Debugging + void print_on(outputStream* out) PRODUCT_RETURN; + void print(); +}; + +#endif // SHARE_VM_RUNTIME_VIRTUALSPACE_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/constMethod.hpp --- a/hotspot/src/share/vm/oops/constMethod.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/oops/constMethod.hpp Thu May 07 20:51:12 2015 -0700 @@ -32,7 +32,6 @@ // processes in a read-only section with Class Data Sharing (CDS). It's important // that this class doesn't have virtual functions because the vptr cannot be shared // with CDS. -// (*)RewriteByteCodes and RewriteFrequentPairs is an exception but turned off in CDS // // Note that most applications load thousands of methods, so keeping the size of this // structure small has a big impact on footprint. diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/cpCache.cpp --- a/hotspot/src/share/vm/oops/cpCache.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/oops/cpCache.cpp Thu May 07 20:51:12 2015 -0700 @@ -606,44 +606,6 @@ // RedefineClasses() API support: // If any entry of this ConstantPoolCache points to any of // old_methods, replace it with the corresponding new_method. -void ConstantPoolCache::adjust_method_entries(Method** old_methods, Method** new_methods, - int methods_length, bool * trace_name_printed) { - - if (methods_length == 0) { - // nothing to do if there are no methods - return; - } - - // get shorthand for the interesting class - Klass* old_holder = old_methods[0]->method_holder(); - - for (int i = 0; i < length(); i++) { - if (entry_at(i)->get_interesting_method_entry(old_holder) == NULL) { - // skip uninteresting methods - continue; - } - - // The ConstantPoolCache contains entries for several different - // things, but we only care about methods. In fact, we only care - // about methods in the same class as the one that contains the - // old_methods. At this point, we have an interesting entry. - - for (int j = 0; j < methods_length; j++) { - Method* old_method = old_methods[j]; - Method* new_method = new_methods[j]; - - if (entry_at(i)->adjust_method_entry(old_method, new_method, - trace_name_printed)) { - // current old_method matched this entry and we updated it so - // break out and get to the next interesting entry if there one - break; - } - } - } -} - -// If any entry of this ConstantPoolCache points to any of -// old_methods, replace it with the corresponding new_method. void ConstantPoolCache::adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed) { for (int i = 0; i < length(); i++) { ConstantPoolCacheEntry* entry = entry_at(i); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/cpCache.hpp --- a/hotspot/src/share/vm/oops/cpCache.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/oops/cpCache.hpp Thu May 07 20:51:12 2015 -0700 @@ -477,8 +477,6 @@ // trace_name_printed is set to true if the current call has // printed the klass name so that other routines in the adjust_* // group don't print the klass name. - void adjust_method_entries(Method** old_methods, Method** new_methods, - int methods_length, bool* trace_name_printed); void adjust_method_entries(InstanceKlass* holder, bool* trace_name_printed); bool check_no_old_or_obsolete_entries(); void dump_cache(); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/instanceClassLoaderKlass.cpp --- a/hotspot/src/share/vm/oops/instanceClassLoaderKlass.cpp Thu May 07 10:19:31 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "classfile/javaClasses.hpp" -#include "classfile/systemDictionary.hpp" -#include "gc_implementation/shared/markSweep.inline.hpp" -#include "gc_interface/collectedHeap.inline.hpp" -#include "memory/genOopClosures.inline.hpp" -#include "memory/iterator.inline.hpp" -#include "memory/oopFactory.hpp" -#include "memory/specialized_oop_closures.hpp" -#include "oops/instanceKlass.hpp" -#include "oops/instanceClassLoaderKlass.hpp" -#include "oops/instanceMirrorKlass.hpp" -#include "oops/instanceOop.hpp" -#include "oops/oop.inline.hpp" -#include "oops/symbol.hpp" -#include "runtime/handles.inline.hpp" -#include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS -#include "gc_implementation/parNew/parOopClosures.inline.hpp" -#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" -#endif // INCLUDE_ALL_GCS - -// Macro to define InstanceClassLoaderKlass::oop_oop_iterate for virtual/nonvirtual for -// all closures. Macros calling macros above for each oop size. -// Since ClassLoader objects have only a pointer to the loader_data, they are not -// compressed nor does the pointer move. - -#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)\ - \ -int InstanceClassLoaderKlass:: \ -oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { \ - /* Get size before changing pointers */ \ - int size = InstanceKlass::oop_oop_iterate##nv_suffix(obj, closure); \ - \ - if_do_metadata_checked(closure, nv_suffix) { \ - ClassLoaderData* cld = java_lang_ClassLoader::loader_data(obj); \ - /* cld can be null if we have a non-registered class loader. */ \ - if (cld != NULL) { \ - closure->do_class_loader_data(cld); \ - } \ - } \ - \ - return size; \ -} - -#if INCLUDE_ALL_GCS -#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ - \ -int InstanceClassLoaderKlass:: \ -oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) { \ - /* Get size before changing pointers */ \ - int size = InstanceKlass::oop_oop_iterate_backwards##nv_suffix(obj, closure); \ - return size; \ -} -#endif // INCLUDE_ALL_GCS - - -#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ - \ -int InstanceClassLoaderKlass:: \ -oop_oop_iterate##nv_suffix##_m(oop obj, \ - OopClosureType* closure, \ - MemRegion mr) { \ - int size = InstanceKlass::oop_oop_iterate##nv_suffix##_m(obj, closure, mr); \ - \ - if_do_metadata_checked(closure, nv_suffix) { \ - if (mr.contains(obj)) { \ - ClassLoaderData* cld = java_lang_ClassLoader::loader_data(obj); \ - /* cld can be null if we have a non-registered class loader. */ \ - if (cld != NULL) { \ - closure->do_class_loader_data(cld); \ - } \ - } \ - } \ - \ - return size; \ -} - -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN) -#if INCLUDE_ALL_GCS -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -#endif // INCLUDE_ALL_GCS -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN_m) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN_m) - -void InstanceClassLoaderKlass::oop_follow_contents(oop obj) { - InstanceKlass::oop_follow_contents(obj); - ClassLoaderData * const loader_data = java_lang_ClassLoader::loader_data(obj); - - // We must NULL check here, since the class loader - // can be found before the loader data has been set up. - if(loader_data != NULL) { - MarkSweep::follow_class_loader(loader_data); - } -} - -#if INCLUDE_ALL_GCS -void InstanceClassLoaderKlass::oop_follow_contents(ParCompactionManager* cm, - oop obj) { - InstanceKlass::oop_follow_contents(cm, obj); - ClassLoaderData * const loader_data = java_lang_ClassLoader::loader_data(obj); - if (loader_data != NULL) { - PSParallelCompact::follow_class_loader(cm, loader_data); - } -} - -void InstanceClassLoaderKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { - InstanceKlass::oop_push_contents(pm, obj); - - // This is called by the young collector. It will already have taken care of - // all class loader data. So, we don't have to follow the class loader -> - // class loader data link. -} - -int InstanceClassLoaderKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { - InstanceKlass::oop_update_pointers(cm, obj); - return size_helper(); -} -#endif // INCLUDE_ALL_GCS - diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp --- a/hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp Thu May 07 20:51:12 2015 -0700 @@ -48,34 +48,60 @@ InstanceClassLoaderKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); } - // Iterators - int oop_oop_iterate(oop obj, ExtendedOopClosure* blk) { - return oop_oop_iterate_v(obj, blk); - } - int oop_oop_iterate_m(oop obj, ExtendedOopClosure* blk, MemRegion mr) { - return oop_oop_iterate_v_m(obj, blk, mr); - } + // GC specific object visitors + // + // Mark Sweep + void oop_ms_follow_contents(oop obj); + int oop_ms_adjust_pointers(oop obj); +#if INCLUDE_ALL_GCS + // Parallel Scavenge + void oop_ps_push_contents( oop obj, PSPromotionManager* pm); + // Parallel Compact + void oop_pc_follow_contents(oop obj, ParCompactionManager* cm); + void oop_pc_update_pointers(oop obj); +#endif + + // Oop fields (and metadata) iterators + // [nv = true] Use non-virtual calls to do_oop_nv. + // [nv = false] Use virtual calls to do_oop. + // + // The InstanceClassLoaderKlass iterators also visit the CLD pointer (or mirror of anonymous klasses.) -#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ - int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* blk); \ + private: + // Forward iteration + // Iterate over the oop fields and metadata. + template + inline int oop_oop_iterate(oop obj, OopClosureType* closure); + +#if INCLUDE_ALL_GCS + // Reverse iteration + // Iterate over the oop fields and metadata. + template + inline int oop_oop_iterate_reverse(oop obj, OopClosureType* closure); +#endif + + // Bounded range iteration + // Iterate over the oop fields and metadata. + template + inline int oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr); + + public: + +#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ + int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* blk); \ int oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* blk, MemRegion mr); ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DECL) #if INCLUDE_ALL_GCS -#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ +#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* blk); ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) #endif // INCLUDE_ALL_GCS - // Garbage collection - void oop_follow_contents(oop obj); - - // Parallel Scavenge and Parallel Old - PARALLEL_GC_DECLS }; #endif // SHARE_VM_OOPS_INSTANCECLASSLOADERKLASS_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/instanceClassLoaderKlass.inline.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/oops/instanceClassLoaderKlass.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_OOPS_INSTANCECLASSLOADERKLASS_INLINE_HPP +#define SHARE_VM_OOPS_INSTANCECLASSLOADERKLASS_INLINE_HPP + +#include "classfile/javaClasses.hpp" +#include "oops/instanceClassLoaderKlass.hpp" +#include "oops/instanceKlass.inline.hpp" +#include "oops/oop.inline.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" + +template +inline int InstanceClassLoaderKlass::oop_oop_iterate(oop obj, OopClosureType* closure) { + int size = InstanceKlass::oop_oop_iterate(obj, closure); + + if (Devirtualizer::do_metadata(closure)) { + ClassLoaderData* cld = java_lang_ClassLoader::loader_data(obj); + // cld can be null if we have a non-registered class loader. + if (cld != NULL) { + closure->do_class_loader_data(cld); + } + } + + return size; +} + +#if INCLUDE_ALL_GCS +template +inline int InstanceClassLoaderKlass::oop_oop_iterate_reverse(oop obj, OopClosureType* closure) { + int size = InstanceKlass::oop_oop_iterate_reverse(obj, closure); + + assert(!Devirtualizer::do_metadata(closure), + "Code to handle metadata is not implemented"); + + return size; +} +#endif // INCLUDE_ALL_GCS + + +template +inline int InstanceClassLoaderKlass::oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr) { + int size = InstanceKlass::oop_oop_iterate_bounded(obj, closure, mr); + + if (Devirtualizer::do_metadata(closure)) { + if (mr.contains(obj)) { + ClassLoaderData* cld = java_lang_ClassLoader::loader_data(obj); + // cld can be null if we have a non-registered class loader. + if (cld != NULL) { + closure->do_class_loader_data(cld); + } + } + } + + return size; +} + + +#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + \ +int InstanceClassLoaderKlass::oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { \ + return oop_oop_iterate(obj, closure); \ +} + +#if INCLUDE_ALL_GCS +#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ + \ +int InstanceClassLoaderKlass::oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) { \ + return oop_oop_iterate_reverse(obj, closure); \ +} +#else +#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) +#endif + + +#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ + \ +int InstanceClassLoaderKlass::oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr) { \ + return oop_oop_iterate_bounded(obj, closure, mr); \ +} + +#define ALL_INSTANCE_CLASS_LOADER_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN( OopClosureType, nv_suffix) \ + InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN_m( OopClosureType, nv_suffix) \ + InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) + +#endif // SHARE_VM_OOPS_INSTANCECLASSLOADERKLASS_INLINE_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/instanceKlass.cpp --- a/hotspot/src/share/vm/oops/instanceKlass.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Thu May 07 20:51:12 2015 -0700 @@ -28,12 +28,10 @@ #include "classfile/verifier.hpp" #include "classfile/vmSymbols.hpp" #include "compiler/compileBroker.hpp" -#include "gc_implementation/shared/markSweep.inline.hpp" #include "gc_interface/collectedHeap.inline.hpp" #include "interpreter/oopMapCache.hpp" #include "interpreter/rewriter.hpp" #include "jvmtifiles/jvmti.h" -#include "memory/genOopClosures.inline.hpp" #include "memory/heapInspection.hpp" #include "memory/iterator.inline.hpp" #include "memory/metadataFactory.hpp" @@ -41,7 +39,7 @@ #include "memory/specialized_oop_closures.hpp" #include "oops/fieldStreams.hpp" #include "oops/instanceClassLoaderKlass.hpp" -#include "oops/instanceKlass.hpp" +#include "oops/instanceKlass.inline.hpp" #include "oops/instanceMirrorKlass.hpp" #include "oops/instanceOop.hpp" #include "oops/klass.inline.hpp" @@ -64,17 +62,6 @@ #include "services/threadService.hpp" #include "utilities/dtrace.hpp" #include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS -#include "gc_implementation/concurrentMarkSweep/cmsOopClosures.inline.hpp" -#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" -#include "gc_implementation/g1/g1OopClosures.inline.hpp" -#include "gc_implementation/g1/g1RemSet.inline.hpp" -#include "gc_implementation/g1/heapRegionManager.inline.hpp" -#include "gc_implementation/parNew/parOopClosures.inline.hpp" -#include "gc_implementation/parallelScavenge/parallelScavengeHeap.inline.hpp" -#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" -#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" -#endif // INCLUDE_ALL_GCS #ifdef COMPILER1 #include "c1/c1_Compiler.hpp" #endif @@ -716,23 +703,6 @@ // Set up method entry points for compiler and interpreter . m->link_method(m, CHECK); - - // This is for JVMTI and unrelated to relocator but the last thing we do -#ifdef ASSERT - if (StressMethodComparator) { - ResourceMark rm(THREAD); - static int nmc = 0; - for (int j = i; j >= 0 && j >= i-4; j--) { - if ((++nmc % 1000) == 0) tty->print_cr("Have run MethodComparator %d times...", nmc); - bool z = MethodComparator::methods_EMCP(m(), - methods()->at(j)); - if (j == i && !z) { - tty->print("MethodComparator FAIL: "); m->print(); m->print_codes(); - assert(z, "method must compare equal to itself"); - } - } - } -#endif //ASSERT } } @@ -2010,288 +1980,6 @@ } #endif //PRODUCT - -// Garbage collection - -#ifdef ASSERT -template void assert_is_in(T *p) { - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop)) { - oop o = oopDesc::decode_heap_oop_not_null(heap_oop); - assert(Universe::heap()->is_in(o), "should be in heap"); - } -} -template void assert_is_in_closed_subset(T *p) { - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop)) { - oop o = oopDesc::decode_heap_oop_not_null(heap_oop); - assert(Universe::heap()->is_in_closed_subset(o), - err_msg("should be in closed *p " INTPTR_FORMAT " " INTPTR_FORMAT, (address)p, (address)o)); - } -} -template void assert_is_in_reserved(T *p) { - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop)) { - oop o = oopDesc::decode_heap_oop_not_null(heap_oop); - assert(Universe::heap()->is_in_reserved(o), "should be in reserved"); - } -} -template void assert_nothing(T *p) {} - -#else -template void assert_is_in(T *p) {} -template void assert_is_in_closed_subset(T *p) {} -template void assert_is_in_reserved(T *p) {} -template void assert_nothing(T *p) {} -#endif // ASSERT - -// -// Macros that iterate over areas of oops which are specialized on type of -// oop pointer either narrow or wide, depending on UseCompressedOops -// -// Parameters are: -// T - type of oop to point to (either oop or narrowOop) -// start_p - starting pointer for region to iterate over -// count - number of oops or narrowOops to iterate over -// do_oop - action to perform on each oop (it's arbitrary C code which -// makes it more efficient to put in a macro rather than making -// it a template function) -// assert_fn - assert function which is template function because performance -// doesn't matter when enabled. -#define InstanceKlass_SPECIALIZED_OOP_ITERATE( \ - T, start_p, count, do_oop, \ - assert_fn) \ -{ \ - T* p = (T*)(start_p); \ - T* const end = p + (count); \ - while (p < end) { \ - (assert_fn)(p); \ - do_oop; \ - ++p; \ - } \ -} - -#define InstanceKlass_SPECIALIZED_OOP_REVERSE_ITERATE( \ - T, start_p, count, do_oop, \ - assert_fn) \ -{ \ - T* const start = (T*)(start_p); \ - T* p = start + (count); \ - while (start < p) { \ - --p; \ - (assert_fn)(p); \ - do_oop; \ - } \ -} - -#define InstanceKlass_SPECIALIZED_BOUNDED_OOP_ITERATE( \ - T, start_p, count, low, high, \ - do_oop, assert_fn) \ -{ \ - T* const l = (T*)(low); \ - T* const h = (T*)(high); \ - assert(mask_bits((intptr_t)l, sizeof(T)-1) == 0 && \ - mask_bits((intptr_t)h, sizeof(T)-1) == 0, \ - "bounded region must be properly aligned"); \ - T* p = (T*)(start_p); \ - T* end = p + (count); \ - if (p < l) p = l; \ - if (end > h) end = h; \ - while (p < end) { \ - (assert_fn)(p); \ - do_oop; \ - ++p; \ - } \ -} - - -// The following macros call specialized macros, passing either oop or -// narrowOop as the specialization type. These test the UseCompressedOops -// flag. -#define InstanceKlass_OOP_MAP_ITERATE(obj, do_oop, assert_fn) \ -{ \ - /* Compute oopmap block range. The common case \ - is nonstatic_oop_map_size == 1. */ \ - OopMapBlock* map = start_of_nonstatic_oop_maps(); \ - OopMapBlock* const end_map = map + nonstatic_oop_map_count(); \ - if (UseCompressedOops) { \ - while (map < end_map) { \ - InstanceKlass_SPECIALIZED_OOP_ITERATE(narrowOop, \ - obj->obj_field_addr(map->offset()), map->count(), \ - do_oop, assert_fn) \ - ++map; \ - } \ - } else { \ - while (map < end_map) { \ - InstanceKlass_SPECIALIZED_OOP_ITERATE(oop, \ - obj->obj_field_addr(map->offset()), map->count(), \ - do_oop, assert_fn) \ - ++map; \ - } \ - } \ -} - -#define InstanceKlass_OOP_MAP_REVERSE_ITERATE(obj, do_oop, assert_fn) \ -{ \ - OopMapBlock* const start_map = start_of_nonstatic_oop_maps(); \ - OopMapBlock* map = start_map + nonstatic_oop_map_count(); \ - if (UseCompressedOops) { \ - while (start_map < map) { \ - --map; \ - InstanceKlass_SPECIALIZED_OOP_REVERSE_ITERATE(narrowOop, \ - obj->obj_field_addr(map->offset()), map->count(), \ - do_oop, assert_fn) \ - } \ - } else { \ - while (start_map < map) { \ - --map; \ - InstanceKlass_SPECIALIZED_OOP_REVERSE_ITERATE(oop, \ - obj->obj_field_addr(map->offset()), map->count(), \ - do_oop, assert_fn) \ - } \ - } \ -} - -#define InstanceKlass_BOUNDED_OOP_MAP_ITERATE(obj, low, high, do_oop, \ - assert_fn) \ -{ \ - /* Compute oopmap block range. The common case is \ - nonstatic_oop_map_size == 1, so we accept the \ - usually non-existent extra overhead of examining \ - all the maps. */ \ - OopMapBlock* map = start_of_nonstatic_oop_maps(); \ - OopMapBlock* const end_map = map + nonstatic_oop_map_count(); \ - if (UseCompressedOops) { \ - while (map < end_map) { \ - InstanceKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(narrowOop, \ - obj->obj_field_addr(map->offset()), map->count(), \ - low, high, \ - do_oop, assert_fn) \ - ++map; \ - } \ - } else { \ - while (map < end_map) { \ - InstanceKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(oop, \ - obj->obj_field_addr(map->offset()), map->count(), \ - low, high, \ - do_oop, assert_fn) \ - ++map; \ - } \ - } \ -} - -void InstanceKlass::oop_follow_contents(oop obj) { - assert(obj != NULL, "can't follow the content of NULL object"); - MarkSweep::follow_klass(obj->klass()); - InstanceKlass_OOP_MAP_ITERATE( \ - obj, \ - MarkSweep::mark_and_push(p), \ - assert_is_in_closed_subset) -} - -#if INCLUDE_ALL_GCS -void InstanceKlass::oop_follow_contents(ParCompactionManager* cm, - oop obj) { - assert(obj != NULL, "can't follow the content of NULL object"); - PSParallelCompact::follow_klass(cm, obj->klass()); - // Only mark the header and let the scan of the meta-data mark - // everything else. - InstanceKlass_OOP_MAP_ITERATE( \ - obj, \ - PSParallelCompact::mark_and_push(cm, p), \ - assert_is_in) -} -#endif // INCLUDE_ALL_GCS - -// closure's do_metadata() method dictates whether the given closure should be -// applied to the klass ptr in the object header. - -#define InstanceKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ - \ -int InstanceKlass::oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { \ - /* header */ \ - if_do_metadata_checked(closure, nv_suffix) { \ - closure->do_klass##nv_suffix(obj->klass()); \ - } \ - InstanceKlass_OOP_MAP_ITERATE( \ - obj, \ - (closure)->do_oop##nv_suffix(p), \ - assert_is_in_closed_subset) \ - return size_helper(); \ -} - -#if INCLUDE_ALL_GCS -#define InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ - \ -int InstanceKlass::oop_oop_iterate_backwards##nv_suffix(oop obj, \ - OopClosureType* closure) { \ - assert_should_ignore_metadata(closure, nv_suffix); \ - \ - /* instance variables */ \ - InstanceKlass_OOP_MAP_REVERSE_ITERATE( \ - obj, \ - (closure)->do_oop##nv_suffix(p), \ - assert_is_in_closed_subset) \ - return size_helper(); \ -} -#endif // INCLUDE_ALL_GCS - -#define InstanceKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ - \ -int InstanceKlass::oop_oop_iterate##nv_suffix##_m(oop obj, \ - OopClosureType* closure, \ - MemRegion mr) { \ - if_do_metadata_checked(closure, nv_suffix) { \ - if (mr.contains(obj)) { \ - closure->do_klass##nv_suffix(obj->klass()); \ - } \ - } \ - InstanceKlass_BOUNDED_OOP_MAP_ITERATE( \ - obj, mr.start(), mr.end(), \ - (closure)->do_oop##nv_suffix(p), \ - assert_is_in_closed_subset) \ - return size_helper(); \ -} - -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceKlass_OOP_OOP_ITERATE_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceKlass_OOP_OOP_ITERATE_DEFN_m) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_DEFN_m) -#if INCLUDE_ALL_GCS -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -#endif // INCLUDE_ALL_GCS - -int InstanceKlass::oop_adjust_pointers(oop obj) { - int size = size_helper(); - InstanceKlass_OOP_MAP_ITERATE( \ - obj, \ - MarkSweep::adjust_pointer(p), \ - assert_is_in) - return size; -} - -#if INCLUDE_ALL_GCS -void InstanceKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { - InstanceKlass_OOP_MAP_REVERSE_ITERATE( \ - obj, \ - if (PSScavenge::should_scavenge(p)) { \ - pm->claim_or_forward_depth(p); \ - }, \ - assert_nothing ) -} - -int InstanceKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { - int size = size_helper(); - InstanceKlass_OOP_MAP_ITERATE( \ - obj, \ - PSParallelCompact::adjust_pointer(p), \ - assert_is_in) - return size; -} - -#endif // INCLUDE_ALL_GCS - void InstanceKlass::clean_implementors_list(BoolObjectClosure* is_alive) { assert(class_loader_data()->is_alive(is_alive), "this klass should be live"); if (is_interface()) { @@ -2712,6 +2400,57 @@ return false; } +bool InstanceKlass::find_inner_classes_attr(instanceKlassHandle k, int* ooff, int* noff, TRAPS) { + constantPoolHandle i_cp(THREAD, k->constants()); + for (InnerClassesIterator iter(k); !iter.done(); iter.next()) { + int ioff = iter.inner_class_info_index(); + if (ioff != 0) { + // Check to see if the name matches the class we're looking for + // before attempting to find the class. + if (i_cp->klass_name_at_matches(k, ioff)) { + Klass* inner_klass = i_cp->klass_at(ioff, CHECK_false); + if (k() == inner_klass) { + *ooff = iter.outer_class_info_index(); + *noff = iter.inner_name_index(); + return true; + } + } + } + } + return false; +} + +Klass* InstanceKlass::compute_enclosing_class_impl(instanceKlassHandle k, bool* inner_is_member, TRAPS) { + instanceKlassHandle outer_klass; + *inner_is_member = false; + int ooff = 0, noff = 0; + if (find_inner_classes_attr(k, &ooff, &noff, THREAD)) { + constantPoolHandle i_cp(THREAD, k->constants()); + if (ooff != 0) { + Klass* ok = i_cp->klass_at(ooff, CHECK_NULL); + outer_klass = instanceKlassHandle(THREAD, ok); + *inner_is_member = true; + } + if (outer_klass.is_null()) { + // It may be anonymous; try for that. + int encl_method_class_idx = k->enclosing_method_class_index(); + if (encl_method_class_idx != 0) { + Klass* ok = i_cp->klass_at(encl_method_class_idx, CHECK_NULL); + outer_klass = instanceKlassHandle(THREAD, ok); + *inner_is_member = false; + } + } + } + + // If no inner class attribute found for this class. + if (outer_klass.is_null()) return NULL; + + // Throws an exception if outer klass has not declared k as an inner klass + // We need evidence that each klass knows about the other, or else + // the system could allow a spoof of an inner class to gain access rights. + Reflection::check_for_inner_class(outer_klass, k, *inner_is_member, CHECK_NULL); + return outer_klass(); +} jint InstanceKlass::compute_modifier_flags(TRAPS) const { jint access = access_flags().as_int(); @@ -3718,6 +3457,37 @@ return m; } + +Method* InstanceKlass::method_with_orig_idnum(int idnum) { + if (idnum >= methods()->length()) { + return NULL; + } + Method* m = methods()->at(idnum); + if (m != NULL && m->orig_method_idnum() == idnum) { + return m; + } + // Obsolete method idnum does not match the original idnum + for (int index = 0; index < methods()->length(); ++index) { + m = methods()->at(index); + if (m->orig_method_idnum() == idnum) { + return m; + } + } + // None found, return null for the caller to handle. + return NULL; +} + + +Method* InstanceKlass::method_with_orig_idnum(int idnum, int version) { + InstanceKlass* holder = get_klass_version(version); + if (holder == NULL) { + return NULL; // The version of klass is gone, no method is found + } + Method* method = holder->method_with_orig_idnum(idnum); + return method; +} + + jint InstanceKlass::get_cached_class_file_len() { return VM_RedefineClasses::get_cached_class_file_len(_cached_class_file); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/instanceKlass.hpp --- a/hotspot/src/share/vm/oops/instanceKlass.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Thu May 07 20:51:12 2015 -0700 @@ -330,6 +330,8 @@ Array* methods() const { return _methods; } void set_methods(Array* a) { _methods = a; } Method* method_with_idnum(int idnum); + Method* method_with_orig_idnum(int idnum); + Method* method_with_orig_idnum(int idnum, int version); // method ordering Array* method_ordering() const { return _method_ordering; } @@ -404,13 +406,17 @@ bool is_same_class_package(oop classloader2, Symbol* classname2); static bool is_same_class_package(oop class_loader1, Symbol* class_name1, oop class_loader2, Symbol* class_name2); - // find an enclosing class (defined where original code was, in jvm.cpp!) + // find an enclosing class Klass* compute_enclosing_class(bool* inner_is_member, TRAPS) { instanceKlassHandle self(THREAD, this); return compute_enclosing_class_impl(self, inner_is_member, THREAD); } static Klass* compute_enclosing_class_impl(instanceKlassHandle self, - bool* inner_is_member, TRAPS); + bool* inner_is_member, TRAPS); + + // Find InnerClasses attribute for k and return outer_class_info_index & inner_name_index. + static bool find_inner_classes_attr(instanceKlassHandle k, + int* ooff, int* noff, TRAPS); // tell if two classes have the same enclosing class (at package level) bool is_same_package_member(Klass* class2, TRAPS) { @@ -621,6 +627,15 @@ InstanceKlass* previous_versions() const { return _previous_versions; } + InstanceKlass* get_klass_version(int version) { + for (InstanceKlass* ik = this; ik != NULL; ik = ik->previous_versions()) { + if (ik->constants()->version() == version) { + return ik; + } + } + return NULL; + } + bool has_been_redefined() const { return (_misc_flags & _misc_has_been_redefined) != 0; } @@ -954,10 +969,6 @@ void adjust_default_methods(InstanceKlass* holder, bool* trace_name_printed); #endif // INCLUDE_JVMTI - // Garbage collection - void oop_follow_contents(oop obj); - int oop_adjust_pointers(oop obj); - void clean_implementors_list(BoolObjectClosure* is_alive); void clean_method_data(BoolObjectClosure* is_alive); void clean_dependent_nmethods(); @@ -981,32 +992,108 @@ static void notify_unload_class(InstanceKlass* ik); static void release_C_heap_structures(InstanceKlass* ik); - // Parallel Scavenge and Parallel Old - PARALLEL_GC_DECLS - // Naming const char* signature_name() const; - // Iterators - int oop_oop_iterate(oop obj, ExtendedOopClosure* blk) { - return oop_oop_iterate_v(obj, blk); - } + // GC specific object visitors + // + // Mark Sweep + void oop_ms_follow_contents(oop obj); + int oop_ms_adjust_pointers(oop obj); +#if INCLUDE_ALL_GCS + // Parallel Scavenge + void oop_ps_push_contents( oop obj, PSPromotionManager* pm); + // Parallel Compact + void oop_pc_follow_contents(oop obj, ParCompactionManager* cm); + void oop_pc_update_pointers(oop obj); +#endif + + // Oop fields (and metadata) iterators + // [nv = true] Use non-virtual calls to do_oop_nv. + // [nv = false] Use virtual calls to do_oop. + // + // The InstanceKlass iterators also visits the Object's klass. + + // Forward iteration + public: + // Iterate over all oop fields in the oop maps. + template + inline void oop_oop_iterate_oop_maps(oop obj, OopClosureType* closure); + + protected: + // Iterate over all oop fields and metadata. + template + inline int oop_oop_iterate(oop obj, OopClosureType* closure); + + private: + // Iterate over all oop fields in the oop maps. + // Specialized for [T = oop] or [T = narrowOop]. + template + inline void oop_oop_iterate_oop_maps_specialized(oop obj, OopClosureType* closure); + + // Iterate over all oop fields in one oop map. + template + inline void oop_oop_iterate_oop_map(OopMapBlock* map, oop obj, OopClosureType* closure); + - int oop_oop_iterate_m(oop obj, ExtendedOopClosure* blk, MemRegion mr) { - return oop_oop_iterate_v_m(obj, blk, mr); - } + // Reverse iteration +#if INCLUDE_ALL_GCS + public: + // Iterate over all oop fields in the oop maps. + template + inline void oop_oop_iterate_oop_maps_reverse(oop obj, OopClosureType* closure); + + protected: + // Iterate over all oop fields and metadata. + template + inline int oop_oop_iterate_reverse(oop obj, OopClosureType* closure); + + private: + // Iterate over all oop fields in the oop maps. + // Specialized for [T = oop] or [T = narrowOop]. + template + inline void oop_oop_iterate_oop_maps_specialized_reverse(oop obj, OopClosureType* closure); + + // Iterate over all oop fields in one oop map. + template + inline void oop_oop_iterate_oop_map_reverse(OopMapBlock* map, oop obj, OopClosureType* closure); +#endif + -#define InstanceKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ - int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* blk); \ - int oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* blk, \ - MemRegion mr); + // Bounded range iteration + public: + // Iterate over all oop fields in the oop maps. + template + inline void oop_oop_iterate_oop_maps_bounded(oop obj, OopClosureType* closure, MemRegion mr); + + protected: + // Iterate over all oop fields and metadata. + template + inline int oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr); + + private: + // Iterate over all oop fields in the oop maps. + // Specialized for [T = oop] or [T = narrowOop]. + template + inline void oop_oop_iterate_oop_maps_specialized_bounded(oop obj, OopClosureType* closure, MemRegion mr); + + // Iterate over all oop fields in one oop map. + template + inline void oop_oop_iterate_oop_map_bounded(OopMapBlock* map, oop obj, OopClosureType* closure, MemRegion mr); + + + public: + +#define InstanceKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ + int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure); \ + int oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr); ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceKlass_OOP_OOP_ITERATE_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_DECL) #if INCLUDE_ALL_GCS -#define InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ - int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* blk); +#define InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ + int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure); ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/instanceKlass.inline.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/oops/instanceKlass.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_OOPS_INSTANCEKLASS_INLINE_HPP +#define SHARE_VM_OOPS_INSTANCEKLASS_INLINE_HPP + +#include "memory/iterator.hpp" +#include "oops/instanceKlass.hpp" +#include "oops/oop.inline.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" + +// The iteration over the oops in objects is a hot path in the GC code. +// By force inlining the following functions, we get similar GC performance +// as the previous macro based implementation. +#ifdef TARGET_COMPILER_visCPP +#define INLINE __forceinline +#else +#define INLINE inline +#endif + +template +INLINE void InstanceKlass::oop_oop_iterate_oop_map(OopMapBlock* map, oop obj, OopClosureType* closure) { + T* p = (T*)obj->obj_field_addr(map->offset()); + T* const end = p + map->count(); + + for (; p < end; ++p) { + Devirtualizer::do_oop(closure, p); + } +} + +#if INCLUDE_ALL_GCS +template +INLINE void InstanceKlass::oop_oop_iterate_oop_map_reverse(OopMapBlock* map, oop obj, OopClosureType* closure) { + T* const start = (T*)obj->obj_field_addr(map->offset()); + T* p = start + map->count(); + + while (start < p) { + --p; + Devirtualizer::do_oop(closure, p); + } +} +#endif + +template +INLINE void InstanceKlass::oop_oop_iterate_oop_map_bounded(OopMapBlock* map, oop obj, OopClosureType* closure, MemRegion mr) { + T* p = (T*)obj->obj_field_addr(map->offset()); + T* end = p + map->count(); + + T* const l = (T*)mr.start(); + T* const h = (T*)mr.end(); + assert(mask_bits((intptr_t)l, sizeof(T)-1) == 0 && + mask_bits((intptr_t)h, sizeof(T)-1) == 0, + "bounded region must be properly aligned"); + + if (p < l) { + p = l; + } + if (end > h) { + end = h; + } + + for (;p < end; ++p) { + Devirtualizer::do_oop(closure, p); + } +} + +template +INLINE void InstanceKlass::oop_oop_iterate_oop_maps_specialized(oop obj, OopClosureType* closure) { + OopMapBlock* map = start_of_nonstatic_oop_maps(); + OopMapBlock* const end_map = map + nonstatic_oop_map_count(); + + for (; map < end_map; ++map) { + oop_oop_iterate_oop_map(map, obj, closure); + } +} + +#if INCLUDE_ALL_GCS +template +INLINE void InstanceKlass::oop_oop_iterate_oop_maps_specialized_reverse(oop obj, OopClosureType* closure) { + OopMapBlock* const start_map = start_of_nonstatic_oop_maps(); + OopMapBlock* map = start_map + nonstatic_oop_map_count(); + + while (start_map < map) { + --map; + oop_oop_iterate_oop_map_reverse(map, obj, closure); + } +} +#endif + +template +INLINE void InstanceKlass::oop_oop_iterate_oop_maps_specialized_bounded(oop obj, OopClosureType* closure, MemRegion mr) { + OopMapBlock* map = start_of_nonstatic_oop_maps(); + OopMapBlock* const end_map = map + nonstatic_oop_map_count(); + + for (;map < end_map; ++map) { + oop_oop_iterate_oop_map_bounded(map, obj, closure, mr); + } +} + +template +INLINE void InstanceKlass::oop_oop_iterate_oop_maps(oop obj, OopClosureType* closure) { + if (UseCompressedOops) { + oop_oop_iterate_oop_maps_specialized(obj, closure); + } else { + oop_oop_iterate_oop_maps_specialized(obj, closure); + } +} + +#if INCLUDE_ALL_GCS +template +INLINE void InstanceKlass::oop_oop_iterate_oop_maps_reverse(oop obj, OopClosureType* closure) { + if (UseCompressedOops) { + oop_oop_iterate_oop_maps_specialized_reverse(obj, closure); + } else { + oop_oop_iterate_oop_maps_specialized_reverse(obj, closure); + } +} +#endif + +template +INLINE void InstanceKlass::oop_oop_iterate_oop_maps_bounded(oop obj, OopClosureType* closure, MemRegion mr) { + if (UseCompressedOops) { + oop_oop_iterate_oop_maps_specialized_bounded(obj, closure, mr); + } else { + oop_oop_iterate_oop_maps_specialized_bounded(obj, closure, mr); + } +} + +template +INLINE int InstanceKlass::oop_oop_iterate(oop obj, OopClosureType* closure) { + if (Devirtualizer::do_metadata(closure)) { + Devirtualizer::do_klass(closure, this); + } + + oop_oop_iterate_oop_maps(obj, closure); + + return size_helper(); +} + +#if INCLUDE_ALL_GCS +template +INLINE int InstanceKlass::oop_oop_iterate_reverse(oop obj, OopClosureType* closure) { + assert(!Devirtualizer::do_metadata(closure), + "Code to handle metadata is not implemented"); + + oop_oop_iterate_oop_maps_reverse(obj, closure); + + return size_helper(); +} +#endif + +template +INLINE int InstanceKlass::oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr) { + if (Devirtualizer::do_metadata(closure)) { + if (mr.contains(obj)) { + Devirtualizer::do_klass(closure, this); + } + } + + oop_oop_iterate_oop_maps_bounded(obj, closure, mr); + + return size_helper(); +} + +#undef INLINE + + +#define InstanceKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ +int InstanceKlass::oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { \ + return oop_oop_iterate(obj, closure); \ +} + +#if INCLUDE_ALL_GCS +#define InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ +int InstanceKlass::oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) { \ + return oop_oop_iterate_reverse(obj, closure); \ +} +#else +#define InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) +#endif + +#define InstanceKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ +int InstanceKlass::oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr) { \ + return oop_oop_iterate_bounded(obj, closure, mr); \ +} + +#define ALL_INSTANCE_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + InstanceKlass_OOP_OOP_ITERATE_DEFN( OopClosureType, nv_suffix) \ + InstanceKlass_OOP_OOP_ITERATE_DEFN_m( OopClosureType, nv_suffix) \ + InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) + +#endif // SHARE_VM_OOPS_INSTANCEKLASS_INLINE_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/instanceMirrorKlass.cpp --- a/hotspot/src/share/vm/oops/instanceMirrorKlass.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/oops/instanceMirrorKlass.cpp Thu May 07 20:51:12 2015 -0700 @@ -25,9 +25,7 @@ #include "precompiled.hpp" #include "classfile/javaClasses.hpp" #include "classfile/systemDictionary.hpp" -#include "gc_implementation/shared/markSweep.inline.hpp" #include "gc_interface/collectedHeap.inline.hpp" -#include "memory/genOopClosures.inline.hpp" #include "memory/iterator.inline.hpp" #include "memory/oopFactory.hpp" #include "memory/specialized_oop_closures.hpp" @@ -38,313 +36,9 @@ #include "oops/symbol.hpp" #include "runtime/handles.inline.hpp" #include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS -#include "gc_implementation/concurrentMarkSweep/cmsOopClosures.inline.hpp" -#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" -#include "gc_implementation/g1/g1OopClosures.inline.hpp" -#include "gc_implementation/g1/g1RemSet.inline.hpp" -#include "gc_implementation/g1/heapRegionManager.inline.hpp" -#include "gc_implementation/parNew/parOopClosures.inline.hpp" -#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" -#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" -#endif // INCLUDE_ALL_GCS int InstanceMirrorKlass::_offset_of_static_fields = 0; -#ifdef ASSERT -template void assert_is_in(T *p) { - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop)) { - oop o = oopDesc::decode_heap_oop_not_null(heap_oop); - assert(Universe::heap()->is_in(o), "should be in heap"); - } -} -template void assert_is_in_closed_subset(T *p) { - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop)) { - oop o = oopDesc::decode_heap_oop_not_null(heap_oop); - assert(Universe::heap()->is_in_closed_subset(o), "should be in closed"); - } -} -template void assert_is_in_reserved(T *p) { - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop)) { - oop o = oopDesc::decode_heap_oop_not_null(heap_oop); - assert(Universe::heap()->is_in_reserved(o), "should be in reserved"); - } -} -template void assert_nothing(T *p) {} - -#else -template void assert_is_in(T *p) {} -template void assert_is_in_closed_subset(T *p) {} -template void assert_is_in_reserved(T *p) {} -template void assert_nothing(T *p) {} -#endif // ASSERT - -#define InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE( \ - T, start_p, count, do_oop, \ - assert_fn) \ -{ \ - T* p = (T*)(start_p); \ - T* const end = p + (count); \ - while (p < end) { \ - (assert_fn)(p); \ - do_oop; \ - ++p; \ - } \ -} - -#define InstanceMirrorKlass_SPECIALIZED_BOUNDED_OOP_ITERATE( \ - T, start_p, count, low, high, \ - do_oop, assert_fn) \ -{ \ - T* const l = (T*)(low); \ - T* const h = (T*)(high); \ - assert(mask_bits((intptr_t)l, sizeof(T)-1) == 0 && \ - mask_bits((intptr_t)h, sizeof(T)-1) == 0, \ - "bounded region must be properly aligned"); \ - T* p = (T*)(start_p); \ - T* end = p + (count); \ - if (p < l) p = l; \ - if (end > h) end = h; \ - while (p < end) { \ - (assert_fn)(p); \ - do_oop; \ - ++p; \ - } \ -} - - -#define InstanceMirrorKlass_OOP_ITERATE(start_p, count, \ - do_oop, assert_fn) \ -{ \ - if (UseCompressedOops) { \ - InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE(narrowOop, \ - start_p, count, \ - do_oop, assert_fn) \ - } else { \ - InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE(oop, \ - start_p, count, \ - do_oop, assert_fn) \ - } \ -} - -// The following macros call specialized macros, passing either oop or -// narrowOop as the specialization type. These test the UseCompressedOops -// flag. -#define InstanceMirrorKlass_BOUNDED_OOP_ITERATE(start_p, count, low, high, \ - do_oop, assert_fn) \ -{ \ - if (UseCompressedOops) { \ - InstanceMirrorKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(narrowOop, \ - start_p, count, \ - low, high, \ - do_oop, assert_fn) \ - } else { \ - InstanceMirrorKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(oop, \ - start_p, count, \ - low, high, \ - do_oop, assert_fn) \ - } \ -} - - -void InstanceMirrorKlass::oop_follow_contents(oop obj) { - InstanceKlass::oop_follow_contents(obj); - - // Follow the klass field in the mirror. - Klass* klass = java_lang_Class::as_Klass(obj); - if (klass != NULL) { - // An anonymous class doesn't have its own class loader, so the call - // to follow_klass will mark and push its java mirror instead of the - // class loader. When handling the java mirror for an anonymous class - // we need to make sure its class loader data is claimed, this is done - // by calling follow_class_loader explicitly. For non-anonymous classes - // the call to follow_class_loader is made when the class loader itself - // is handled. - if (klass->oop_is_instance() && InstanceKlass::cast(klass)->is_anonymous()) { - MarkSweep::follow_class_loader(klass->class_loader_data()); - } else { - MarkSweep::follow_klass(klass); - } - } else { - // If klass is NULL then this a mirror for a primitive type. - // We don't have to follow them, since they are handled as strong - // roots in Universe::oops_do. - assert(java_lang_Class::is_primitive(obj), "Sanity check"); - } - - InstanceMirrorKlass_OOP_ITERATE( \ - start_of_static_fields(obj), java_lang_Class::static_oop_field_count(obj), \ - MarkSweep::mark_and_push(p), \ - assert_is_in_closed_subset) -} - -#if INCLUDE_ALL_GCS -void InstanceMirrorKlass::oop_follow_contents(ParCompactionManager* cm, - oop obj) { - InstanceKlass::oop_follow_contents(cm, obj); - - // Follow the klass field in the mirror. - Klass* klass = java_lang_Class::as_Klass(obj); - if (klass != NULL) { - // An anonymous class doesn't have its own class loader, so the call - // to follow_klass will mark and push its java mirror instead of the - // class loader. When handling the java mirror for an anonymous class - // we need to make sure its class loader data is claimed, this is done - // by calling follow_class_loader explicitly. For non-anonymous classes - // the call to follow_class_loader is made when the class loader itself - // is handled. - if (klass->oop_is_instance() && InstanceKlass::cast(klass)->is_anonymous()) { - PSParallelCompact::follow_class_loader(cm, klass->class_loader_data()); - } else { - PSParallelCompact::follow_klass(cm, klass); - } - } else { - // If klass is NULL then this a mirror for a primitive type. - // We don't have to follow them, since they are handled as strong - // roots in Universe::oops_do. - assert(java_lang_Class::is_primitive(obj), "Sanity check"); - } - - InstanceMirrorKlass_OOP_ITERATE( \ - start_of_static_fields(obj), java_lang_Class::static_oop_field_count(obj), \ - PSParallelCompact::mark_and_push(cm, p), \ - assert_is_in) -} -#endif // INCLUDE_ALL_GCS - -int InstanceMirrorKlass::oop_adjust_pointers(oop obj) { - int size = oop_size(obj); - InstanceKlass::oop_adjust_pointers(obj); - - InstanceMirrorKlass_OOP_ITERATE( \ - start_of_static_fields(obj), java_lang_Class::static_oop_field_count(obj), \ - MarkSweep::adjust_pointer(p), \ - assert_nothing) - return size; -} - -#define InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE_DEFN(T, nv_suffix) \ - InstanceMirrorKlass_OOP_ITERATE( \ - start_of_static_fields(obj), java_lang_Class::static_oop_field_count(obj), \ - (closure)->do_oop##nv_suffix(p), \ - assert_is_in_closed_subset) \ - return oop_size(obj); \ - -#define InstanceMirrorKlass_BOUNDED_SPECIALIZED_OOP_ITERATE(T, nv_suffix, mr) \ - InstanceMirrorKlass_BOUNDED_OOP_ITERATE( \ - start_of_static_fields(obj), java_lang_Class::static_oop_field_count(obj), \ - mr.start(), mr.end(), \ - (closure)->do_oop##nv_suffix(p), \ - assert_is_in_closed_subset) \ - return oop_size(obj); \ - - -// Macro to define InstanceMirrorKlass::oop_oop_iterate for virtual/nonvirtual for -// all closures. Macros calling macros above for each oop size. - -#define InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ - \ -int InstanceMirrorKlass:: \ -oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { \ - /* Get size before changing pointers */ \ - InstanceKlass::oop_oop_iterate##nv_suffix(obj, closure); \ - \ - if_do_metadata_checked(closure, nv_suffix) { \ - Klass* klass = java_lang_Class::as_Klass(obj); \ - /* We'll get NULL for primitive mirrors. */ \ - if (klass != NULL) { \ - closure->do_klass##nv_suffix(klass); \ - } \ - } \ - \ - if (UseCompressedOops) { \ - InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE_DEFN(narrowOop, nv_suffix); \ - } else { \ - InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE_DEFN(oop, nv_suffix); \ - } \ -} - -#if INCLUDE_ALL_GCS -#define InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ - \ -int InstanceMirrorKlass:: \ -oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) { \ - /* Get size before changing pointers */ \ - InstanceKlass::oop_oop_iterate_backwards##nv_suffix(obj, closure); \ - \ - if (UseCompressedOops) { \ - InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE_DEFN(narrowOop, nv_suffix); \ - } else { \ - InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE_DEFN(oop, nv_suffix); \ - } \ -} -#endif // INCLUDE_ALL_GCS - - -#define InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ - \ -int InstanceMirrorKlass:: \ -oop_oop_iterate##nv_suffix##_m(oop obj, \ - OopClosureType* closure, \ - MemRegion mr) { \ - InstanceKlass::oop_oop_iterate##nv_suffix##_m(obj, closure, mr); \ - \ - if_do_metadata_checked(closure, nv_suffix) { \ - if (mr.contains(obj)) { \ - Klass* klass = java_lang_Class::as_Klass(obj); \ - /* We'll get NULL for primitive mirrors. */ \ - if (klass != NULL) { \ - closure->do_klass##nv_suffix(klass); \ - } \ - } \ - } \ - \ - if (UseCompressedOops) { \ - InstanceMirrorKlass_BOUNDED_SPECIALIZED_OOP_ITERATE(narrowOop, nv_suffix, mr); \ - } else { \ - InstanceMirrorKlass_BOUNDED_SPECIALIZED_OOP_ITERATE(oop, nv_suffix, mr); \ - } \ -} - -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN) -#if INCLUDE_ALL_GCS -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -#endif // INCLUDE_ALL_GCS -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m) - -#if INCLUDE_ALL_GCS -void InstanceMirrorKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { - // Note that we don't have to follow the mirror -> klass pointer, since all - // klasses that are dirty will be scavenged when we iterate over the - // ClassLoaderData objects. - - InstanceKlass::oop_push_contents(pm, obj); - InstanceMirrorKlass_OOP_ITERATE( \ - start_of_static_fields(obj), java_lang_Class::static_oop_field_count(obj),\ - if (PSScavenge::should_scavenge(p)) { \ - pm->claim_or_forward_depth(p); \ - }, \ - assert_nothing ) -} - -int InstanceMirrorKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { - int size = oop_size(obj); - InstanceKlass::oop_update_pointers(cm, obj); - - InstanceMirrorKlass_OOP_ITERATE( \ - start_of_static_fields(obj), java_lang_Class::static_oop_field_count(obj),\ - PSParallelCompact::adjust_pointer(p), \ - assert_nothing) - return size; -} -#endif // INCLUDE_ALL_GCS - int InstanceMirrorKlass::instance_size(KlassHandle k) { if (k() != NULL && k->oop_is_instance()) { return align_object_size(size_helper() + InstanceKlass::cast(k())->static_field_size()); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/instanceMirrorKlass.hpp --- a/hotspot/src/share/vm/oops/instanceMirrorKlass.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/oops/instanceMirrorKlass.hpp Thu May 07 20:51:12 2015 -0700 @@ -88,19 +88,66 @@ // allocation instanceOop allocate_instance(KlassHandle k, TRAPS); - // Garbage collection - int oop_adjust_pointers(oop obj); - void oop_follow_contents(oop obj); + // GC specific object visitors + // + // Mark Sweep + void oop_ms_follow_contents(oop obj); + int oop_ms_adjust_pointers(oop obj); +#if INCLUDE_ALL_GCS + // Parallel Scavenge + void oop_ps_push_contents( oop obj, PSPromotionManager* pm); + // Parallel Compact + void oop_pc_follow_contents(oop obj, ParCompactionManager* cm); + void oop_pc_update_pointers(oop obj); +#endif - // Parallel Scavenge and Parallel Old - PARALLEL_GC_DECLS + // Oop fields (and metadata) iterators + // [nv = true] Use non-virtual calls to do_oop_nv. + // [nv = false] Use virtual calls to do_oop. + // + // The InstanceMirrorKlass iterators also visit the hidden Klass pointer. + + public: + // Iterate over the static fields. + template + inline void oop_oop_iterate_statics(oop obj, OopClosureType* closure); + + private: + // Iterate over the static fields. + // Specialized for [T = oop] or [T = narrowOop]. + template + inline void oop_oop_iterate_statics_specialized(oop obj, OopClosureType* closure); - int oop_oop_iterate(oop obj, ExtendedOopClosure* blk) { - return oop_oop_iterate_v(obj, blk); - } - int oop_oop_iterate_m(oop obj, ExtendedOopClosure* blk, MemRegion mr) { - return oop_oop_iterate_v_m(obj, blk, mr); - } + // Forward iteration + // Iterate over the oop fields and metadata. + template + inline int oop_oop_iterate(oop obj, OopClosureType* closure); + + + // Reverse iteration +#if INCLUDE_ALL_GCS + // Iterate over the oop fields and metadata. + template + inline int oop_oop_iterate_reverse(oop obj, OopClosureType* closure); +#endif + + + // Bounded range iteration + // Iterate over the oop fields and metadata. + template + inline int oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr); + + // Iterate over the static fields. + template + inline void oop_oop_iterate_statics_bounded(oop obj, OopClosureType* closure, MemRegion mr); + + // Iterate over the static fields. + // Specialized for [T = oop] or [T = narrowOop]. + template + inline void oop_oop_iterate_statics_specialized_bounded(oop obj, OopClosureType* closure, MemRegion mr); + + + public: #define InstanceMirrorKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* blk); \ diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/instanceMirrorKlass.inline.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/oops/instanceMirrorKlass.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,164 @@ +/* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_OOPS_INSTANCEMIRRORKLASS_INLINE_HPP +#define SHARE_VM_OOPS_INSTANCEMIRRORKLASS_INLINE_HPP + +#include "classfile/javaClasses.hpp" +#include "oops/instanceKlass.inline.hpp" +#include "oops/instanceMirrorKlass.hpp" +#include "oops/oop.inline.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" + +template +void InstanceMirrorKlass::oop_oop_iterate_statics_specialized(oop obj, OopClosureType* closure) { + T* p = (T*)start_of_static_fields(obj); + T* const end = p + java_lang_Class::static_oop_field_count(obj); + + for (; p < end; ++p) { + Devirtualizer::do_oop(closure, p); + } +} + +template +void InstanceMirrorKlass::oop_oop_iterate_statics(oop obj, OopClosureType* closure) { + if (UseCompressedOops) { + oop_oop_iterate_statics_specialized(obj, closure); + } else { + oop_oop_iterate_statics_specialized(obj, closure); + } +} + +template +int InstanceMirrorKlass::oop_oop_iterate(oop obj, OopClosureType* closure) { + InstanceKlass::oop_oop_iterate(obj, closure); + + if (Devirtualizer::do_metadata(closure)) { + Klass* klass = java_lang_Class::as_Klass(obj); + // We'll get NULL for primitive mirrors. + if (klass != NULL) { + Devirtualizer::do_klass(closure, klass); + } + } + + oop_oop_iterate_statics(obj, closure); + + return oop_size(obj); +} + +#if INCLUDE_ALL_GCS +template +int InstanceMirrorKlass::oop_oop_iterate_reverse(oop obj, OopClosureType* closure) { + InstanceKlass::oop_oop_iterate_reverse(obj, closure); + + InstanceMirrorKlass::oop_oop_iterate_statics(obj, closure); + + return oop_size(obj); +} +#endif + +template +void InstanceMirrorKlass::oop_oop_iterate_statics_specialized_bounded(oop obj, + OopClosureType* closure, + MemRegion mr) { + T* p = (T*)start_of_static_fields(obj); + T* end = p + java_lang_Class::static_oop_field_count(obj); + + T* const l = (T*)mr.start(); + T* const h = (T*)mr.end(); + assert(mask_bits((intptr_t)l, sizeof(T)-1) == 0 && + mask_bits((intptr_t)h, sizeof(T)-1) == 0, + "bounded region must be properly aligned"); + + if (p < l) { + p = l; + } + if (end > h) { + end = h; + } + + for (;p < end; ++p) { + Devirtualizer::do_oop(closure, p); + } +} + +template +void InstanceMirrorKlass::oop_oop_iterate_statics_bounded(oop obj, OopClosureType* closure, MemRegion mr) { + if (UseCompressedOops) { + oop_oop_iterate_statics_specialized_bounded(obj, closure, mr); + } else { + oop_oop_iterate_statics_specialized_bounded(obj, closure, mr); + } +} + +template +int InstanceMirrorKlass::oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr) { + InstanceKlass::oop_oop_iterate_bounded(obj, closure, mr); + + if (Devirtualizer::do_metadata(closure)) { + if (mr.contains(obj)) { + Klass* klass = java_lang_Class::as_Klass(obj); + // We'll get NULL for primitive mirrors. + if (klass != NULL) { + Devirtualizer::do_klass(closure, klass); + } + } + } + + oop_oop_iterate_statics_bounded(obj, closure, mr); + + return oop_size(obj); +} + + +#define InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + \ +int InstanceMirrorKlass::oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { \ + return oop_oop_iterate(obj, closure); \ +} + +#if INCLUDE_ALL_GCS +#define InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ + \ +int InstanceMirrorKlass::oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) { \ + return oop_oop_iterate_reverse(obj, closure); \ +} +#else +#define InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) +#endif + + +#define InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ + \ +int InstanceMirrorKlass::oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr) { \ + return oop_oop_iterate_bounded(obj, closure, mr); \ +} + +#define ALL_INSTANCE_MIRROR_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN( OopClosureType, nv_suffix) \ + InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m( OopClosureType, nv_suffix) \ + InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) + +#endif // SHARE_VM_OOPS_INSTANCEMIRRORKLASS_INLINE_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/instanceRefKlass.cpp --- a/hotspot/src/share/vm/oops/instanceRefKlass.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/oops/instanceRefKlass.cpp Thu May 07 20:51:12 2015 -0700 @@ -25,421 +25,16 @@ #include "precompiled.hpp" #include "classfile/javaClasses.hpp" #include "classfile/systemDictionary.hpp" -#include "gc_implementation/shared/markSweep.inline.hpp" -#include "gc_interface/collectedHeap.hpp" #include "gc_interface/collectedHeap.inline.hpp" #include "memory/genCollectedHeap.hpp" -#include "memory/genOopClosures.inline.hpp" #include "memory/specialized_oop_closures.hpp" -#include "oops/instanceRefKlass.hpp" +#include "oops/instanceRefKlass.inline.hpp" #include "oops/oop.inline.hpp" #include "utilities/preserveException.hpp" #include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS -#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" -#include "gc_implementation/g1/g1OopClosures.inline.hpp" -#include "gc_implementation/g1/g1RemSet.inline.hpp" -#include "gc_implementation/g1/heapRegionManager.inline.hpp" -#include "gc_implementation/parNew/parOopClosures.inline.hpp" -#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" -#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" -#endif // INCLUDE_ALL_GCS PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC -template -void specialized_oop_follow_contents(InstanceRefKlass* ref, oop obj) { - T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); - T heap_oop = oopDesc::load_heap_oop(referent_addr); - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr("InstanceRefKlass::oop_follow_contents " INTPTR_FORMAT, (void *)obj); - } - ) - if (!oopDesc::is_null(heap_oop)) { - oop referent = oopDesc::decode_heap_oop_not_null(heap_oop); - if (!referent->is_gc_marked() && - MarkSweep::ref_processor()->discover_reference(obj, ref->reference_type())) { - // reference was discovered, referent will be traversed later - ref->InstanceKlass::oop_follow_contents(obj); - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Non NULL enqueued " INTPTR_FORMAT, (void *)obj); - } - ) - return; - } else { - // treat referent as normal oop - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Non NULL normal " INTPTR_FORMAT, (void *)obj); - } - ) - MarkSweep::mark_and_push(referent_addr); - } - } - T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); - if (ReferenceProcessor::pending_list_uses_discovered_field()) { - // Treat discovered as normal oop, if ref is not "active", - // i.e. if next is non-NULL. - T next_oop = oopDesc::load_heap_oop(next_addr); - if (!oopDesc::is_null(next_oop)) { // i.e. ref is not "active" - T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Process discovered as normal " - INTPTR_FORMAT, discovered_addr); - } - ) - MarkSweep::mark_and_push(discovered_addr); - } - } else { -#ifdef ASSERT - // In the case of older JDKs which do not use the discovered - // field for the pending list, an inactive ref (next != NULL) - // must always have a NULL discovered field. - oop next = oopDesc::load_decode_heap_oop(next_addr); - oop discovered = java_lang_ref_Reference::discovered(obj); - assert(oopDesc::is_null(next) || oopDesc::is_null(discovered), - err_msg("Found an inactive reference " PTR_FORMAT " with a non-NULL discovered field", - (oopDesc*)obj)); -#endif - } - // treat next as normal oop. next is a link in the reference queue. - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Process next as normal " INTPTR_FORMAT, next_addr); - } - ) - MarkSweep::mark_and_push(next_addr); - ref->InstanceKlass::oop_follow_contents(obj); -} - -void InstanceRefKlass::oop_follow_contents(oop obj) { - if (UseCompressedOops) { - specialized_oop_follow_contents(this, obj); - } else { - specialized_oop_follow_contents(this, obj); - } -} - -#if INCLUDE_ALL_GCS -template -void specialized_oop_follow_contents(InstanceRefKlass* ref, - ParCompactionManager* cm, - oop obj) { - T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); - T heap_oop = oopDesc::load_heap_oop(referent_addr); - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr("InstanceRefKlass::oop_follow_contents " INTPTR_FORMAT, (void *)obj); - } - ) - if (!oopDesc::is_null(heap_oop)) { - oop referent = oopDesc::decode_heap_oop_not_null(heap_oop); - if (PSParallelCompact::mark_bitmap()->is_unmarked(referent) && - PSParallelCompact::ref_processor()-> - discover_reference(obj, ref->reference_type())) { - // reference already enqueued, referent will be traversed later - ref->InstanceKlass::oop_follow_contents(cm, obj); - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Non NULL enqueued " INTPTR_FORMAT, (void *)obj); - } - ) - return; - } else { - // treat referent as normal oop - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Non NULL normal " INTPTR_FORMAT, (void *)obj); - } - ) - PSParallelCompact::mark_and_push(cm, referent_addr); - } - } - T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); - if (ReferenceProcessor::pending_list_uses_discovered_field()) { - // Treat discovered as normal oop, if ref is not "active", - // i.e. if next is non-NULL. - T next_oop = oopDesc::load_heap_oop(next_addr); - if (!oopDesc::is_null(next_oop)) { // i.e. ref is not "active" - T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Process discovered as normal " - INTPTR_FORMAT, discovered_addr); - } - ) - PSParallelCompact::mark_and_push(cm, discovered_addr); - } - } else { -#ifdef ASSERT - // In the case of older JDKs which do not use the discovered - // field for the pending list, an inactive ref (next != NULL) - // must always have a NULL discovered field. - T next = oopDesc::load_heap_oop(next_addr); - oop discovered = java_lang_ref_Reference::discovered(obj); - assert(oopDesc::is_null(next) || oopDesc::is_null(discovered), - err_msg("Found an inactive reference " PTR_FORMAT " with a non-NULL discovered field", - (oopDesc*)obj)); -#endif - } - PSParallelCompact::mark_and_push(cm, next_addr); - ref->InstanceKlass::oop_follow_contents(cm, obj); -} - -void InstanceRefKlass::oop_follow_contents(ParCompactionManager* cm, - oop obj) { - if (UseCompressedOops) { - specialized_oop_follow_contents(this, cm, obj); - } else { - specialized_oop_follow_contents(this, cm, obj); - } -} -#endif // INCLUDE_ALL_GCS - -#ifdef ASSERT -template void trace_reference_gc(const char *s, oop obj, - T* referent_addr, - T* next_addr, - T* discovered_addr) { - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr("%s obj " INTPTR_FORMAT, s, (address)obj); - gclog_or_tty->print_cr(" referent_addr/* " INTPTR_FORMAT " / " - INTPTR_FORMAT, referent_addr, - referent_addr ? - (address)oopDesc::load_decode_heap_oop(referent_addr) : NULL); - gclog_or_tty->print_cr(" next_addr/* " INTPTR_FORMAT " / " - INTPTR_FORMAT, next_addr, - next_addr ? (address)oopDesc::load_decode_heap_oop(next_addr) : NULL); - gclog_or_tty->print_cr(" discovered_addr/* " INTPTR_FORMAT " / " - INTPTR_FORMAT, discovered_addr, - discovered_addr ? - (address)oopDesc::load_decode_heap_oop(discovered_addr) : NULL); - } -} -#endif - -template void specialized_oop_adjust_pointers(InstanceRefKlass *ref, oop obj) { - T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); - MarkSweep::adjust_pointer(referent_addr); - T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); - MarkSweep::adjust_pointer(next_addr); - T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); - MarkSweep::adjust_pointer(discovered_addr); - debug_only(trace_reference_gc("InstanceRefKlass::oop_adjust_pointers", obj, - referent_addr, next_addr, discovered_addr);) -} - -int InstanceRefKlass::oop_adjust_pointers(oop obj) { - int size = size_helper(); - InstanceKlass::oop_adjust_pointers(obj); - - if (UseCompressedOops) { - specialized_oop_adjust_pointers(this, obj); - } else { - specialized_oop_adjust_pointers(this, obj); - } - return size; -} - -#define InstanceRefKlass_SPECIALIZED_OOP_ITERATE(T, nv_suffix, contains) \ - T* disc_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); \ - if (closure->apply_to_weak_ref_discovered_field()) { \ - closure->do_oop##nv_suffix(disc_addr); \ - } \ - \ - T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); \ - T heap_oop = oopDesc::load_heap_oop(referent_addr); \ - ReferenceProcessor* rp = closure->_ref_processor; \ - if (!oopDesc::is_null(heap_oop)) { \ - oop referent = oopDesc::decode_heap_oop_not_null(heap_oop); \ - if (!referent->is_gc_marked() && (rp != NULL) && \ - rp->discover_reference(obj, reference_type())) { \ - return size; \ - } else if (contains(referent_addr)) { \ - /* treat referent as normal oop */ \ - closure->do_oop##nv_suffix(referent_addr); \ - } \ - } \ - T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); \ - if (ReferenceProcessor::pending_list_uses_discovered_field()) { \ - T next_oop = oopDesc::load_heap_oop(next_addr); \ - /* Treat discovered as normal oop, if ref is not "active" (next non-NULL) */\ - if (!oopDesc::is_null(next_oop) && contains(disc_addr)) { \ - /* i.e. ref is not "active" */ \ - debug_only( \ - if(TraceReferenceGC && PrintGCDetails) { \ - gclog_or_tty->print_cr(" Process discovered as normal " \ - INTPTR_FORMAT, disc_addr); \ - } \ - ) \ - closure->do_oop##nv_suffix(disc_addr); \ - } \ - } else { \ - /* In the case of older JDKs which do not use the discovered field for */ \ - /* the pending list, an inactive ref (next != NULL) must always have a */ \ - /* NULL discovered field. */ \ - debug_only( \ - T next_oop = oopDesc::load_heap_oop(next_addr); \ - T disc_oop = oopDesc::load_heap_oop(disc_addr); \ - assert(oopDesc::is_null(next_oop) || oopDesc::is_null(disc_oop), \ - err_msg("Found an inactive reference " PTR_FORMAT " with a non-NULL" \ - "discovered field", (oopDesc*)obj)); \ - ) \ - } \ - /* treat next as normal oop */ \ - if (contains(next_addr)) { \ - closure->do_oop##nv_suffix(next_addr); \ - } \ - return size; \ - - -template bool contains(T *t) { return true; } - -// Macro to define InstanceRefKlass::oop_oop_iterate for virtual/nonvirtual for -// all closures. Macros calling macros above for each oop size. - -#define InstanceRefKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ - \ -int InstanceRefKlass:: \ -oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { \ - /* Get size before changing pointers */ \ - int size = InstanceKlass::oop_oop_iterate##nv_suffix(obj, closure); \ - \ - if (UseCompressedOops) { \ - InstanceRefKlass_SPECIALIZED_OOP_ITERATE(narrowOop, nv_suffix, contains); \ - } else { \ - InstanceRefKlass_SPECIALIZED_OOP_ITERATE(oop, nv_suffix, contains); \ - } \ -} - -#if INCLUDE_ALL_GCS -#define InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ - \ -int InstanceRefKlass:: \ -oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) { \ - /* Get size before changing pointers */ \ - int size = InstanceKlass::oop_oop_iterate_backwards##nv_suffix(obj, closure); \ - \ - if (UseCompressedOops) { \ - InstanceRefKlass_SPECIALIZED_OOP_ITERATE(narrowOop, nv_suffix, contains); \ - } else { \ - InstanceRefKlass_SPECIALIZED_OOP_ITERATE(oop, nv_suffix, contains); \ - } \ -} -#endif // INCLUDE_ALL_GCS - - -#define InstanceRefKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ - \ -int InstanceRefKlass:: \ -oop_oop_iterate##nv_suffix##_m(oop obj, \ - OopClosureType* closure, \ - MemRegion mr) { \ - int size = InstanceKlass::oop_oop_iterate##nv_suffix##_m(obj, closure, mr); \ - if (UseCompressedOops) { \ - InstanceRefKlass_SPECIALIZED_OOP_ITERATE(narrowOop, nv_suffix, mr.contains); \ - } else { \ - InstanceRefKlass_SPECIALIZED_OOP_ITERATE(oop, nv_suffix, mr.contains); \ - } \ -} - -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_DEFN) -#if INCLUDE_ALL_GCS -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -#endif // INCLUDE_ALL_GCS -ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_DEFN_m) -ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_DEFN_m) - -#if INCLUDE_ALL_GCS -template -void specialized_oop_push_contents(InstanceRefKlass *ref, - PSPromotionManager* pm, oop obj) { - T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); - if (PSScavenge::should_scavenge(referent_addr)) { - ReferenceProcessor* rp = PSScavenge::reference_processor(); - if (rp->discover_reference(obj, ref->reference_type())) { - // reference already enqueued, referent and next will be traversed later - ref->InstanceKlass::oop_push_contents(pm, obj); - return; - } else { - // treat referent as normal oop - pm->claim_or_forward_depth(referent_addr); - } - } - // Treat discovered as normal oop, if ref is not "active", - // i.e. if next is non-NULL. - T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); - if (ReferenceProcessor::pending_list_uses_discovered_field()) { - T next_oop = oopDesc::load_heap_oop(next_addr); - if (!oopDesc::is_null(next_oop)) { // i.e. ref is not "active" - T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Process discovered as normal " - INTPTR_FORMAT, discovered_addr); - } - ) - if (PSScavenge::should_scavenge(discovered_addr)) { - pm->claim_or_forward_depth(discovered_addr); - } - } - } else { -#ifdef ASSERT - // In the case of older JDKs which do not use the discovered - // field for the pending list, an inactive ref (next != NULL) - // must always have a NULL discovered field. - oop next = oopDesc::load_decode_heap_oop(next_addr); - oop discovered = java_lang_ref_Reference::discovered(obj); - assert(oopDesc::is_null(next) || oopDesc::is_null(discovered), - err_msg("Found an inactive reference " PTR_FORMAT " with a non-NULL discovered field", - (oopDesc*)obj)); -#endif - } - - // Treat next as normal oop; next is a link in the reference queue. - if (PSScavenge::should_scavenge(next_addr)) { - pm->claim_or_forward_depth(next_addr); - } - ref->InstanceKlass::oop_push_contents(pm, obj); -} - -void InstanceRefKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { - if (UseCompressedOops) { - specialized_oop_push_contents(this, pm, obj); - } else { - specialized_oop_push_contents(this, pm, obj); - } -} - -template -void specialized_oop_update_pointers(InstanceRefKlass *ref, - ParCompactionManager* cm, oop obj) { - T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); - PSParallelCompact::adjust_pointer(referent_addr); - T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); - PSParallelCompact::adjust_pointer(next_addr); - T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); - PSParallelCompact::adjust_pointer(discovered_addr); - debug_only(trace_reference_gc("InstanceRefKlass::oop_update_ptrs", obj, - referent_addr, next_addr, discovered_addr);) -} - -int InstanceRefKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { - InstanceKlass::oop_update_pointers(cm, obj); - if (UseCompressedOops) { - specialized_oop_update_pointers(this, cm, obj); - } else { - specialized_oop_update_pointers(this, cm, obj); - } - return size_helper(); -} -#endif // INCLUDE_ALL_GCS - void InstanceRefKlass::update_nonstatic_oop_maps(Klass* k) { // Clear the nonstatic oop-map entries corresponding to referent // and nextPending field. They are treated specially by the @@ -483,12 +78,6 @@ InstanceKlass::oop_verify_on(obj, st); // Verify referent field oop referent = java_lang_ref_Reference::referent(obj); - - // We should make this general to all heaps - GenCollectedHeap* gch = NULL; - if (Universe::heap()->kind() == CollectedHeap::GenCollectedHeap) - gch = GenCollectedHeap::heap(); - if (referent != NULL) { guarantee(referent->is_oop(), "referent field heap failed"); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/instanceRefKlass.hpp --- a/hotspot/src/share/vm/oops/instanceRefKlass.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/oops/instanceRefKlass.hpp Thu May 07 20:51:12 2015 -0700 @@ -64,30 +64,71 @@ return (InstanceRefKlass*) k; } - // Garbage collection - int oop_adjust_pointers(oop obj); - void oop_follow_contents(oop obj); + // GC specific object visitors + // + // Mark Sweep + void oop_ms_follow_contents(oop obj); + int oop_ms_adjust_pointers(oop obj); +#if INCLUDE_ALL_GCS + // Parallel Scavenge + void oop_ps_push_contents( oop obj, PSPromotionManager* pm); + // Parallel Compact + void oop_pc_follow_contents(oop obj, ParCompactionManager* cm); + void oop_pc_update_pointers(oop obj); +#endif - // Parallel Scavenge and Parallel Old - PARALLEL_GC_DECLS + // Oop fields (and metadata) iterators + // [nv = true] Use non-virtual calls to do_oop_nv. + // [nv = false] Use virtual calls to do_oop. + // + // The InstanceRefKlass iterators also support reference processing. + + + // Forward iteration +private: + // Iterate over all oop fields and metadata. + template + inline int oop_oop_iterate(oop obj, OopClosureType* closure); - int oop_oop_iterate(oop obj, ExtendedOopClosure* blk) { - return oop_oop_iterate_v(obj, blk); - } - int oop_oop_iterate_m(oop obj, ExtendedOopClosure* blk, MemRegion mr) { - return oop_oop_iterate_v_m(obj, blk, mr); - } + // Reverse iteration +#if INCLUDE_ALL_GCS + // Iterate over all oop fields and metadata. + template + inline int oop_oop_iterate_reverse(oop obj, OopClosureType* closure); +#endif // INCLUDE_ALL_GCS + + // Bounded range iteration + // Iterate over all oop fields and metadata. + template + inline int oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr); + + // Reference processing part of the iterators. -#define InstanceRefKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ - int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* blk); \ - int oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* blk, MemRegion mr); + // Specialized for [T = oop] or [T = narrowOop]. + template + inline void oop_oop_iterate_ref_processing_specialized(oop obj, OopClosureType* closure, Contains& contains); + + // Only perform reference processing if the referent object is within mr. + template + inline void oop_oop_iterate_ref_processing_bounded(oop obj, OopClosureType* closure, MemRegion mr); + + // Reference processing + template + inline void oop_oop_iterate_ref_processing(oop obj, OopClosureType* closure); + + + public: + +#define InstanceRefKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ + int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure); \ + int oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr); ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_DECL) #if INCLUDE_ALL_GCS -#define InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ - int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* blk); +#define InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ + int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure); ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/instanceRefKlass.inline.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/oops/instanceRefKlass.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_OOPS_INSTANCEREFKLASS_INLINE_HPP +#define SHARE_VM_OOPS_INSTANCEREFKLASS_INLINE_HPP + +#include "classfile/javaClasses.hpp" +#include "memory/referenceProcessor.hpp" +#include "oops/instanceRefKlass.hpp" +#include "oops/instanceKlass.inline.hpp" +#include "oops/oop.inline.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" + +template +void InstanceRefKlass::oop_oop_iterate_ref_processing_specialized(oop obj, OopClosureType* closure, Contains& contains) { + T* disc_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); + if (closure->apply_to_weak_ref_discovered_field()) { + Devirtualizer::do_oop(closure, disc_addr); + } + + T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); + T heap_oop = oopDesc::load_heap_oop(referent_addr); + ReferenceProcessor* rp = closure->_ref_processor; + if (!oopDesc::is_null(heap_oop)) { + oop referent = oopDesc::decode_heap_oop_not_null(heap_oop); + if (!referent->is_gc_marked() && (rp != NULL) && + rp->discover_reference(obj, reference_type())) { + return; + } else if (contains(referent_addr)) { + // treat referent as normal oop + Devirtualizer::do_oop(closure, referent_addr); + } + } + T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj); + if (ReferenceProcessor::pending_list_uses_discovered_field()) { + T next_oop = oopDesc::load_heap_oop(next_addr); + // Treat discovered as normal oop, if ref is not "active" (next non-NULL) + if (!oopDesc::is_null(next_oop) && contains(disc_addr)) { + // i.e. ref is not "active" + debug_only( + if(TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print_cr(" Process discovered as normal " + PTR_FORMAT, p2i(disc_addr)); + } + ) + Devirtualizer::do_oop(closure, disc_addr); + } + } else { + // In the case of older JDKs which do not use the discovered field for + // the pending list, an inactive ref (next != NULL) must always have a + // NULL discovered field. + debug_only( + T next_oop = oopDesc::load_heap_oop(next_addr); + T disc_oop = oopDesc::load_heap_oop(disc_addr); + assert(oopDesc::is_null(next_oop) || oopDesc::is_null(disc_oop), + err_msg("Found an inactive reference " PTR_FORMAT " with a non-NULL" + "discovered field", p2i(obj))); + ) + } + // treat next as normal oop + if (contains(next_addr)) { + Devirtualizer::do_oop(closure, next_addr); + } +} + +class AlwaysContains { + public: + template bool operator()(T* p) const { return true; } +}; + +template +void InstanceRefKlass::oop_oop_iterate_ref_processing(oop obj, OopClosureType* closure) { + AlwaysContains always_contains; + if (UseCompressedOops) { + oop_oop_iterate_ref_processing_specialized(obj, closure, always_contains); + } else { + oop_oop_iterate_ref_processing_specialized(obj, closure, always_contains); + } +} + +class MrContains { + const MemRegion _mr; + public: + MrContains(MemRegion mr) : _mr(mr) {} + template bool operator()(T* p) const { return _mr.contains(p); } +}; + +template +void InstanceRefKlass::oop_oop_iterate_ref_processing_bounded(oop obj, OopClosureType* closure, MemRegion mr) { + const MrContains contains(mr); + if (UseCompressedOops) { + oop_oop_iterate_ref_processing_specialized(obj, closure, contains); + } else { + oop_oop_iterate_ref_processing_specialized(obj, closure, contains); + } +} + +template +int InstanceRefKlass::oop_oop_iterate(oop obj, OopClosureType* closure) { + // Get size before changing pointers + int size = InstanceKlass::oop_oop_iterate(obj, closure); + + oop_oop_iterate_ref_processing(obj, closure); + + return size; +} + +#if INCLUDE_ALL_GCS +template +int InstanceRefKlass:: +oop_oop_iterate_reverse(oop obj, OopClosureType* closure) { + // Get size before changing pointers + int size = InstanceKlass::oop_oop_iterate_reverse(obj, closure); + + oop_oop_iterate_ref_processing(obj, closure); + + return size; +} +#endif // INCLUDE_ALL_GCS + + +template +int InstanceRefKlass::oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr) { + // Get size before changing pointers + int size = InstanceKlass::oop_oop_iterate_bounded(obj, closure, mr); + + oop_oop_iterate_ref_processing_bounded(obj, closure, mr); + + return size; +} + +// Macro to define InstanceRefKlass::oop_oop_iterate for virtual/nonvirtual for +// all closures. Macros calling macros above for each oop size. + +#define InstanceRefKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + \ +int InstanceRefKlass::oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { \ + return oop_oop_iterate(obj, closure); \ +} + +#if INCLUDE_ALL_GCS +#define InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ + \ +int InstanceRefKlass::oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) { \ + return oop_oop_iterate_reverse(obj, closure); \ +} +#else +#define InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) +#endif + + +#define InstanceRefKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ + \ +int InstanceRefKlass::oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr) { \ + return oop_oop_iterate_bounded(obj, closure, mr); \ +} + +#define ALL_INSTANCE_REF_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + InstanceRefKlass_OOP_OOP_ITERATE_DEFN( OopClosureType, nv_suffix) \ + InstanceRefKlass_OOP_OOP_ITERATE_DEFN_m( OopClosureType, nv_suffix) \ + InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) + + +#endif // SHARE_VM_OOPS_INSTANCEREFKLASS_INLINE_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/klass.cpp --- a/hotspot/src/share/vm/oops/klass.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/oops/klass.cpp Thu May 07 20:51:12 2015 -0700 @@ -27,7 +27,6 @@ #include "classfile/dictionary.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" -#include "gc_implementation/shared/markSweep.inline.hpp" #include "gc_interface/collectedHeap.inline.hpp" #include "memory/heapInspection.hpp" #include "memory/metadataFactory.hpp" @@ -43,9 +42,6 @@ #include "utilities/stack.inline.hpp" #if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" -#include "gc_implementation/parallelScavenge/psParallelCompact.hpp" -#include "gc_implementation/parallelScavenge/psPromotionManager.hpp" -#include "gc_implementation/parallelScavenge/psScavenge.hpp" #endif // INCLUDE_ALL_GCS void Klass::set_name(Symbol* n) { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/klass.hpp --- a/hotspot/src/share/vm/oops/klass.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/oops/klass.hpp Thu May 07 20:51:12 2015 -0700 @@ -25,21 +25,14 @@ #ifndef SHARE_VM_OOPS_KLASS_HPP #define SHARE_VM_OOPS_KLASS_HPP -#include "memory/genOopClosures.hpp" #include "memory/iterator.hpp" #include "memory/memRegion.hpp" #include "memory/specialized_oop_closures.hpp" -#include "oops/klassPS.hpp" #include "oops/metadata.hpp" #include "oops/oop.hpp" #include "trace/traceMacros.hpp" #include "utilities/accessFlags.hpp" #include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS -#include "gc_implementation/concurrentMarkSweep/cmsOopClosures.hpp" -#include "gc_implementation/g1/g1OopClosures.hpp" -#include "gc_implementation/parNew/parOopClosures.hpp" -#endif // INCLUDE_ALL_GCS // // A Klass provides: @@ -61,6 +54,7 @@ class ClassLoaderData; class klassVtable; class ParCompactionManager; +class PSPromotionManager; class KlassSizeStats; class fieldDescriptor; @@ -478,13 +472,6 @@ // and the package separators as '/'. virtual const char* signature_name() const; - // garbage collection support - virtual void oop_follow_contents(oop obj) = 0; - virtual int oop_adjust_pointers(oop obj) = 0; - - // Parallel Scavenge and Parallel Old - PARALLEL_GC_DECLS_PV - // type testing operations protected: virtual bool oop_is_instance_slow() const { return false; } @@ -581,60 +568,35 @@ clean_weak_klass_links(is_alive, false /* clean_alive_klasses */); } - // iterators - virtual int oop_oop_iterate(oop obj, ExtendedOopClosure* blk) = 0; - virtual int oop_oop_iterate_v(oop obj, ExtendedOopClosure* blk) { - return oop_oop_iterate(obj, blk); - } + // GC specific object visitors + // + // Mark Sweep + virtual void oop_ms_follow_contents(oop obj) = 0; + virtual int oop_ms_adjust_pointers(oop obj) = 0; +#if INCLUDE_ALL_GCS + // Parallel Scavenge + virtual void oop_ps_push_contents( oop obj, PSPromotionManager* pm) = 0; + // Parallel Compact + virtual void oop_pc_follow_contents(oop obj, ParCompactionManager* cm) = 0; + virtual void oop_pc_update_pointers(oop obj) = 0; +#endif + + // Iterators specialized to particular subtypes + // of ExtendedOopClosure, to avoid closure virtual calls. +#define Klass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ + virtual int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) = 0; \ + /* Iterates "closure" over all the oops in "obj" (of type "this") within "mr". */ \ + virtual int oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr) = 0; + + ALL_OOP_OOP_ITERATE_CLOSURES_1(Klass_OOP_OOP_ITERATE_DECL) + ALL_OOP_OOP_ITERATE_CLOSURES_2(Klass_OOP_OOP_ITERATE_DECL) #if INCLUDE_ALL_GCS - // In case we don't have a specialized backward scanner use forward - // iteration. - virtual int oop_oop_iterate_backwards_v(oop obj, ExtendedOopClosure* blk) { - return oop_oop_iterate_v(obj, blk); - } -#endif // INCLUDE_ALL_GCS - - // Iterates "blk" over all the oops in "obj" (of type "this") within "mr". - // (I don't see why the _m should be required, but without it the Solaris - // C++ gives warning messages about overridings of the "oop_oop_iterate" - // defined above "hiding" this virtual function. (DLD, 6/20/00)) */ - virtual int oop_oop_iterate_m(oop obj, ExtendedOopClosure* blk, MemRegion mr) = 0; - virtual int oop_oop_iterate_v_m(oop obj, ExtendedOopClosure* blk, MemRegion mr) { - return oop_oop_iterate_m(obj, blk, mr); - } +#define Klass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ + virtual int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) = 0; - // Versions of the above iterators specialized to particular subtypes - // of OopClosure, to avoid closure virtual calls. -#define Klass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ - virtual int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* blk) { \ - /* Default implementation reverts to general version. */ \ - return oop_oop_iterate(obj, blk); \ - } \ - \ - /* Iterates "blk" over all the oops in "obj" (of type "this") within "mr". \ - (I don't see why the _m should be required, but without it the Solaris \ - C++ gives warning messages about overridings of the "oop_oop_iterate" \ - defined above "hiding" this virtual function. (DLD, 6/20/00)) */ \ - virtual int oop_oop_iterate##nv_suffix##_m(oop obj, \ - OopClosureType* blk, \ - MemRegion mr) { \ - return oop_oop_iterate_m(obj, blk, mr); \ - } - - SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_1(Klass_OOP_OOP_ITERATE_DECL) - SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_2(Klass_OOP_OOP_ITERATE_DECL) - -#if INCLUDE_ALL_GCS -#define Klass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ - virtual int oop_oop_iterate_backwards##nv_suffix(oop obj, \ - OopClosureType* blk) { \ - /* Default implementation reverts to general version. */ \ - return oop_oop_iterate_backwards_v(obj, blk); \ - } - - SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_1(Klass_OOP_OOP_ITERATE_BACKWARDS_DECL) - SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_2(Klass_OOP_OOP_ITERATE_BACKWARDS_DECL) + ALL_OOP_OOP_ITERATE_CLOSURES_1(Klass_OOP_OOP_ITERATE_BACKWARDS_DECL) + ALL_OOP_OOP_ITERATE_CLOSURES_2(Klass_OOP_OOP_ITERATE_BACKWARDS_DECL) #endif // INCLUDE_ALL_GCS virtual void array_klasses_do(void f(Klass* k)) {} diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/klassPS.hpp --- a/hotspot/src/share/vm/oops/klassPS.hpp Thu May 07 10:19:31 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2007, 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 SHARE_VM_OOPS_KLASSPS_HPP -#define SHARE_VM_OOPS_KLASSPS_HPP - - // Expands to Parallel Scavenge and Parallel Old declarations - -#include "utilities/macros.hpp" - -#if INCLUDE_ALL_GCS -#define PARALLEL_GC_DECLS \ - virtual void oop_push_contents(PSPromotionManager* pm, oop obj); \ - /* Parallel Old GC support \ - \ - The 2-arg version of oop_update_pointers is for objects that are \ - known not to cross chunk boundaries. The 4-arg version is for \ - objects that do (or may) cross chunk boundaries; it updates only those \ - oops that are in the region [beg_addr, end_addr). */ \ - virtual void oop_follow_contents(ParCompactionManager* cm, oop obj); \ - virtual int oop_update_pointers(ParCompactionManager* cm, oop obj); - -// Pure virtual version for klass.hpp -#define PARALLEL_GC_DECLS_PV \ - virtual void oop_push_contents(PSPromotionManager* pm, oop obj) = 0; \ - virtual void oop_follow_contents(ParCompactionManager* cm, oop obj) = 0; \ - virtual int oop_update_pointers(ParCompactionManager* cm, oop obj) = 0; -#else // INCLUDE_ALL_GCS -#define PARALLEL_GC_DECLS -#define PARALLEL_GC_DECLS_PV -#endif // INCLUDE_ALL_GCS - -#endif // SHARE_VM_OOPS_KLASSPS_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/methodData.cpp --- a/hotspot/src/share/vm/oops/methodData.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/oops/methodData.cpp Thu May 07 20:51:12 2015 -0700 @@ -152,6 +152,7 @@ void BitData::print_data_on(outputStream* st, const char* extra) const { print_shared(st, "BitData", extra); + st->cr(); } // ================================================================== diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/methodData.hpp --- a/hotspot/src/share/vm/oops/methodData.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/oops/methodData.hpp Thu May 07 20:51:12 2015 -0700 @@ -2056,7 +2056,7 @@ // Whole-method sticky bits and flags enum { - _trap_hist_limit = 21, // decoupled from Deoptimization::Reason_LIMIT + _trap_hist_limit = 22, // decoupled from Deoptimization::Reason_LIMIT _trap_hist_mask = max_jubyte, _extra_data_count = 4 // extra DataLayout headers, for trap history }; // Public flag values diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/objArrayKlass.cpp --- a/hotspot/src/share/vm/oops/objArrayKlass.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/oops/objArrayKlass.cpp Thu May 07 20:51:12 2015 -0700 @@ -26,9 +26,7 @@ #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" -#include "gc_implementation/shared/markSweep.inline.hpp" #include "gc_interface/collectedHeap.inline.hpp" -#include "memory/genOopClosures.inline.hpp" #include "memory/iterator.inline.hpp" #include "memory/metadataFactory.hpp" #include "memory/resourceArea.hpp" @@ -45,17 +43,6 @@ #include "runtime/orderAccess.inline.hpp" #include "utilities/copy.hpp" #include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS -#include "gc_implementation/concurrentMarkSweep/cmsOopClosures.inline.hpp" -#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" -#include "gc_implementation/g1/g1OopClosures.inline.hpp" -#include "gc_implementation/g1/g1RemSet.inline.hpp" -#include "gc_implementation/g1/heapRegionManager.inline.hpp" -#include "gc_implementation/parNew/parOopClosures.inline.hpp" -#include "gc_implementation/parallelScavenge/psCompactionManager.hpp" -#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" -#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" -#endif // INCLUDE_ALL_GCS ObjArrayKlass* ObjArrayKlass::allocate(ClassLoaderData* loader_data, int n, KlassHandle klass_handle, Symbol* name, TRAPS) { assert(ObjArrayKlass::header_size() <= InstanceKlass::header_size(), @@ -410,179 +397,6 @@ bottom_klass()->initialize(THREAD); // dispatches to either InstanceKlass or TypeArrayKlass } -#define ObjArrayKlass_SPECIALIZED_OOP_ITERATE(T, a, p, do_oop) \ -{ \ - T* p = (T*)(a)->base(); \ - T* const end = p + (a)->length(); \ - while (p < end) { \ - do_oop; \ - p++; \ - } \ -} - -#define ObjArrayKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(T, a, p, low, high, do_oop) \ -{ \ - T* const l = (T*)(low); \ - T* const h = (T*)(high); \ - T* p = (T*)(a)->base(); \ - T* end = p + (a)->length(); \ - if (p < l) p = l; \ - if (end > h) end = h; \ - while (p < end) { \ - do_oop; \ - ++p; \ - } \ -} - -#define ObjArrayKlass_OOP_ITERATE(a, p, do_oop) \ - if (UseCompressedOops) { \ - ObjArrayKlass_SPECIALIZED_OOP_ITERATE(narrowOop, \ - a, p, do_oop) \ - } else { \ - ObjArrayKlass_SPECIALIZED_OOP_ITERATE(oop, \ - a, p, do_oop) \ - } - -#define ObjArrayKlass_BOUNDED_OOP_ITERATE(a, p, low, high, do_oop) \ - if (UseCompressedOops) { \ - ObjArrayKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(narrowOop, \ - a, p, low, high, do_oop) \ - } else { \ - ObjArrayKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(oop, \ - a, p, low, high, do_oop) \ - } - -void ObjArrayKlass::oop_follow_contents(oop obj) { - assert (obj->is_array(), "obj must be array"); - MarkSweep::follow_klass(obj->klass()); - if (UseCompressedOops) { - objarray_follow_contents(obj, 0); - } else { - objarray_follow_contents(obj, 0); - } -} - -#if INCLUDE_ALL_GCS -void ObjArrayKlass::oop_follow_contents(ParCompactionManager* cm, - oop obj) { - assert(obj->is_array(), "obj must be array"); - PSParallelCompact::follow_klass(cm, obj->klass()); - if (UseCompressedOops) { - objarray_follow_contents(cm, obj, 0); - } else { - objarray_follow_contents(cm, obj, 0); - } -} -#endif // INCLUDE_ALL_GCS - -#define ObjArrayKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ - \ -int ObjArrayKlass::oop_oop_iterate##nv_suffix(oop obj, \ - OopClosureType* closure) { \ - assert (obj->is_array(), "obj must be array"); \ - objArrayOop a = objArrayOop(obj); \ - /* Get size before changing pointers. */ \ - /* Don't call size() or oop_size() since that is a virtual call. */ \ - int size = a->object_size(); \ - if_do_metadata_checked(closure, nv_suffix) { \ - closure->do_klass##nv_suffix(obj->klass()); \ - } \ - ObjArrayKlass_OOP_ITERATE(a, p, (closure)->do_oop##nv_suffix(p)) \ - return size; \ -} - -#define ObjArrayKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ - \ -int ObjArrayKlass::oop_oop_iterate##nv_suffix##_m(oop obj, \ - OopClosureType* closure, \ - MemRegion mr) { \ - assert(obj->is_array(), "obj must be array"); \ - objArrayOop a = objArrayOop(obj); \ - /* Get size before changing pointers. */ \ - /* Don't call size() or oop_size() since that is a virtual call */ \ - int size = a->object_size(); \ - if_do_metadata_checked(closure, nv_suffix) { \ - /* SSS: Do we need to pass down mr here? */ \ - closure->do_klass##nv_suffix(a->klass()); \ - } \ - ObjArrayKlass_BOUNDED_OOP_ITERATE( \ - a, p, mr.start(), mr.end(), (closure)->do_oop##nv_suffix(p)) \ - return size; \ -} - -// Like oop_oop_iterate but only iterates over a specified range and only used -// for objArrayOops. -#define ObjArrayKlass_OOP_OOP_ITERATE_DEFN_r(OopClosureType, nv_suffix) \ - \ -int ObjArrayKlass::oop_oop_iterate_range##nv_suffix(oop obj, \ - OopClosureType* closure, \ - int start, int end) { \ - assert(obj->is_array(), "obj must be array"); \ - objArrayOop a = objArrayOop(obj); \ - /* Get size before changing pointers. */ \ - /* Don't call size() or oop_size() since that is a virtual call */ \ - int size = a->object_size(); \ - if (UseCompressedOops) { \ - HeapWord* low = start == 0 ? (HeapWord*)a : (HeapWord*)a->obj_at_addr(start);\ - /* this might be wierd if end needs to be aligned on HeapWord boundary */ \ - HeapWord* high = (HeapWord*)((narrowOop*)a->base() + end); \ - MemRegion mr(low, high); \ - if_do_metadata_checked(closure, nv_suffix) { \ - /* SSS: Do we need to pass down mr here? */ \ - closure->do_klass##nv_suffix(a->klass()); \ - } \ - ObjArrayKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(narrowOop, \ - a, p, low, high, (closure)->do_oop##nv_suffix(p)) \ - } else { \ - HeapWord* low = start == 0 ? (HeapWord*)a : (HeapWord*)a->obj_at_addr(start); \ - HeapWord* high = (HeapWord*)((oop*)a->base() + end); \ - MemRegion mr(low, high); \ - if_do_metadata_checked(closure, nv_suffix) { \ - /* SSS: Do we need to pass down mr here? */ \ - closure->do_klass##nv_suffix(a->klass()); \ - } \ - ObjArrayKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(oop, \ - a, p, low, high, (closure)->do_oop##nv_suffix(p)) \ - } \ - return size; \ -} - -ALL_OOP_OOP_ITERATE_CLOSURES_1(ObjArrayKlass_OOP_OOP_ITERATE_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_2(ObjArrayKlass_OOP_OOP_ITERATE_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_1(ObjArrayKlass_OOP_OOP_ITERATE_DEFN_m) -ALL_OOP_OOP_ITERATE_CLOSURES_2(ObjArrayKlass_OOP_OOP_ITERATE_DEFN_m) -ALL_OOP_OOP_ITERATE_CLOSURES_1(ObjArrayKlass_OOP_OOP_ITERATE_DEFN_r) -ALL_OOP_OOP_ITERATE_CLOSURES_2(ObjArrayKlass_OOP_OOP_ITERATE_DEFN_r) - -int ObjArrayKlass::oop_adjust_pointers(oop obj) { - assert(obj->is_objArray(), "obj must be obj array"); - objArrayOop a = objArrayOop(obj); - // Get size before changing pointers. - // Don't call size() or oop_size() since that is a virtual call. - int size = a->object_size(); - ObjArrayKlass_OOP_ITERATE(a, p, MarkSweep::adjust_pointer(p)) - return size; -} - -#if INCLUDE_ALL_GCS -void ObjArrayKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { - assert(obj->is_objArray(), "obj must be obj array"); - ObjArrayKlass_OOP_ITERATE( \ - objArrayOop(obj), p, \ - if (PSScavenge::should_scavenge(p)) { \ - pm->claim_or_forward_depth(p); \ - }) -} - -int ObjArrayKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { - assert (obj->is_objArray(), "obj must be obj array"); - objArrayOop a = objArrayOop(obj); - int size = a->object_size(); - ObjArrayKlass_OOP_ITERATE(a, p, PSParallelCompact::adjust_pointer(p)) - return size; -} -#endif // INCLUDE_ALL_GCS - // JVM support jint ObjArrayKlass::compute_modifier_flags(TRAPS) const { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/objArrayKlass.hpp --- a/hotspot/src/share/vm/oops/objArrayKlass.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/oops/objArrayKlass.hpp Thu May 07 20:51:12 2015 -0700 @@ -26,7 +26,6 @@ #define SHARE_VM_OOPS_OBJARRAYKLASS_HPP #include "classfile/classLoaderData.hpp" -#include "memory/specialized_oop_closures.hpp" #include "oops/arrayKlass.hpp" #include "utilities/macros.hpp" @@ -103,28 +102,67 @@ // Initialization (virtual from Klass) void initialize(TRAPS); - // Garbage collection - void oop_follow_contents(oop obj); - inline void oop_follow_contents(oop obj, int index); - template inline void objarray_follow_contents(oop obj, int index); - - int oop_adjust_pointers(oop obj); - - // Parallel Scavenge and Parallel Old - PARALLEL_GC_DECLS + // GC specific object visitors + // + // Mark Sweep + void oop_ms_follow_contents(oop obj); + int oop_ms_adjust_pointers(oop obj); #if INCLUDE_ALL_GCS - inline void oop_follow_contents(ParCompactionManager* cm, oop obj, int index); - template inline void - objarray_follow_contents(ParCompactionManager* cm, oop obj, int index); -#endif // INCLUDE_ALL_GCS + // Parallel Scavenge + void oop_ps_push_contents( oop obj, PSPromotionManager* pm); + // Parallel Compact + void oop_pc_follow_contents(oop obj, ParCompactionManager* cm); + void oop_pc_update_pointers(oop obj); +#endif + + // Oop fields (and metadata) iterators + // [nv = true] Use non-virtual calls to do_oop_nv. + // [nv = false] Use virtual calls to do_oop. + // + // The ObjArrayKlass iterators also visits the Object's klass. + + private: + + // Iterate over oop elements and metadata. + template + inline int oop_oop_iterate(oop obj, OopClosureType* closure); + + // Iterate over oop elements within mr, and metadata. + template + inline int oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr); + + // Iterate over oop elements with indices within [start, end), and metadata. + template + inline int oop_oop_iterate_range(oop obj, OopClosureType* closure, int start, int end); - // Iterators - int oop_oop_iterate(oop obj, ExtendedOopClosure* blk) { - return oop_oop_iterate_v(obj, blk); - } - int oop_oop_iterate_m(oop obj, ExtendedOopClosure* blk, MemRegion mr) { - return oop_oop_iterate_v_m(obj, blk, mr); - } + // Iterate over oop elements within [start, end), and metadata. + // Specialized for [T = oop] or [T = narrowOop]. + template + inline void oop_oop_iterate_range_specialized(objArrayOop a, OopClosureType* closure, int start, int end); + + public: + // Iterate over all oop elements. + template + inline void oop_oop_iterate_elements(objArrayOop a, OopClosureType* closure); + + private: + // Iterate over all oop elements. + // Specialized for [T = oop] or [T = narrowOop]. + template + inline void oop_oop_iterate_elements_specialized(objArrayOop a, OopClosureType* closure); + + // Iterate over all oop elements with indices within mr. + template + inline void oop_oop_iterate_elements_bounded(objArrayOop a, OopClosureType* closure, MemRegion mr); + + // Iterate over oop elements within [low, high).. + // Specialized for [T = oop] or [T = narrowOop]. + template + inline void oop_oop_iterate_elements_specialized_bounded(objArrayOop a, OopClosureType* closure, void* low, void* high); + + + public: + #define ObjArrayKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* blk); \ int oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* blk, \ @@ -135,6 +173,14 @@ ALL_OOP_OOP_ITERATE_CLOSURES_1(ObjArrayKlass_OOP_OOP_ITERATE_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(ObjArrayKlass_OOP_OOP_ITERATE_DECL) +#if INCLUDE_ALL_GCS +#define ObjArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ + int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* blk); + + ALL_OOP_OOP_ITERATE_CLOSURES_1(ObjArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) + ALL_OOP_OOP_ITERATE_CLOSURES_2(ObjArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) +#endif // INCLUDE_ALL_GCS + // JVM support jint compute_modifier_flags(TRAPS) const; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/objArrayKlass.inline.hpp --- a/hotspot/src/share/vm/oops/objArrayKlass.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/oops/objArrayKlass.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,78 +25,165 @@ #ifndef SHARE_VM_OOPS_OBJARRAYKLASS_INLINE_HPP #define SHARE_VM_OOPS_OBJARRAYKLASS_INLINE_HPP -#include "gc_implementation/shared/markSweep.inline.hpp" +#include "memory/memRegion.hpp" +#include "memory/iterator.inline.hpp" #include "oops/objArrayKlass.hpp" +#include "oops/objArrayOop.inline.hpp" +#include "oops/oop.inline.hpp" #include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS -#include "gc_implementation/parallelScavenge/psCompactionManager.inline.hpp" -#include "gc_implementation/parallelScavenge/psParallelCompact.hpp" -#endif // INCLUDE_ALL_GCS + +template +void ObjArrayKlass::oop_oop_iterate_elements_specialized(objArrayOop a, OopClosureType* closure) { + T* p = (T*)a->base(); + T* const end = p + a->length(); + + for (;p < end; p++) { + Devirtualizer::do_oop(closure, p); + } +} + +template +void ObjArrayKlass::oop_oop_iterate_elements_specialized_bounded( + objArrayOop a, OopClosureType* closure, void* low, void* high) { + + T* const l = (T*)low; + T* const h = (T*)high; + + T* p = (T*)a->base(); + T* end = p + a->length(); -void ObjArrayKlass::oop_follow_contents(oop obj, int index) { + if (p < l) { + p = l; + } + if (end > h) { + end = h; + } + + for (;p < end; ++p) { + Devirtualizer::do_oop(closure, p); + } +} + +template +void ObjArrayKlass::oop_oop_iterate_elements(objArrayOop a, OopClosureType* closure) { if (UseCompressedOops) { - objarray_follow_contents(obj, index); + oop_oop_iterate_elements_specialized(a, closure); } else { - objarray_follow_contents(obj, index); + oop_oop_iterate_elements_specialized(a, closure); + } +} + +template +void ObjArrayKlass::oop_oop_iterate_elements_bounded(objArrayOop a, OopClosureType* closure, MemRegion mr) { + if (UseCompressedOops) { + oop_oop_iterate_elements_specialized_bounded(a, closure, mr.start(), mr.end()); + } else { + oop_oop_iterate_elements_specialized_bounded(a, closure, mr.start(), mr.end()); } } -template -void ObjArrayKlass::objarray_follow_contents(oop obj, int index) { +template +int ObjArrayKlass::oop_oop_iterate(oop obj, OopClosureType* closure) { + assert (obj->is_array(), "obj must be array"); objArrayOop a = objArrayOop(obj); - const size_t len = size_t(a->length()); - const size_t beg_index = size_t(index); - assert(beg_index < len || len == 0, "index too large"); + + // Get size before changing pointers. + // Don't call size() or oop_size() since that is a virtual call. + int size = a->object_size(); + if (Devirtualizer::do_metadata(closure)) { + Devirtualizer::do_klass(closure, obj->klass()); + } + + oop_oop_iterate_elements(a, closure); - const size_t stride = MIN2(len - beg_index, ObjArrayMarkingStride); - const size_t end_index = beg_index + stride; - T* const base = (T*)a->base(); - T* const beg = base + beg_index; - T* const end = base + end_index; + return size; +} - // Push the non-NULL elements of the next stride on the marking stack. - for (T* e = beg; e < end; e++) { - MarkSweep::mark_and_push(e); +template +int ObjArrayKlass::oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr) { + assert(obj->is_array(), "obj must be array"); + objArrayOop a = objArrayOop(obj); + + // Get size before changing pointers. + // Don't call size() or oop_size() since that is a virtual call + int size = a->object_size(); + + if (Devirtualizer::do_metadata(closure)) { + Devirtualizer::do_klass(closure, a->klass()); } - if (end_index < len) { - MarkSweep::push_objarray(a, end_index); // Push the continuation. + oop_oop_iterate_elements_bounded(a, closure, mr); + + return size; +} + +template +void ObjArrayKlass::oop_oop_iterate_range_specialized(objArrayOop a, OopClosureType* closure, int start, int end) { + if (Devirtualizer::do_metadata(closure)) { + Devirtualizer::do_klass(closure, a->klass()); } + + T* low = start == 0 ? cast_from_oop(a) : a->obj_at_addr(start); + T* high = (T*)a->base() + end; + + oop_oop_iterate_elements_specialized_bounded(a, closure, low, high); +} + +// Like oop_oop_iterate but only iterates over a specified range and only used +// for objArrayOops. +template +int ObjArrayKlass::oop_oop_iterate_range(oop obj, OopClosureType* closure, int start, int end) { + assert(obj->is_array(), "obj must be array"); + objArrayOop a = objArrayOop(obj); + + // Get size before changing pointers. + // Don't call size() or oop_size() since that is a virtual call + int size = a->object_size(); + + if (UseCompressedOops) { + oop_oop_iterate_range_specialized(a, closure, start, end); + } else { + oop_oop_iterate_range_specialized(a, closure, start, end); + } + + return size; +} + + +#define ObjArrayKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + \ +int ObjArrayKlass::oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { \ + return oop_oop_iterate(obj, closure); \ } #if INCLUDE_ALL_GCS -void ObjArrayKlass::oop_follow_contents(ParCompactionManager* cm, oop obj, - int index) { - if (UseCompressedOops) { - objarray_follow_contents(cm, obj, index); - } else { - objarray_follow_contents(cm, obj, index); - } +#define ObjArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ +int ObjArrayKlass::oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) { \ + /* No reverse implementation ATM. */ \ + return oop_oop_iterate(obj, closure); \ +} +#else +#define ObjArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) +#endif + +#define ObjArrayKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ + \ +int ObjArrayKlass::oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr) { \ + return oop_oop_iterate_bounded(obj, closure, mr); \ } -template -void ObjArrayKlass::objarray_follow_contents(ParCompactionManager* cm, oop obj, - int index) { - objArrayOop a = objArrayOop(obj); - const size_t len = size_t(a->length()); - const size_t beg_index = size_t(index); - assert(beg_index < len || len == 0, "index too large"); +#define ObjArrayKlass_OOP_OOP_ITERATE_DEFN_r(OopClosureType, nv_suffix) \ + \ +int ObjArrayKlass::oop_oop_iterate_range##nv_suffix(oop obj, OopClosureType* closure, int start, int end) { \ + return oop_oop_iterate_range(obj, closure, start, end); \ +} + - const size_t stride = MIN2(len - beg_index, ObjArrayMarkingStride); - const size_t end_index = beg_index + stride; - T* const base = (T*)a->base(); - T* const beg = base + beg_index; - T* const end = base + end_index; +#define ALL_OBJ_ARRAY_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + ObjArrayKlass_OOP_OOP_ITERATE_DEFN( OopClosureType, nv_suffix) \ + ObjArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ + ObjArrayKlass_OOP_OOP_ITERATE_DEFN_m( OopClosureType, nv_suffix) \ + ObjArrayKlass_OOP_OOP_ITERATE_DEFN_r( OopClosureType, nv_suffix) - // Push the non-NULL elements of the next stride on the marking stack. - for (T* e = beg; e < end; e++) { - PSParallelCompact::mark_and_push(cm, e); - } - - if (end_index < len) { - cm->push_objarray(a, end_index); // Push the continuation. - } -} -#endif // INCLUDE_ALL_GCS #endif // SHARE_VM_OOPS_OBJARRAYKLASS_INLINE_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/oop.hpp --- a/hotspot/src/share/vm/oops/oop.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/oops/oop.hpp Thu May 07 20:51:12 2015 -0700 @@ -298,19 +298,6 @@ // garbage collection bool is_gc_marked() const; - // Apply "MarkSweep::mark_and_push" to (the address of) every non-NULL - // reference field in "this". - void follow_contents(void); - -#if INCLUDE_ALL_GCS - // Parallel Scavenge - void push_contents(PSPromotionManager* pm); - - // Parallel Old - void update_contents(ParCompactionManager* cm); - - void follow_contents(ParCompactionManager* cm); -#endif // INCLUDE_ALL_GCS bool is_scavengable() const; @@ -334,9 +321,6 @@ uint age() const; void incr_age(); - // Adjust all pointers in this object to point at it's forwarded location and - // return the size of this oop. This is used by the MarkSweep collector. - int adjust_pointers(); // mark-sweep support void follow_body(int begin, int end); @@ -345,6 +329,22 @@ static BarrierSet* bs() { return _bs; } static void set_bs(BarrierSet* bs) { _bs = bs; } + // Garbage Collection support + + // Mark Sweep + void ms_follow_contents(); + // Adjust all pointers in this object to point at it's forwarded location and + // return the size of this oop. This is used by the MarkSweep collector. + int ms_adjust_pointers(); +#if INCLUDE_ALL_GCS + // Parallel Compact + void pc_follow_contents(ParCompactionManager* pc); + void pc_update_contents(); + // Parallel Scavenge + void ps_push_contents(PSPromotionManager* pm); +#endif + + // iterators, returns size of object #define OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ int oop_iterate(OopClosureType* blk); \ diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/oop.inline.hpp --- a/hotspot/src/share/vm/oops/oop.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/oops/oop.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -26,13 +26,11 @@ #define SHARE_VM_OOPS_OOP_INLINE_HPP #include "gc_implementation/shared/ageTable.hpp" -#include "gc_implementation/shared/markSweep.inline.hpp" #include "gc_interface/collectedHeap.inline.hpp" #include "memory/barrierSet.inline.hpp" #include "memory/cardTableModRefBS.hpp" #include "memory/genCollectedHeap.hpp" #include "memory/generation.hpp" -#include "memory/specialized_oop_closures.hpp" #include "oops/arrayKlass.hpp" #include "oops/arrayOop.hpp" #include "oops/klass.inline.hpp" @@ -592,11 +590,6 @@ } #endif // PRODUCT -inline void oopDesc::follow_contents(void) { - assert (is_gc_marked(), "should be marked"); - klass()->oop_follow_contents(this); -} - inline bool oopDesc::is_scavengable() const { return Universe::heap()->is_scavengable(this); } @@ -706,21 +699,49 @@ } } -inline int oopDesc::adjust_pointers() { +inline void oopDesc::ms_follow_contents() { + klass()->oop_ms_follow_contents(this); +} + +inline int oopDesc::ms_adjust_pointers() { debug_only(int check_size = size()); - int s = klass()->oop_adjust_pointers(this); + int s = klass()->oop_ms_adjust_pointers(this); assert(s == check_size, "should be the same"); return s; } -#define OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ - \ -inline int oopDesc::oop_iterate(OopClosureType* blk) { \ - return klass()->oop_oop_iterate##nv_suffix(this, blk); \ -} \ - \ -inline int oopDesc::oop_iterate(OopClosureType* blk, MemRegion mr) { \ - return klass()->oop_oop_iterate##nv_suffix##_m(this, blk, mr); \ +#if INCLUDE_ALL_GCS +inline void oopDesc::pc_follow_contents(ParCompactionManager* cm) { + klass()->oop_pc_follow_contents(this, cm); +} + +inline void oopDesc::pc_update_contents() { + Klass* k = klass(); + if (!k->oop_is_typeArray()) { + // It might contain oops beyond the header, so take the virtual call. + k->oop_pc_update_pointers(this); + } + // Else skip it. The TypeArrayKlass in the header never needs scavenging. +} + +inline void oopDesc::ps_push_contents(PSPromotionManager* pm) { + Klass* k = klass(); + if (!k->oop_is_typeArray()) { + // It might contain oops beyond the header, so take the virtual call. + k->oop_ps_push_contents(this, pm); + } + // Else skip it. The TypeArrayKlass in the header never needs scavenging. +} +#endif + +#define OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + \ +inline int oopDesc::oop_iterate(OopClosureType* blk) { \ + return klass()->oop_oop_iterate##nv_suffix(this, blk); \ +} \ + \ +inline int oopDesc::oop_iterate(OopClosureType* blk, MemRegion mr) { \ + return klass()->oop_oop_iterate##nv_suffix##_m(this, blk, mr); \ } @@ -736,18 +757,21 @@ return oop_iterate(&cl, mr); } -ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_ITERATE_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_ITERATE_DEFN) +#if INCLUDE_ALL_GCS +#define OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ + \ +inline int oopDesc::oop_iterate_backwards(OopClosureType* blk) { \ + return klass()->oop_oop_iterate_backwards##nv_suffix(this, blk); \ +} +#else +#define OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) +#endif -#if INCLUDE_ALL_GCS -#define OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ - \ -inline int oopDesc::oop_iterate_backwards(OopClosureType* blk) { \ - return klass()->oop_oop_iterate_backwards##nv_suffix(this, blk); \ -} +#define ALL_OOPDESC_OOP_ITERATE(OopClosureType, nv_suffix) \ + OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) -ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_ITERATE_BACKWARDS_DEFN) -ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_ITERATE_BACKWARDS_DEFN) -#endif // INCLUDE_ALL_GCS +ALL_OOP_OOP_ITERATE_CLOSURES_1(ALL_OOPDESC_OOP_ITERATE) +ALL_OOP_OOP_ITERATE_CLOSURES_2(ALL_OOPDESC_OOP_ITERATE) #endif // SHARE_VM_OOPS_OOP_INLINE_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/oop.pcgc.inline.hpp --- a/hotspot/src/share/vm/oops/oop.pcgc.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_VM_OOPS_OOP_PCGC_INLINE_HPP -#define SHARE_VM_OOPS_OOP_PCGC_INLINE_HPP - -#include "runtime/atomic.inline.hpp" -#include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS -#include "gc_implementation/parNew/parNewGeneration.hpp" -#include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" -#include "gc_implementation/parallelScavenge/psCompactionManager.hpp" -#include "gc_implementation/parallelScavenge/psParallelCompact.hpp" -#include "gc_implementation/parallelScavenge/psScavenge.hpp" -#endif // INCLUDE_ALL_GCS - -inline void oopDesc::update_contents(ParCompactionManager* cm) { - // The klass field must be updated before anything else - // can be done. - DEBUG_ONLY(Klass* original_klass = klass()); - - Klass* new_klass = klass(); - if (!new_klass->oop_is_typeArray()) { - // It might contain oops beyond the header, so take the virtual call. - new_klass->oop_update_pointers(cm, this); - } - // Else skip it. The TypeArrayKlass in the header never needs scavenging. -} - -inline void oopDesc::follow_contents(ParCompactionManager* cm) { - assert (PSParallelCompact::mark_bitmap()->is_marked(this), - "should be marked"); - klass()->oop_follow_contents(cm, this); -} - -#endif // SHARE_VM_OOPS_OOP_PCGC_INLINE_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/oop.psgc.inline.hpp --- a/hotspot/src/share/vm/oops/oop.psgc.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2002, 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 SHARE_VM_OOPS_OOP_PSGC_INLINE_HPP -#define SHARE_VM_OOPS_OOP_PSGC_INLINE_HPP - -#include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS -#include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" -#include "gc_implementation/parallelScavenge/psScavenge.hpp" -#endif // INCLUDE_ALL_GCS - -// ParallelScavengeHeap methods - -inline void oopDesc::push_contents(PSPromotionManager* pm) { - Klass* k = klass(); - if (!k->oop_is_typeArray()) { - // It might contain oops beyond the header, so take the virtual call. - k->oop_push_contents(pm, this); - } - // Else skip it. The TypeArrayKlass in the header never needs scavenging. -} - -#endif // SHARE_VM_OOPS_OOP_PSGC_INLINE_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/typeArrayKlass.cpp --- a/hotspot/src/share/vm/oops/typeArrayKlass.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/oops/typeArrayKlass.cpp Thu May 07 20:51:12 2015 -0700 @@ -36,7 +36,7 @@ #include "oops/klass.inline.hpp" #include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" -#include "oops/typeArrayKlass.hpp" +#include "oops/typeArrayKlass.inline.hpp" #include "oops/typeArrayOop.hpp" #include "runtime/handles.inline.hpp" #include "runtime/orderAccess.inline.hpp" @@ -204,57 +204,6 @@ return t->object_size(); } -void TypeArrayKlass::oop_follow_contents(oop obj) { - assert(obj->is_typeArray(),"must be a type array"); - // Performance tweak: We skip iterating over the klass pointer since we - // know that Universe::TypeArrayKlass never moves. -} - -#if INCLUDE_ALL_GCS -void TypeArrayKlass::oop_follow_contents(ParCompactionManager* cm, oop obj) { - assert(obj->is_typeArray(),"must be a type array"); - // Performance tweak: We skip iterating over the klass pointer since we - // know that Universe::TypeArrayKlass never moves. -} -#endif // INCLUDE_ALL_GCS - -int TypeArrayKlass::oop_adjust_pointers(oop obj) { - assert(obj->is_typeArray(),"must be a type array"); - typeArrayOop t = typeArrayOop(obj); - // Performance tweak: We skip iterating over the klass pointer since we - // know that Universe::TypeArrayKlass never moves. - return t->object_size(); -} - -int TypeArrayKlass::oop_oop_iterate(oop obj, ExtendedOopClosure* blk) { - assert(obj->is_typeArray(),"must be a type array"); - typeArrayOop t = typeArrayOop(obj); - // Performance tweak: We skip iterating over the klass pointer since we - // know that Universe::TypeArrayKlass never moves. - return t->object_size(); -} - -int TypeArrayKlass::oop_oop_iterate_m(oop obj, ExtendedOopClosure* blk, MemRegion mr) { - assert(obj->is_typeArray(),"must be a type array"); - typeArrayOop t = typeArrayOop(obj); - // Performance tweak: We skip iterating over the klass pointer since we - // know that Universe::TypeArrayKlass never moves. - return t->object_size(); -} - -#if INCLUDE_ALL_GCS -void TypeArrayKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { - ShouldNotReachHere(); - assert(obj->is_typeArray(),"must be a type array"); -} - -int -TypeArrayKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { - assert(obj->is_typeArray(),"must be a type array"); - return typeArrayOop(obj)->object_size(); -} -#endif // INCLUDE_ALL_GCS - void TypeArrayKlass::initialize(TRAPS) { // Nothing to do. Having this function is handy since objArrayKlasses can be // initialized by calling initialize on their bottom_klass, see ObjArrayKlass::initialize diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/typeArrayKlass.hpp --- a/hotspot/src/share/vm/oops/typeArrayKlass.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/oops/typeArrayKlass.hpp Thu May 07 20:51:12 2015 -0700 @@ -72,16 +72,46 @@ // Copying void copy_array(arrayOop s, int src_pos, arrayOop d, int dst_pos, int length, TRAPS); - // Iteration - int oop_oop_iterate(oop obj, ExtendedOopClosure* blk); - int oop_oop_iterate_m(oop obj, ExtendedOopClosure* blk, MemRegion mr); + // GC specific object visitors + // + // Mark Sweep + void oop_ms_follow_contents(oop obj); + int oop_ms_adjust_pointers(oop obj); +#if INCLUDE_ALL_GCS + // Parallel Scavenge + void oop_ps_push_contents( oop obj, PSPromotionManager* pm); + // Parallel Compact + void oop_pc_follow_contents(oop obj, ParCompactionManager* cm); + void oop_pc_update_pointers(oop obj); +#endif + + // Oop iterators. Since there are no oops in TypeArrayKlasses, + // these functions only return the size of the object. + + private: + // The implementation used by all oop_oop_iterate functions in TypeArrayKlasses. + inline int oop_oop_iterate_impl(oop obj, ExtendedOopClosure* closure); - // Garbage collection - void oop_follow_contents(oop obj); - int oop_adjust_pointers(oop obj); + public: + +#define TypeArrayKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ + int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure); \ + int oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, \ + MemRegion mr); \ + int oop_oop_iterate_range##nv_suffix(oop obj, OopClosureType* closure, \ + int start, int end); - // Parallel Scavenge and Parallel Old - PARALLEL_GC_DECLS + ALL_OOP_OOP_ITERATE_CLOSURES_1(TypeArrayKlass_OOP_OOP_ITERATE_DECL) + ALL_OOP_OOP_ITERATE_CLOSURES_2(TypeArrayKlass_OOP_OOP_ITERATE_DECL) + +#if INCLUDE_ALL_GCS +#define TypeArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ + int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure); + + ALL_OOP_OOP_ITERATE_CLOSURES_1(TypeArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) + ALL_OOP_OOP_ITERATE_CLOSURES_2(TypeArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) +#endif // INCLUDE_ALL_GCS + protected: // Find n'th dimensional array diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/oops/typeArrayKlass.inline.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/oops/typeArrayKlass.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,73 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_OOPS_TYPEARRAYKLASS_INLINE_HPP +#define SHARE_VM_OOPS_TYPEARRAYKLASS_INLINE_HPP + +#include "oops/oop.inline.hpp" +#include "oops/typeArrayKlass.hpp" +#include "oops/typeArrayOop.hpp" + +class ExtendedOopClosure; + +inline int TypeArrayKlass::oop_oop_iterate_impl(oop obj, ExtendedOopClosure* closure) { + assert(obj->is_typeArray(),"must be a type array"); + typeArrayOop t = typeArrayOop(obj); + // Performance tweak: We skip iterating over the klass pointer since we + // know that Universe::TypeArrayKlass never moves. + return t->object_size(); +} + +#define TypeArrayKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + \ +int TypeArrayKlass:: \ +oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { \ + return oop_oop_iterate_impl(obj, closure); \ +} + +#if INCLUDE_ALL_GCS +#define TypeArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ + \ +int TypeArrayKlass:: \ +oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) { \ + return oop_oop_iterate_impl(obj, closure); \ +} +#else +#define TypeArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) +#endif + + +#define TypeArrayKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ + \ +int TypeArrayKlass:: \ +oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr) { \ + return oop_oop_iterate_impl(obj, closure); \ +} + +#define ALL_TYPE_ARRAY_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + TypeArrayKlass_OOP_OOP_ITERATE_DEFN( OopClosureType, nv_suffix) \ + TypeArrayKlass_OOP_OOP_ITERATE_DEFN_m( OopClosureType, nv_suffix) \ + TypeArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) + +#endif // SHARE_VM_OOPS_TYPEARRAYKLASS_INLINE_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/bytecodeInfo.cpp --- a/hotspot/src/share/vm/opto/bytecodeInfo.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/bytecodeInfo.cpp Thu May 07 20:51:12 2015 -0700 @@ -631,11 +631,11 @@ } int max_inline_level_adjust = 0; if (caller_jvms->method() != NULL) { - if (caller_jvms->method()->is_compiled_lambda_form()) + if (caller_jvms->method()->is_compiled_lambda_form()) { max_inline_level_adjust += 1; // don't count actions in MH or indy adapter frames - else if (callee_method->is_method_handle_intrinsic() || - callee_method->is_compiled_lambda_form()) { - max_inline_level_adjust += 1; // don't count method handle calls from java.lang.invoke implem + } else if (callee_method->is_method_handle_intrinsic() || + callee_method->is_compiled_lambda_form()) { + max_inline_level_adjust += 1; // don't count method handle calls from java.lang.invoke implementation } if (max_inline_level_adjust != 0 && C->print_inlining() && (Verbose || WizardMode)) { CompileTask::print_inline_indent(inline_level()); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/c2_globals.hpp --- a/hotspot/src/share/vm/opto/c2_globals.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/c2_globals.hpp Thu May 07 20:51:12 2015 -0700 @@ -324,6 +324,9 @@ develop(bool, SuperWordRTDepCheck, false, \ "Enable runtime dependency checks.") \ \ + product(bool, SuperWordReductions, true, \ + "Enable reductions support in superword.") \ + \ notproduct(bool, TraceSuperWord, false, \ "Trace superword transforms") \ \ @@ -590,9 +593,6 @@ develop(bool, PoisonOSREntry, true, \ "Detect abnormal calls to OSR code") \ \ - product(bool, UseCondCardMark, false, \ - "Check for already marked card before updating card table") \ - \ develop(bool, SoftMatchFailure, trueInProduct, \ "If the DFA fails to match a node, print a message and bail out") \ \ diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/callGenerator.cpp --- a/hotspot/src/share/vm/opto/callGenerator.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/callGenerator.cpp Thu May 07 20:51:12 2015 -0700 @@ -876,7 +876,8 @@ // Parse::do_call()) target = C->optimize_virtual_call(caller, jvms->bci(), klass, klass, target, receiver_type, is_virtual, - call_does_dispatch, vtable_index); // out-parameters + call_does_dispatch, vtable_index, // out-parameters + /*check_access=*/false); // We lack profiling at this call but type speculation may // provide us with a type speculative_receiver_type = (receiver_type != NULL) ? receiver_type->speculative_type() : NULL; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/castnode.cpp --- a/hotspot/src/share/vm/opto/castnode.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/castnode.cpp Thu May 07 20:51:12 2015 -0700 @@ -73,16 +73,6 @@ return (in(0) && remove_dead_region(phase, can_reshape)) ? this : NULL; } -//------------------------------Ideal_DU_postCCP------------------------------- -// Throw away cast after constant propagation -Node *ConstraintCastNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { - const Type *t = ccp->type(in(1)); - ccp->hash_delete(this); - set_type(t); // Turn into ID function - ccp->hash_insert(this); - return this; -} - uint CastIINode::size_of() const { return sizeof(*this); } @@ -164,13 +154,6 @@ return res; } -Node *CastIINode::Ideal_DU_postCCP(PhaseCCP *ccp) { - if (_carry_dependency) { - return NULL; - } - return ConstraintCastNode::Ideal_DU_postCCP(ccp); -} - #ifndef PRODUCT void CastIINode::dump_spec(outputStream *st) const { TypeNode::dump_spec(st); @@ -181,20 +164,6 @@ #endif //============================================================================= - -//------------------------------Ideal_DU_postCCP------------------------------- -// If not converting int->oop, throw away cast after constant propagation -Node *CastPPNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { - const Type *t = ccp->type(in(1)); - if (!t->isa_oop_ptr() || ((in(1)->is_DecodeN()) && Matcher::gen_narrow_oop_implicit_null_checks())) { - return NULL; // do not transform raw pointers or narrow oops - } - return ConstraintCastNode::Ideal_DU_postCCP(ccp); -} - - - -//============================================================================= //------------------------------Identity--------------------------------------- // If input is already higher or equal to cast type, then this is an identity. Node *CheckCastPPNode::Identity( PhaseTransform *phase ) { @@ -216,16 +185,13 @@ const Type *result = _type; if( in_type != NULL && my_type != NULL ) { TypePtr::PTR in_ptr = in_type->ptr(); - if( in_ptr == TypePtr::Null ) { + if (in_ptr == TypePtr::Null) { result = in_type; - } else if( in_ptr == TypePtr::Constant ) { - // Casting a constant oop to an interface? - // (i.e., a String to a Comparable?) - // Then return the interface. + } else if (in_ptr == TypePtr::Constant) { const TypeOopPtr *jptr = my_type->isa_oopptr(); - assert( jptr, "" ); - result = (jptr->klass()->is_interface() || !in_type->higher_equal(_type)) - ? my_type->cast_to_ptr_type( TypePtr::NotNull ) + assert(jptr, ""); + result = !in_type->higher_equal(_type) + ? my_type->cast_to_ptr_type(TypePtr::NotNull) : in_type; } else { result = my_type->cast_to_ptr_type( my_type->join_ptr(in_ptr) ); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/castnode.hpp --- a/hotspot/src/share/vm/opto/castnode.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/castnode.hpp Thu May 07 20:51:12 2015 -0700 @@ -42,7 +42,6 @@ virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); virtual int Opcode() const; virtual uint ideal_reg() const = 0; - virtual Node *Ideal_DU_postCCP( PhaseCCP * ); }; //------------------------------CastIINode------------------------------------- @@ -63,7 +62,6 @@ virtual uint ideal_reg() const { return Op_RegI; } virtual Node *Identity( PhaseTransform *phase ); virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Ideal_DU_postCCP( PhaseCCP * ); #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; #endif @@ -76,7 +74,6 @@ CastPPNode (Node *n, const Type *t ): ConstraintCastNode(n, t) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegP; } - virtual Node *Ideal_DU_postCCP( PhaseCCP * ); }; //------------------------------CheckCastPPNode-------------------------------- @@ -94,9 +91,6 @@ virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegP; } - // No longer remove CheckCast after CCP as it gives me a place to hang - // the proper address type - which is required to compute anti-deps. - //virtual Node *Ideal_DU_postCCP( PhaseCCP * ); }; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/cfgnode.cpp --- a/hotspot/src/share/vm/opto/cfgnode.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/cfgnode.cpp Thu May 07 20:51:12 2015 -0700 @@ -525,13 +525,16 @@ // Cut the backedge input and remove phis since no data paths left. // We don't cut outputs to other nodes here since we need to put them // on the worklist. + PhaseIterGVN *igvn = phase->is_IterGVN(); + if (in(1)->outcnt() == 1) { + igvn->_worklist.push(in(1)); + } del_req(1); cnt = 0; assert( req() == 1, "no more inputs expected" ); uint max = outcnt(); bool progress = true; Node *top = phase->C->top(); - PhaseIterGVN *igvn = phase->is_IterGVN(); DUIterator j; while(progress) { progress = false; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/cfgnode.hpp --- a/hotspot/src/share/vm/opto/cfgnode.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/cfgnode.hpp Thu May 07 20:51:12 2015 -0700 @@ -263,6 +263,30 @@ // Size is bigger to hold the probability field. However, _prob does not // change the semantics so it does not appear in the hash & cmp functions. virtual uint size_of() const { return sizeof(*this); } + +private: + ProjNode* range_check_trap_proj(int& flip, Node*& l, Node*& r); + ProjNode* range_check_trap_proj() { + int flip_test = 0; + Node* l = NULL; + Node* r = NULL; + return range_check_trap_proj(flip_test, l, r); + } + + // Helper methods for fold_compares + bool cmpi_folds(PhaseIterGVN* igvn); + bool is_ctrl_folds(Node* ctrl, PhaseIterGVN* igvn); + bool has_shared_region(ProjNode* proj, ProjNode*& success, ProjNode*& fail); + bool has_only_uncommon_traps(ProjNode* proj, ProjNode*& success, ProjNode*& fail, PhaseIterGVN* igvn); + static void merge_uncommon_traps(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn); + static void improve_address_types(Node* l, Node* r, ProjNode* fail, PhaseIterGVN* igvn); + bool is_cmp_with_loadrange(ProjNode* proj); + bool is_null_check(ProjNode* proj, PhaseIterGVN* igvn); + bool is_side_effect_free_test(ProjNode* proj, PhaseIterGVN* igvn); + void reroute_side_effect_free_unc(ProjNode* proj, ProjNode* dom_proj, PhaseIterGVN* igvn); + ProjNode* uncommon_trap_proj(CallStaticJavaNode*& call) const; + bool fold_compares_helper(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn); + public: // Degrees of branch prediction probability by order of magnitude: @@ -348,7 +372,7 @@ virtual const RegMask &out_RegMask() const; void dominated_by(Node* prev_dom, PhaseIterGVN* igvn); int is_range_check(Node* &range, Node* &index, jint &offset); - Node* fold_compares(PhaseGVN* phase); + Node* fold_compares(PhaseIterGVN* phase); static Node* up_one_dom(Node* curr, bool linear_only = false); // Takes the type of val and filters it through the test represented diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/chaitin.cpp --- a/hotspot/src/share/vm/opto/chaitin.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/chaitin.cpp Thu May 07 20:51:12 2015 -0700 @@ -2095,7 +2095,7 @@ // Dump a register name into a buffer. Be intelligent if we get called // before allocation is complete. char *PhaseChaitin::dump_register( const Node *n, char *buf ) const { - if( !this ) { // Not got anything? + if( this == NULL ) { // Not got anything? sprintf(buf,"N%d",n->_idx); // Then use Node index } else if( _node_regs ) { // Post allocation, use direct mappings, no LRG info available diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/classes.hpp --- a/hotspot/src/share/vm/opto/classes.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/classes.hpp Thu May 07 20:51:12 2015 -0700 @@ -266,9 +266,13 @@ macro(AddVB) macro(AddVS) macro(AddVI) +macro(AddReductionVI) macro(AddVL) +macro(AddReductionVL) macro(AddVF) +macro(AddReductionVF) macro(AddVD) +macro(AddReductionVD) macro(SubVB) macro(SubVS) macro(SubVI) @@ -277,8 +281,11 @@ macro(SubVD) macro(MulVS) macro(MulVI) +macro(MulReductionVI) macro(MulVF) +macro(MulReductionVF) macro(MulVD) +macro(MulReductionVD) macro(DivVF) macro(DivVD) macro(LShiftCntV) diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/compile.cpp --- a/hotspot/src/share/vm/opto/compile.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/compile.cpp Thu May 07 20:51:12 2015 -0700 @@ -2811,9 +2811,38 @@ break; } -#ifdef _LP64 - case Op_CastPP: - if (n->in(1)->is_DecodeN() && Matcher::gen_narrow_oop_implicit_null_checks()) { + case Op_CastPP: { + // Remove CastPP nodes to gain more freedom during scheduling but + // keep the dependency they encode as control or precedence edges + // (if control is set already) on memory operations. Some CastPP + // nodes don't have a control (don't carry a dependency): skip + // those. + if (n->in(0) != NULL) { + ResourceMark rm; + Unique_Node_List wq; + wq.push(n); + for (uint next = 0; next < wq.size(); ++next) { + Node *m = wq.at(next); + for (DUIterator_Fast imax, i = m->fast_outs(imax); i < imax; i++) { + Node* use = m->fast_out(i); + if (use->is_Mem() || use->is_EncodeNarrowPtr()) { + use->ensure_control_or_add_prec(n->in(0)); + } else if (use->in(0) == NULL) { + switch(use->Opcode()) { + case Op_AddP: + case Op_DecodeN: + case Op_DecodeNKlass: + case Op_CheckCastPP: + case Op_CastPP: + wq.push(use); + break; + } + } + } + } + } + const bool is_LP64 = LP64_ONLY(true) NOT_LP64(false); + if (is_LP64 && n->in(1)->is_DecodeN() && Matcher::gen_narrow_oop_implicit_null_checks()) { Node* in1 = n->in(1); const Type* t = n->bottom_type(); Node* new_in1 = in1->clone(); @@ -2846,9 +2875,15 @@ if (in1->outcnt() == 0) { in1->disconnect_inputs(NULL, this); } + } else { + n->subsume_by(n->in(1), this); + if (n->outcnt() == 0) { + n->disconnect_inputs(NULL, this); + } } break; - + } +#ifdef _LP64 case Op_CmpP: // Do this transformation here to preserve CmpPNode::sub() and // other TypePtr related Ideal optimizations (for example, ptr nullness). @@ -3049,6 +3084,15 @@ case Op_StoreVector: break; + case Op_AddReductionVI: + case Op_AddReductionVL: + case Op_AddReductionVF: + case Op_AddReductionVD: + case Op_MulReductionVI: + case Op_MulReductionVF: + case Op_MulReductionVD: + break; + case Op_PackB: case Op_PackS: case Op_PackI: diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/compile.hpp --- a/hotspot/src/share/vm/opto/compile.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/compile.hpp Thu May 07 20:51:12 2015 -0700 @@ -879,9 +879,11 @@ ciMethod* optimize_virtual_call(ciMethod* caller, int bci, ciInstanceKlass* klass, ciKlass* holder, ciMethod* callee, const TypeOopPtr* receiver_type, bool is_virtual, - bool &call_does_dispatch, int &vtable_index); + bool &call_does_dispatch, int &vtable_index, + bool check_access = true); ciMethod* optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* klass, - ciMethod* callee, const TypeOopPtr* receiver_type); + ciMethod* callee, const TypeOopPtr* receiver_type, + bool check_access = true); // Report if there were too many traps at a current method and bci. // Report if a trap was recorded, and/or PerMethodTrapLimit was exceeded. diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/doCall.cpp --- a/hotspot/src/share/vm/opto/doCall.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/doCall.cpp Thu May 07 20:51:12 2015 -0700 @@ -959,13 +959,15 @@ ciMethod* Compile::optimize_virtual_call(ciMethod* caller, int bci, ciInstanceKlass* klass, ciKlass* holder, ciMethod* callee, const TypeOopPtr* receiver_type, bool is_virtual, - bool& call_does_dispatch, int& vtable_index) { + bool& call_does_dispatch, int& vtable_index, + bool check_access) { // Set default values for out-parameters. call_does_dispatch = true; vtable_index = Method::invalid_vtable_index; // Choose call strategy. - ciMethod* optimized_virtual_method = optimize_inlining(caller, bci, klass, callee, receiver_type); + ciMethod* optimized_virtual_method = optimize_inlining(caller, bci, klass, callee, + receiver_type, check_access); // Have the call been sufficiently improved such that it is no longer a virtual? if (optimized_virtual_method != NULL) { @@ -980,7 +982,8 @@ // Identify possible target method and inlining style ciMethod* Compile::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* klass, - ciMethod* callee, const TypeOopPtr* receiver_type) { + ciMethod* callee, const TypeOopPtr* receiver_type, + bool check_access) { // only use for virtual or interface calls // If it is obviously final, do not bother to call find_monomorphic_target, @@ -1020,7 +1023,7 @@ } ciInstanceKlass* calling_klass = caller->holder(); - ciMethod* cha_monomorphic_target = callee->find_monomorphic_target(calling_klass, klass, actual_receiver); + ciMethod* cha_monomorphic_target = callee->find_monomorphic_target(calling_klass, klass, actual_receiver, check_access); if (cha_monomorphic_target != NULL) { assert(!cha_monomorphic_target->is_abstract(), ""); // Look at the method-receiver type. Does it add "too much information"? diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/gcm.cpp --- a/hotspot/src/share/vm/opto/gcm.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/gcm.cpp Thu May 07 20:51:12 2015 -0700 @@ -100,6 +100,9 @@ } } +static bool is_dominator(Block* d, Block* n) { + return d->dom_lca(n) == d; +} //------------------------------schedule_pinned_nodes-------------------------- // Set the basic block for Nodes pinned into blocks @@ -122,6 +125,42 @@ schedule_node_into_block(node, block); } + // If the node has precedence edges (added when CastPP nodes are + // removed in final_graph_reshaping), fix the control of the + // node to cover the precedence edges and remove the + // dependencies. + Node* n = NULL; + for (uint i = node->len()-1; i >= node->req(); i--) { + Node* m = node->in(i); + if (m == NULL) continue; + // Skip the precedence edge if the test that guarded a CastPP: + // - was optimized out during escape analysis + // (OptimizePtrCompare): the CastPP's control isn't an end of + // block. + // - is moved in the branch of a dominating If: the control of + // the CastPP is then a Region. + if (m->is_block_proj() || m->is_block_start()) { + node->rm_prec(i); + if (n == NULL) { + n = m; + } else { + Block* bn = get_block_for_node(n); + Block* bm = get_block_for_node(m); + assert(is_dominator(bn, bm) || is_dominator(bm, bn), "one must dominate the other"); + n = is_dominator(bn, bm) ? m : n; + } + } + } + if (n != NULL) { + assert(node->in(0), "control should have been set"); + Block* bn = get_block_for_node(n); + Block* bnode = get_block_for_node(node->in(0)); + assert(is_dominator(bn, bnode) || is_dominator(bnode, bn), "one must dominate the other"); + if (!is_dominator(bn, bnode)) { + node->set_req(0, n); + } + } + // process all inputs that are non NULL for (int i = node->req() - 1; i >= 0; --i) { if (node->in(i) != NULL) { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/graphKit.cpp --- a/hotspot/src/share/vm/opto/graphKit.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/graphKit.cpp Thu May 07 20:51:12 2015 -0700 @@ -2530,6 +2530,11 @@ // prior to coming here. Node* Phase::gen_subtype_check(Node* subklass, Node* superklass, Node** ctrl, MergeMemNode* mem, PhaseGVN* gvn) { Compile* C = gvn->C; + + if ((*ctrl)->is_top()) { + return C->top(); + } + // Fast check for identical types, perhaps identical constants. // The types can even be identical non-constants, in cases // involving Array.newInstance, Object.clone, etc. @@ -2792,18 +2797,19 @@ */ Node* GraphKit::maybe_cast_profiled_obj(Node* obj, ciKlass* type, - bool not_null, - SafePointNode* sfpt) { + bool not_null) { + if (stopped()) { + return obj; + } + // type == NULL if profiling tells us this object is always null if (type != NULL) { Deoptimization::DeoptReason class_reason = Deoptimization::Reason_speculate_class_check; Deoptimization::DeoptReason null_reason = Deoptimization::Reason_speculate_null_check; - ciMethod* trap_method = (sfpt == NULL) ? method() : sfpt->jvms()->method(); - int trap_bci = (sfpt == NULL) ? bci() : sfpt->jvms()->bci(); if (!too_many_traps(null_reason) && !too_many_recompiles(null_reason) && - !C->too_many_traps(trap_method, trap_bci, class_reason) && - !C->too_many_recompiles(trap_method, trap_bci, class_reason)) { + !too_many_traps(class_reason) && + !too_many_recompiles(class_reason)) { Node* not_null_obj = NULL; // not_null is true if we know the object is not null and // there's no need for a null check @@ -2819,12 +2825,7 @@ ciKlass* exact_kls = type; Node* slow_ctl = type_check_receiver(exact_obj, exact_kls, 1.0, &exact_obj); - if (sfpt != NULL) { - GraphKit kit(sfpt->jvms()); - PreserveJVMState pjvms(&kit); - kit.set_control(slow_ctl); - kit.uncommon_trap_exact(class_reason, Deoptimization::Action_maybe_recompile); - } else { + { PreserveJVMState pjvms(this); set_control(slow_ctl); uncommon_trap_exact(class_reason, Deoptimization::Action_maybe_recompile); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/graphKit.hpp --- a/hotspot/src/share/vm/opto/graphKit.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/graphKit.hpp Thu May 07 20:51:12 2015 -0700 @@ -409,8 +409,7 @@ // Cast obj to type and emit guard unless we had too many traps here already Node* maybe_cast_profiled_obj(Node* obj, ciKlass* type, - bool not_null = false, - SafePointNode* sfpt = NULL); + bool not_null = false); // Cast obj to not-null on this path Node* cast_not_null(Node* obj, bool do_replace_in_map = true); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/ifnode.cpp --- a/hotspot/src/share/vm/opto/ifnode.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/ifnode.cpp Thu May 07 20:51:12 2015 -0700 @@ -25,11 +25,13 @@ #include "precompiled.hpp" #include "memory/allocation.inline.hpp" #include "opto/addnode.hpp" +#include "opto/castnode.hpp" #include "opto/cfgnode.hpp" #include "opto/connode.hpp" #include "opto/loopnode.hpp" #include "opto/phaseX.hpp" #include "opto/runtime.hpp" +#include "opto/rootnode.hpp" #include "opto/subnode.hpp" // Portions of code courtesy of Clifford Click @@ -232,16 +234,24 @@ // Make a region merging constants and a region merging the rest uint req_c = 0; Node* predicate_proj = NULL; + int nb_predicate_proj = 0; for (uint ii = 1; ii < r->req(); ii++) { if (phi->in(ii) == con1) { req_c++; } Node* proj = PhaseIdealLoop::find_predicate(r->in(ii)); if (proj != NULL) { - assert(predicate_proj == NULL, "only one predicate entry expected"); + nb_predicate_proj++; predicate_proj = proj; } } + if (nb_predicate_proj > 1) { + // Can happen in case of loop unswitching and when the loop is + // optimized out: it's not a loop anymore so we don't care about + // predicates. + assert(!r->is_Loop(), "this must not be a loop anymore"); + predicate_proj = NULL; + } Node* predicate_c = NULL; Node* predicate_x = NULL; bool counted_loop = r->is_CountedLoop(); @@ -449,62 +459,59 @@ return new ConINode(TypeInt::ZERO); } -//------------------------------is_range_check--------------------------------- -// Return 0 if not a range check. Return 1 if a range check and set index and -// offset. Return 2 if we had to negate the test. Index is NULL if the check -// is versus a constant. -int IfNode::is_range_check(Node* &range, Node* &index, jint &offset) { +// if this IfNode follows a range check pattern return the projection +// for the failed path +ProjNode* IfNode::range_check_trap_proj(int& flip_test, Node*& l, Node*& r) { Node* b = in(1); - if (b == NULL || !b->is_Bool()) return 0; + if (b == NULL || !b->is_Bool()) return NULL; BoolNode* bn = b->as_Bool(); Node* cmp = bn->in(1); - if (cmp == NULL) return 0; - if (cmp->Opcode() != Op_CmpU) return 0; + if (cmp == NULL) return NULL; + if (cmp->Opcode() != Op_CmpU) return NULL; - Node* l = cmp->in(1); - Node* r = cmp->in(2); - int flip_test = 1; + l = cmp->in(1); + r = cmp->in(2); + flip_test = 1; if (bn->_test._test == BoolTest::le) { l = cmp->in(2); r = cmp->in(1); flip_test = 2; } else if (bn->_test._test != BoolTest::lt) { - return 0; + return NULL; } - if (l->is_top()) return 0; // Top input means dead test - if (r->Opcode() != Op_LoadRange) return 0; + if (l->is_top()) return NULL; // Top input means dead test + if (r->Opcode() != Op_LoadRange) return NULL; // We have recognized one of these forms: // Flip 1: If (Bool[<] CmpU(l, LoadRange)) ... // Flip 2: If (Bool[<=] CmpU(LoadRange, l)) ... + ProjNode* iftrap = proj_out(flip_test == 2 ? true : false); + return iftrap; +} + + +//------------------------------is_range_check--------------------------------- +// Return 0 if not a range check. Return 1 if a range check and set index and +// offset. Return 2 if we had to negate the test. Index is NULL if the check +// is versus a constant. +int IfNode::is_range_check(Node* &range, Node* &index, jint &offset) { + int flip_test = 0; + Node* l = NULL; + Node* r = NULL; + ProjNode* iftrap = range_check_trap_proj(flip_test, l, r); + + if (iftrap == NULL) { + return 0; + } + // Make sure it's a real range check by requiring an uncommon trap // along the OOB path. Otherwise, it's possible that the user wrote // something which optimized to look like a range check but behaves // in some other way. - Node* iftrap = proj_out(flip_test == 2 ? true : false); - bool found_trap = false; - if (iftrap != NULL) { - Node* u = iftrap->unique_ctrl_out(); - if (u != NULL) { - // It could be a merge point (Region) for uncommon trap. - if (u->is_Region()) { - Node* c = u->unique_ctrl_out(); - if (c != NULL) { - iftrap = u; - u = c; - } - } - if (u->in(0) == iftrap && u->is_CallStaticJava()) { - int req = u->as_CallStaticJava()->uncommon_trap_request(); - if (Deoptimization::trap_request_reason(req) == - Deoptimization::Reason_range_check) { - found_trap = true; - } - } - } + if (iftrap->is_uncommon_trap_proj(Deoptimization::Reason_range_check) == NULL) { + return 0; } - if (!found_trap) return 0; // sorry, no cigar // Look for index+offset form Node* ind = l; @@ -664,11 +671,12 @@ //------------------------------fold_compares---------------------------- // See if a pair of CmpIs can be converted into a CmpU. In some cases // the direction of this if is determined by the preceding if so it -// can be eliminate entirely. Given an if testing (CmpI n c) check -// for an immediately control dependent if that is testing (CmpI n c2) -// and has one projection leading to this if and the other projection -// leading to a region that merges one of this ifs control -// projections. +// can be eliminate entirely. +// +// Given an if testing (CmpI n v) check for an immediately control +// dependent if that is testing (CmpI n v2) and has one projection +// leading to this if and the other projection leading to a region +// that merges one of this ifs control projections. // // If // / | @@ -680,79 +688,458 @@ // / \ | // / Region // -Node* IfNode::fold_compares(PhaseGVN* phase) { - if (Opcode() != Op_If) return NULL; +// Or given an if testing (CmpI n v) check for a dominating if that is +// testing (CmpI n v2), both having one projection leading to an +// uncommon trap. Allow Another independent guard in between to cover +// an explicit range check: +// if (index < 0 || index >= array.length) { +// which may need a null check to guard the LoadRange +// +// If +// / \ +// / \ +// / \ +// If unc +// /\ +// / \ +// / \ +// / unc +// + +// Is the comparison for this If suitable for folding? +bool IfNode::cmpi_folds(PhaseIterGVN* igvn) { + return in(1) != NULL && + in(1)->is_Bool() && + in(1)->in(1) != NULL && + in(1)->in(1)->Opcode() == Op_CmpI && + in(1)->in(1)->in(2) != NULL && + in(1)->in(1)->in(2) != igvn->C->top() && + (in(1)->as_Bool()->_test.is_less() || + in(1)->as_Bool()->_test.is_greater()); +} + +// Is a dominating control suitable for folding with this if? +bool IfNode::is_ctrl_folds(Node* ctrl, PhaseIterGVN* igvn) { + return ctrl != NULL && + ctrl->is_Proj() && + ctrl->in(0) != NULL && + ctrl->in(0)->is_If() && + ctrl->in(0)->outcnt() == 2 && + ctrl->in(0)->as_If()->cmpi_folds(igvn) && + // Must compare same value + ctrl->in(0)->in(1)->in(1)->in(1) != NULL && + ctrl->in(0)->in(1)->in(1)->in(1) == in(1)->in(1)->in(1); +} + +// Do this If and the dominating If share a region? +bool IfNode::has_shared_region(ProjNode* proj, ProjNode*& success, ProjNode*& fail) { + ProjNode* otherproj = proj->other_if_proj(); + Node* otherproj_ctrl_use = otherproj->unique_ctrl_out(); + RegionNode* region = (otherproj_ctrl_use != NULL && otherproj_ctrl_use->is_Region()) ? otherproj_ctrl_use->as_Region() : NULL; + success = NULL; + fail = NULL; + if (otherproj->outcnt() == 1 && region != NULL && !region->has_phi()) { + for (int i = 0; i < 2; i++) { + ProjNode* proj = proj_out(i); + if (success == NULL && proj->outcnt() == 1 && proj->unique_out() == region) { + success = proj; + } else if (fail == NULL) { + fail = proj; + } else { + success = fail = NULL; + } + } + } + return success != NULL && fail != NULL; +} + +// Return projection that leads to an uncommon trap if any +ProjNode* IfNode::uncommon_trap_proj(CallStaticJavaNode*& call) const { + for (int i = 0; i < 2; i++) { + call = proj_out(i)->is_uncommon_trap_proj(Deoptimization::Reason_none); + if (call != NULL) { + return proj_out(i); + } + } + return NULL; +} + +// Do this If and the dominating If both branch out to an uncommon trap +bool IfNode::has_only_uncommon_traps(ProjNode* proj, ProjNode*& success, ProjNode*& fail, PhaseIterGVN* igvn) { + ProjNode* otherproj = proj->other_if_proj(); + CallStaticJavaNode* dom_unc = otherproj->is_uncommon_trap_proj(Deoptimization::Reason_none); + + if (otherproj->outcnt() == 1 && dom_unc != NULL) { + CallStaticJavaNode* unc = NULL; + ProjNode* unc_proj = uncommon_trap_proj(unc); + if (unc_proj != NULL && unc_proj->outcnt() == 1) { + if (dom_unc == unc) { + // Allow the uncommon trap to be shared through a region + RegionNode* r = unc->in(0)->as_Region(); + if (r->outcnt() != 2 || r->req() != 3 || r->find_edge(otherproj) == -1 || r->find_edge(unc_proj) == -1) { + return false; + } + assert(r->has_phi() == NULL, "simple region shouldn't have a phi"); + } else if (dom_unc->in(0) != otherproj || unc->in(0) != unc_proj) { + return false; + } + // See merge_uncommon_traps: the reason of the uncommon trap + // will be changed and the state of the dominating If will be + // used. Checked that we didn't apply this transformation in a + // previous compilation and it didn't cause too many traps + if (!igvn->C->too_many_traps(dom_unc->jvms()->method(), dom_unc->jvms()->bci(), Deoptimization::Reason_unstable_fused_if) && + !igvn->C->too_many_traps(dom_unc->jvms()->method(), dom_unc->jvms()->bci(), Deoptimization::Reason_range_check)) { + success = unc_proj; + fail = unc_proj->other_if_proj(); + return true; + } + } + } + return false; +} + +// Check that the 2 CmpI can be folded into as single CmpU and proceed with the folding +bool IfNode::fold_compares_helper(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn) { Node* this_cmp = in(1)->in(1); - if (this_cmp != NULL && this_cmp->Opcode() == Op_CmpI && - this_cmp->in(2)->is_Con() && this_cmp->in(2) != phase->C->top()) { - Node* ctrl = in(0); - BoolNode* this_bool = in(1)->as_Bool(); - Node* n = this_cmp->in(1); - int hi = this_cmp->in(2)->get_int(); - if (ctrl != NULL && ctrl->is_Proj() && ctrl->outcnt() == 1 && - ctrl->in(0)->is_If() && - ctrl->in(0)->outcnt() == 2 && - ctrl->in(0)->in(1)->is_Bool() && - ctrl->in(0)->in(1)->in(1)->Opcode() == Op_CmpI && - ctrl->in(0)->in(1)->in(1)->in(2)->is_Con() && - ctrl->in(0)->in(1)->in(1)->in(2) != phase->C->top() && - ctrl->in(0)->in(1)->in(1)->in(1) == n) { - IfNode* dom_iff = ctrl->in(0)->as_If(); - Node* otherproj = dom_iff->proj_out(!ctrl->as_Proj()->_con); - if (otherproj->outcnt() == 1 && otherproj->unique_out()->is_Region() && - this_bool->_test._test != BoolTest::ne && this_bool->_test._test != BoolTest::eq) { - // Identify which proj goes to the region and which continues on - RegionNode* region = otherproj->unique_out()->as_Region(); - Node* success = NULL; - Node* fail = NULL; - for (int i = 0; i < 2; i++) { - Node* proj = proj_out(i); - if (success == NULL && proj->outcnt() == 1 && proj->unique_out() == region) { - success = proj; - } else if (fail == NULL) { - fail = proj; - } else { - success = fail = NULL; + BoolNode* this_bool = in(1)->as_Bool(); + IfNode* dom_iff = proj->in(0)->as_If(); + BoolNode* dom_bool = dom_iff->in(1)->as_Bool(); + Node* lo = dom_iff->in(1)->in(1)->in(2); + Node* hi = this_cmp->in(2); + Node* n = this_cmp->in(1); + ProjNode* otherproj = proj->other_if_proj(); + + const TypeInt* lo_type = IfNode::filtered_int_type(igvn, n, otherproj); + const TypeInt* hi_type = IfNode::filtered_int_type(igvn, n, success); + + BoolTest::mask lo_test = dom_bool->_test._test; + BoolTest::mask hi_test = this_bool->_test._test; + BoolTest::mask cond = hi_test; + + // Figure out which of the two tests sets the upper bound and which + // sets the lower bound if any. + if (hi_type->_lo > lo_type->_hi && hi_type->_hi == max_jint && lo_type->_lo == min_jint) { + + assert((dom_bool->_test.is_less() && !proj->_con) || + (dom_bool->_test.is_greater() && proj->_con), "incorrect test"); + // this test was canonicalized + assert(this_bool->_test.is_less() && fail->_con, "incorrect test"); + + if (lo_test == BoolTest::gt || lo_test == BoolTest::le) { + lo = igvn->transform(new AddINode(lo, igvn->intcon(1))); + } + } else if (lo_type->_lo > hi_type->_hi && lo_type->_hi == max_jint && hi_type->_lo == min_jint) { + swap(lo, hi); + swap(lo_type, hi_type); + swap(lo_test, hi_test); + + assert((this_bool->_test.is_less() && proj->_con) || + (this_bool->_test.is_greater() && !proj->_con), "incorrect test"); + // this test was canonicalized + assert(dom_bool->_test.is_less() && !fail->_con, "incorrect test"); + + cond = (hi_test == BoolTest::le || hi_test == BoolTest::gt) ? BoolTest::gt : BoolTest::ge; + + if (lo_test == BoolTest::le) { + lo = igvn->transform(new AddINode(lo, igvn->intcon(1))); + } + + } else { + const TypeInt* failtype = filtered_int_type(igvn, n, proj); + if (failtype != NULL) { + const TypeInt* type2 = filtered_int_type(igvn, n, fail); + if (type2 != NULL) { + failtype = failtype->join(type2)->is_int(); + if (failtype->_lo > failtype->_hi) { + // previous if determines the result of this if so + // replace Bool with constant + igvn->hash_delete(this); + set_req(1, igvn->intcon(success->_con)); + return true; + } + } + } + + lo = NULL; + hi = NULL; + } + + if (lo && hi) { + // Merge the two compares into a single unsigned compare by building (CmpU (n - lo) (hi - lo)) + Node* adjusted_val = igvn->transform(new SubINode(n, lo)); + Node* adjusted_lim = igvn->transform(new SubINode(hi, lo)); + Node* newcmp = igvn->transform(new CmpUNode(adjusted_val, adjusted_lim)); + Node* newbool = igvn->transform(new BoolNode(newcmp, cond)); + + igvn->is_IterGVN()->replace_input_of(dom_iff, 1, igvn->intcon(proj->_con)); + igvn->hash_delete(this); + set_req(1, newbool); + + return true; + } + return false; +} + +// Merge the branches that trap for this If and the dominating If into +// a single region that branches to the uncommon trap for the +// dominating If +void IfNode::merge_uncommon_traps(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn) { + ProjNode* otherproj = proj->other_if_proj(); + + CallStaticJavaNode* unc = success->is_uncommon_trap_proj(Deoptimization::Reason_none); + CallStaticJavaNode* dom_unc = otherproj->is_uncommon_trap_proj(Deoptimization::Reason_none); + + if (unc != dom_unc) { + Node* r = new RegionNode(3); + + r->set_req(1, otherproj); + r->set_req(2, success); + r = igvn->transform(r); + assert(r->is_Region(), "can't go away"); + + // Make both If trap at the state of the first If: once the CmpI + // nodes are merged, if we trap we don't know which of the CmpI + // nodes would have caused the trap so we have to restart + // execution at the first one + igvn->replace_input_of(dom_unc, 0, r); + igvn->replace_input_of(unc, 0, igvn->C->top()); + } + int trap_request = dom_unc->uncommon_trap_request(); + Deoptimization::DeoptReason reason = Deoptimization::trap_request_reason(trap_request); + Deoptimization::DeoptAction action = Deoptimization::trap_request_action(trap_request); + + int flip_test = 0; + Node* l = NULL; + Node* r = NULL; + + if (success->in(0)->as_If()->range_check_trap_proj(flip_test, l, r) != NULL) { + // If this looks like a range check, change the trap to + // Reason_range_check so the compiler recognizes it as a range + // check and applies the corresponding optimizations + trap_request = Deoptimization::make_trap_request(Deoptimization::Reason_range_check, action); + + improve_address_types(l, r, fail, igvn); + } else if (unc != dom_unc) { + // If we trap we won't know what CmpI would have caused the trap + // so use a special trap reason to mark this pair of CmpI nodes as + // bad candidate for folding. On recompilation we won't fold them + // and we may trap again but this time we'll know what branch + // traps + trap_request = Deoptimization::make_trap_request(Deoptimization::Reason_unstable_fused_if, action); + } + igvn->replace_input_of(dom_unc, TypeFunc::Parms, igvn->intcon(trap_request)); +} + +// If we are turning 2 CmpI nodes into a CmpU that follows the pattern +// of a rangecheck on index i, on 64 bit the compares may be followed +// by memory accesses using i as index. In that case, the CmpU tells +// us something about the values taken by i that can help the compiler +// (see Compile::conv_I2X_index()) +void IfNode::improve_address_types(Node* l, Node* r, ProjNode* fail, PhaseIterGVN* igvn) { +#ifdef _LP64 + ResourceMark rm; + Node_Stack stack(2); + + assert(r->Opcode() == Op_LoadRange, "unexpected range check"); + const TypeInt* array_size = igvn->type(r)->is_int(); + + stack.push(l, 0); + + while(stack.size() > 0) { + Node* n = stack.node(); + uint start = stack.index(); + + uint i = start; + for (; i < n->outcnt(); i++) { + Node* use = n->raw_out(i); + if (stack.size() == 1) { + if (use->Opcode() == Op_ConvI2L) { + const TypeLong* bounds = use->as_Type()->type()->is_long(); + if (bounds->_lo <= array_size->_lo && bounds->_hi >= array_size->_hi && + (bounds->_lo != array_size->_lo || bounds->_hi != array_size->_hi)) { + stack.set_index(i+1); + stack.push(use, 0); + break; } } - if (success != NULL && fail != NULL && !region->has_phi()) { - int lo = dom_iff->in(1)->in(1)->in(2)->get_int(); - BoolNode* dom_bool = dom_iff->in(1)->as_Bool(); - Node* dom_cmp = dom_bool->in(1); - const TypeInt* failtype = filtered_int_type(phase, n, ctrl); - if (failtype != NULL) { - const TypeInt* type2 = filtered_int_type(phase, n, fail); - if (type2 != NULL) { - failtype = failtype->join(type2)->is_int(); - } else { - failtype = NULL; - } - } + } else if (use->is_Mem()) { + Node* ctrl = use->in(0); + for (int i = 0; i < 10 && ctrl != NULL && ctrl != fail; i++) { + ctrl = up_one_dom(ctrl); + } + if (ctrl == fail) { + Node* init_n = stack.node_at(1); + assert(init_n->Opcode() == Op_ConvI2L, "unexpected first node"); + Node* new_n = igvn->C->conv_I2X_index(igvn, l, array_size); - if (failtype != NULL && - dom_bool->_test._test != BoolTest::ne && dom_bool->_test._test != BoolTest::eq) { - int bound = failtype->_hi - failtype->_lo + 1; - if (failtype->_hi != max_jint && failtype->_lo != min_jint && bound > 1) { - // Merge the two compares into a single unsigned compare by building (CmpU (n - lo) hi) - BoolTest::mask cond = fail->as_Proj()->_con ? BoolTest::lt : BoolTest::ge; - Node* adjusted = phase->transform(new SubINode(n, phase->intcon(failtype->_lo))); - Node* newcmp = phase->transform(new CmpUNode(adjusted, phase->intcon(bound))); - Node* newbool = phase->transform(new BoolNode(newcmp, cond)); - phase->is_IterGVN()->replace_input_of(dom_iff, 1, phase->intcon(ctrl->as_Proj()->_con)); - phase->hash_delete(this); - set_req(1, newbool); - return this; - } - if (failtype->_lo > failtype->_hi) { - // previous if determines the result of this if so - // replace Bool with constant - phase->hash_delete(this); - set_req(1, phase->intcon(success->as_Proj()->_con)); - return this; - } + for (uint j = 2; j < stack.size(); j++) { + Node* n = stack.node_at(j); + Node* clone = n->clone(); + int rep = clone->replace_edge(init_n, new_n); + assert(rep > 0, "can't find expected node?"); + clone = igvn->transform(clone); + init_n = n; + new_n = clone; + } + igvn->hash_delete(use); + int rep = use->replace_edge(init_n, new_n); + assert(rep > 0, "can't find expected node?"); + igvn->transform(use); + if (init_n->outcnt() == 0) { + igvn->_worklist.push(init_n); } } + } else if (use->in(0) == NULL && (igvn->type(use)->isa_long() || + igvn->type(use)->isa_ptr())) { + stack.set_index(i+1); + stack.push(use, 0); + break; + } + } + if (i == n->outcnt()) { + stack.pop(); + } + } +#endif +} + +bool IfNode::is_cmp_with_loadrange(ProjNode* proj) { + if (in(1) != NULL && + in(1)->in(1) != NULL && + in(1)->in(1)->in(2) != NULL) { + Node* other = in(1)->in(1)->in(2); + if (other->Opcode() == Op_LoadRange && + ((other->in(0) != NULL && other->in(0) == proj) || + (other->in(0) == NULL && + other->in(2) != NULL && + other->in(2)->is_AddP() && + other->in(2)->in(1) != NULL && + other->in(2)->in(1)->Opcode() == Op_CastPP && + other->in(2)->in(1)->in(0) == proj))) { + return true; + } + } + return false; +} + +bool IfNode::is_null_check(ProjNode* proj, PhaseIterGVN* igvn) { + Node* other = in(1)->in(1)->in(2); + if (other->in(MemNode::Address) != NULL && + proj->in(0)->in(1) != NULL && + proj->in(0)->in(1)->is_Bool() && + proj->in(0)->in(1)->in(1) != NULL && + proj->in(0)->in(1)->in(1)->Opcode() == Op_CmpP && + proj->in(0)->in(1)->in(1)->in(2) != NULL && + proj->in(0)->in(1)->in(1)->in(1) == other->in(MemNode::Address)->in(AddPNode::Address)->uncast() && + igvn->type(proj->in(0)->in(1)->in(1)->in(2)) == TypePtr::NULL_PTR) { + return true; + } + return false; +} + +// Check that the If that is in between the 2 integer comparisons has +// no side effect +bool IfNode::is_side_effect_free_test(ProjNode* proj, PhaseIterGVN* igvn) { + if (proj != NULL && + proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none) && + proj->outcnt() <= 2) { + if (proj->outcnt() == 1 || + // Allow simple null check from LoadRange + (is_cmp_with_loadrange(proj) && is_null_check(proj, igvn))) { + CallStaticJavaNode* unc = proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); + CallStaticJavaNode* dom_unc = proj->in(0)->in(0)->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); + + // reroute_side_effect_free_unc changes the state of this + // uncommon trap to restart execution at the previous + // CmpI. Check that this change in a previous compilation didn't + // cause too many traps. + int trap_request = unc->uncommon_trap_request(); + Deoptimization::DeoptReason reason = Deoptimization::trap_request_reason(trap_request); + + if (igvn->C->too_many_traps(dom_unc->jvms()->method(), dom_unc->jvms()->bci(), reason)) { + return false; + } + + return true; + } + } + return false; +} + +// Make the If between the 2 integer comparisons trap at the state of +// the first If: the last CmpI is the one replaced by a CmpU and the +// first CmpI is eliminated, so the test between the 2 CmpI nodes +// won't be guarded by the first CmpI anymore. It can trap in cases +// where the first CmpI would have prevented it from executing: on a +// trap, we need to restart execution at the state of the first CmpI +void IfNode::reroute_side_effect_free_unc(ProjNode* proj, ProjNode* dom_proj, PhaseIterGVN* igvn) { + CallStaticJavaNode* dom_unc = dom_proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); + ProjNode* otherproj = proj->other_if_proj(); + CallStaticJavaNode* unc = proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); + Node* call_proj = dom_unc->unique_ctrl_out(); + Node* halt = call_proj->unique_ctrl_out(); + + Node* new_unc = dom_unc->clone(); + call_proj = call_proj->clone(); + halt = halt->clone(); + Node* c = otherproj->clone(); + + c = igvn->transform(c); + new_unc->set_req(TypeFunc::Parms, unc->in(TypeFunc::Parms)); + new_unc->set_req(0, c); + new_unc = igvn->transform(new_unc); + call_proj->set_req(0, new_unc); + call_proj = igvn->transform(call_proj); + halt->set_req(0, call_proj); + halt = igvn->transform(halt); + + igvn->replace_node(otherproj, igvn->C->top()); + igvn->C->root()->add_req(halt); +} + +Node* IfNode::fold_compares(PhaseIterGVN* igvn) { + if (Opcode() != Op_If) return NULL; + + if (cmpi_folds(igvn)) { + Node* ctrl = in(0); + if (is_ctrl_folds(ctrl, igvn) && + ctrl->outcnt() == 1) { + // A integer comparison immediately dominated by another integer + // comparison + ProjNode* success = NULL; + ProjNode* fail = NULL; + ProjNode* dom_cmp = ctrl->as_Proj(); + if (has_shared_region(dom_cmp, success, fail) && + // Next call modifies graph so must be last + fold_compares_helper(dom_cmp, success, fail, igvn)) { + return this; + } + if (has_only_uncommon_traps(dom_cmp, success, fail, igvn) && + // Next call modifies graph so must be last + fold_compares_helper(dom_cmp, success, fail, igvn)) { + merge_uncommon_traps(dom_cmp, success, fail, igvn); + return this; + } + return NULL; + } else if (ctrl->in(0) != NULL && + ctrl->in(0)->in(0) != NULL) { + ProjNode* success = NULL; + ProjNode* fail = NULL; + Node* dom = ctrl->in(0)->in(0); + ProjNode* dom_cmp = dom->isa_Proj(); + ProjNode* other_cmp = ctrl->isa_Proj(); + + // Check if it's an integer comparison dominated by another + // integer comparison with another test in between + if (is_ctrl_folds(dom, igvn) && + has_only_uncommon_traps(dom_cmp, success, fail, igvn) && + is_side_effect_free_test(other_cmp, igvn) && + // Next call modifies graph so must be last + fold_compares_helper(dom_cmp, success, fail, igvn)) { + reroute_side_effect_free_unc(other_cmp, dom_cmp, igvn); + merge_uncommon_traps(dom_cmp, success, fail, igvn); + return this; } } } @@ -1029,7 +1416,7 @@ // Normal equivalent-test check. if( !dom ) return NULL; // Dead loop? - Node* result = fold_compares(phase); + Node* result = fold_compares(igvn); if (result != NULL) { return result; } @@ -1089,7 +1476,7 @@ // be skipped. For example, range check predicate has two checks // for lower and upper bounds. ProjNode* unc_proj = proj_out(1 - prev_dom->as_Proj()->_con)->as_Proj(); - if (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate)) + if (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate) != NULL) prev_dom = idom; // Now walk the current IfNode's projections. diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/library_call.cpp --- a/hotspot/src/share/vm/opto/library_call.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/library_call.cpp Thu May 07 20:51:12 2015 -0700 @@ -262,6 +262,9 @@ bool inline_arraycopy(); AllocateArrayNode* tightly_coupled_allocation(Node* ptr, RegionNode* slow_region); + JVMState* arraycopy_restore_alloc_state(AllocateArrayNode* alloc, int& saved_reexecute_sp); + void arraycopy_move_allocation_here(AllocateArrayNode* alloc, Node* dest, JVMState* saved_jvms, int saved_reexecute_sp); + typedef enum { LS_xadd, LS_xchg, LS_cmpxchg } LoadStoreKind; bool inline_unsafe_load_store(BasicType type, LoadStoreKind kind); bool inline_unsafe_ordered_store(BasicType type); @@ -290,6 +293,7 @@ bool inline_multiplyToLen(); bool inline_profileBoolean(); + bool inline_isCompileConstant(); }; @@ -549,6 +553,17 @@ if (!Matcher::match_rule_supported(Op_OverflowMulL) || !UseMathExactIntrinsics) return NULL; break; + case vmIntrinsics::_getShortUnaligned: + case vmIntrinsics::_getCharUnaligned: + case vmIntrinsics::_getIntUnaligned: + case vmIntrinsics::_getLongUnaligned: + case vmIntrinsics::_putShortUnaligned: + case vmIntrinsics::_putCharUnaligned: + case vmIntrinsics::_putIntUnaligned: + case vmIntrinsics::_putLongUnaligned: + if (!UseUnalignedAccesses) return NULL; + break; + default: assert(id <= vmIntrinsics::LAST_COMPILER_INLINE, "caller responsibility"); assert(id != vmIntrinsics::_Object_init && id != vmIntrinsics::_invoke, "enum out of order?"); @@ -799,6 +814,16 @@ case vmIntrinsics::_putFloatVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, is_volatile); case vmIntrinsics::_putDoubleVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, is_volatile); + case vmIntrinsics::_getShortUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, !is_volatile); + case vmIntrinsics::_getCharUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, !is_volatile); + case vmIntrinsics::_getIntUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, !is_volatile); + case vmIntrinsics::_getLongUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, !is_volatile); + + case vmIntrinsics::_putShortUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, !is_volatile); + case vmIntrinsics::_putCharUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, !is_volatile); + case vmIntrinsics::_putIntUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, !is_volatile); + case vmIntrinsics::_putLongUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, !is_volatile); + case vmIntrinsics::_compareAndSwapObject: return inline_unsafe_load_store(T_OBJECT, LS_cmpxchg); case vmIntrinsics::_compareAndSwapInt: return inline_unsafe_load_store(T_INT, LS_cmpxchg); case vmIntrinsics::_compareAndSwapLong: return inline_unsafe_load_store(T_LONG, LS_cmpxchg); @@ -900,6 +925,8 @@ case vmIntrinsics::_profileBoolean: return inline_profileBoolean(); + case vmIntrinsics::_isCompileConstant: + return inline_isCompileConstant(); default: // If you get here, it may be that someone has added a new intrinsic @@ -3664,6 +3691,11 @@ //---------------------generate_array_guard_common------------------------ Node* LibraryCallKit::generate_array_guard_common(Node* kls, RegionNode* region, bool obj_array, bool not_array) { + + if (stopped()) { + return NULL; + } + // If obj_array/non_array==false/false: // Branch around if the given klass is in fact an array (either obj or prim). // If obj_array/non_array==false/true: @@ -3911,21 +3943,23 @@ validated = true; } - newcopy = new_array(klass_node, length, 0); // no arguments to push - - ArrayCopyNode* ac = ArrayCopyNode::make(this, true, original, start, newcopy, intcon(0), moved, true, - load_object_klass(original), klass_node); - if (!is_copyOfRange) { - ac->set_copyof(validated); - } else { - ac->set_copyofrange(validated); - } - Node* n = _gvn.transform(ac); - if (n == ac) { - ac->connect_outputs(this); - } else { - assert(validated, "shouldn't transform if all arguments not validated"); - set_all_memory(n); + if (!stopped()) { + newcopy = new_array(klass_node, length, 0); // no arguments to push + + ArrayCopyNode* ac = ArrayCopyNode::make(this, true, original, start, newcopy, intcon(0), moved, true, + load_object_klass(original), klass_node); + if (!is_copyOfRange) { + ac->set_copyof(validated); + } else { + ac->set_copyofrange(validated); + } + Node* n = _gvn.transform(ac); + if (n == ac) { + ac->connect_outputs(this); + } else { + assert(validated, "shouldn't transform if all arguments not validated"); + set_all_memory(n); + } } } } // original reexecute is set back here @@ -4674,6 +4708,141 @@ return true; } +// If we have a tighly coupled allocation, the arraycopy may take care +// of the array initialization. If one of the guards we insert between +// the allocation and the arraycopy causes a deoptimization, an +// unitialized array will escape the compiled method. To prevent that +// we set the JVM state for uncommon traps between the allocation and +// the arraycopy to the state before the allocation so, in case of +// deoptimization, we'll reexecute the allocation and the +// initialization. +JVMState* LibraryCallKit::arraycopy_restore_alloc_state(AllocateArrayNode* alloc, int& saved_reexecute_sp) { + if (alloc != NULL) { + ciMethod* trap_method = alloc->jvms()->method(); + int trap_bci = alloc->jvms()->bci(); + + if (!C->too_many_traps(trap_method, trap_bci, Deoptimization::Reason_intrinsic) & + !C->too_many_traps(trap_method, trap_bci, Deoptimization::Reason_null_check)) { + // Make sure there's no store between the allocation and the + // arraycopy otherwise visible side effects could be rexecuted + // in case of deoptimization and cause incorrect execution. + bool no_interfering_store = true; + Node* mem = alloc->in(TypeFunc::Memory); + if (mem->is_MergeMem()) { + for (MergeMemStream mms(merged_memory(), mem->as_MergeMem()); mms.next_non_empty2(); ) { + Node* n = mms.memory(); + if (n != mms.memory2() && !(n->is_Proj() && n->in(0) == alloc->initialization())) { + assert(n->is_Store(), "what else?"); + no_interfering_store = false; + break; + } + } + } else { + for (MergeMemStream mms(merged_memory()); mms.next_non_empty(); ) { + Node* n = mms.memory(); + if (n != mem && !(n->is_Proj() && n->in(0) == alloc->initialization())) { + assert(n->is_Store(), "what else?"); + no_interfering_store = false; + break; + } + } + } + + if (no_interfering_store) { + JVMState* old_jvms = alloc->jvms()->clone_shallow(C); + uint size = alloc->req(); + SafePointNode* sfpt = new SafePointNode(size, old_jvms); + old_jvms->set_map(sfpt); + for (uint i = 0; i < size; i++) { + sfpt->init_req(i, alloc->in(i)); + } + // re-push array length for deoptimization + sfpt->ins_req(old_jvms->stkoff() + old_jvms->sp(), alloc->in(AllocateNode::ALength)); + old_jvms->set_sp(old_jvms->sp()+1); + old_jvms->set_monoff(old_jvms->monoff()+1); + old_jvms->set_scloff(old_jvms->scloff()+1); + old_jvms->set_endoff(old_jvms->endoff()+1); + old_jvms->set_should_reexecute(true); + + sfpt->set_i_o(map()->i_o()); + sfpt->set_memory(map()->memory()); + sfpt->set_control(map()->control()); + + JVMState* saved_jvms = jvms(); + saved_reexecute_sp = _reexecute_sp; + + set_jvms(sfpt->jvms()); + _reexecute_sp = jvms()->sp(); + + return saved_jvms; + } + } + } + return NULL; +} + +// In case of a deoptimization, we restart execution at the +// allocation, allocating a new array. We would leave an uninitialized +// array in the heap that GCs wouldn't expect. Move the allocation +// after the traps so we don't allocate the array if we +// deoptimize. This is possible because tightly_coupled_allocation() +// guarantees there's no observer of the allocated array at this point +// and the control flow is simple enough. +void LibraryCallKit::arraycopy_move_allocation_here(AllocateArrayNode* alloc, Node* dest, JVMState* saved_jvms, int saved_reexecute_sp) { + if (saved_jvms != NULL && !stopped()) { + assert(alloc != NULL, "only with a tightly coupled allocation"); + // restore JVM state to the state at the arraycopy + saved_jvms->map()->set_control(map()->control()); + assert(saved_jvms->map()->memory() == map()->memory(), "memory state changed?"); + assert(saved_jvms->map()->i_o() == map()->i_o(), "IO state changed?"); + // If we've improved the types of some nodes (null check) while + // emitting the guards, propagate them to the current state + map()->replaced_nodes().apply(saved_jvms->map()); + set_jvms(saved_jvms); + _reexecute_sp = saved_reexecute_sp; + + // Remove the allocation from above the guards + CallProjections callprojs; + alloc->extract_projections(&callprojs, true); + InitializeNode* init = alloc->initialization(); + Node* alloc_mem = alloc->in(TypeFunc::Memory); + C->gvn_replace_by(callprojs.fallthrough_ioproj, alloc->in(TypeFunc::I_O)); + C->gvn_replace_by(init->proj_out(TypeFunc::Memory), alloc_mem); + C->gvn_replace_by(init->proj_out(TypeFunc::Control), alloc->in(0)); + + // move the allocation here (after the guards) + _gvn.hash_delete(alloc); + alloc->set_req(TypeFunc::Control, control()); + alloc->set_req(TypeFunc::I_O, i_o()); + Node *mem = reset_memory(); + set_all_memory(mem); + alloc->set_req(TypeFunc::Memory, mem); + set_control(init->proj_out(TypeFunc::Control)); + set_i_o(callprojs.fallthrough_ioproj); + + // Update memory as done in GraphKit::set_output_for_allocation() + const TypeInt* length_type = _gvn.find_int_type(alloc->in(AllocateNode::ALength)); + const TypeOopPtr* ary_type = _gvn.type(alloc->in(AllocateNode::KlassNode))->is_klassptr()->as_instance_type(); + if (ary_type->isa_aryptr() && length_type != NULL) { + ary_type = ary_type->is_aryptr()->cast_to_size(length_type); + } + const TypePtr* telemref = ary_type->add_offset(Type::OffsetBot); + int elemidx = C->get_alias_index(telemref); + set_memory(init->proj_out(TypeFunc::Memory), Compile::AliasIdxRaw); + set_memory(init->proj_out(TypeFunc::Memory), elemidx); + + Node* allocx = _gvn.transform(alloc); + assert(allocx == alloc, "where has the allocation gone?"); + assert(dest->is_CheckCastPP(), "not an allocation result?"); + + _gvn.hash_delete(dest); + dest->set_req(0, control()); + Node* destx = _gvn.transform(dest); + assert(destx == dest, "where has the allocation result gone?"); + } +} + + //------------------------------inline_arraycopy----------------------- // public static native void java.lang.System.arraycopy(Object src, int srcPos, // Object dest, int destPos, @@ -4686,6 +4855,19 @@ Node* dest_offset = argument(3); // type: int Node* length = argument(4); // type: int + + // Check for allocation before we add nodes that would confuse + // tightly_coupled_allocation() + AllocateArrayNode* alloc = tightly_coupled_allocation(dest, NULL); + + int saved_reexecute_sp = -1; + JVMState* saved_jvms = arraycopy_restore_alloc_state(alloc, saved_reexecute_sp); + // See arraycopy_restore_alloc_state() comment + // if alloc == NULL we don't have to worry about a tightly coupled allocation so we can emit all needed guards + // if saved_jvms != NULL (then alloc != NULL) then we can handle guards and a tightly coupled allocation + // if saved_jvms == NULL and alloc != NULL, we can’t emit any guards + bool can_emit_guards = (alloc == NULL || saved_jvms != NULL); + // The following tests must be performed // (1) src and dest are arrays. // (2) src and dest arrays must have elements of the same BasicType @@ -4699,42 +4881,20 @@ // (3) src and dest must not be null. // always do this here because we need the JVM state for uncommon traps - src = null_check(src, T_ARRAY); + Node* null_ctl = top(); + src = saved_jvms != NULL ? null_check_oop(src, &null_ctl, true, true) : null_check(src, T_ARRAY); + assert(null_ctl->is_top(), "no null control here"); dest = null_check(dest, T_ARRAY); - // Check for allocation before we add nodes that would confuse - // tightly_coupled_allocation() - AllocateArrayNode* alloc = tightly_coupled_allocation(dest, NULL); - - ciMethod* trap_method = method(); - int trap_bci = bci(); - SafePointNode* sfpt = NULL; - if (alloc != NULL) { - // The JVM state for uncommon traps between the allocation and - // arraycopy is set to the state before the allocation: if the - // initialization is performed by the array copy, we don't want to - // go back to the interpreter with an unitialized array. - JVMState* old_jvms = alloc->jvms(); - JVMState* jvms = old_jvms->clone_shallow(C); - uint size = alloc->req(); - sfpt = new SafePointNode(size, jvms); - jvms->set_map(sfpt); - for (uint i = 0; i < size; i++) { - sfpt->init_req(i, alloc->in(i)); - } - // re-push array length for deoptimization - sfpt->ins_req(jvms->stkoff() + jvms->sp(), alloc->in(AllocateNode::ALength)); - jvms->set_sp(jvms->sp()+1); - jvms->set_monoff(jvms->monoff()+1); - jvms->set_scloff(jvms->scloff()+1); - jvms->set_endoff(jvms->endoff()+1); - jvms->set_should_reexecute(true); - - sfpt->set_i_o(map()->i_o()); - sfpt->set_memory(map()->memory()); - - trap_method = jvms->method(); - trap_bci = jvms->bci(); + if (!can_emit_guards) { + // if saved_jvms == NULL and alloc != NULL, we don't emit any + // guards but the arraycopy node could still take advantage of a + // tightly allocated allocation. tightly_coupled_allocation() is + // called again to make sure it takes the null check above into + // account: the null check is mandatory and if it caused an + // uncommon trap to be emitted then the allocation can't be + // considered tightly coupled in this context. + alloc = tightly_coupled_allocation(dest, NULL); } bool validated = false; @@ -4753,7 +4913,7 @@ // Is the type for dest from speculation? bool dest_spec = false; - if (!has_src || !has_dest) { + if ((!has_src || !has_dest) && can_emit_guards) { // We don't have sufficient type information, let's see if // speculative types can help. We need to have types for both src // and dest so that it pays off. @@ -4782,7 +4942,7 @@ if (could_have_src && could_have_dest) { // This is going to pay off so emit the required guards if (!has_src) { - src = maybe_cast_profiled_obj(src, src_k, true, sfpt); + src = maybe_cast_profiled_obj(src, src_k, true); src_type = _gvn.type(src); top_src = src_type->isa_aryptr(); has_src = (top_src != NULL && top_src->klass() != NULL); @@ -4798,7 +4958,7 @@ } } - if (has_src && has_dest) { + if (has_src && has_dest && can_emit_guards) { BasicType src_elem = top_src->klass()->as_array_klass()->element_type()->basic_type(); BasicType dest_elem = top_dest->klass()->as_array_klass()->element_type()->basic_type(); if (src_elem == T_ARRAY) src_elem = T_OBJECT; @@ -4830,7 +4990,7 @@ if (could_have_src && could_have_dest) { // If we can have both exact types, emit the missing guards if (could_have_src && !src_spec) { - src = maybe_cast_profiled_obj(src, src_k, true, sfpt); + src = maybe_cast_profiled_obj(src, src_k, true); } if (could_have_dest && !dest_spec) { dest = maybe_cast_profiled_obj(dest, dest_k, true); @@ -4839,7 +4999,16 @@ } } - if (!C->too_many_traps(trap_method, trap_bci, Deoptimization::Reason_intrinsic) && !src->is_top() && !dest->is_top()) { + ciMethod* trap_method = method(); + int trap_bci = bci(); + if (saved_jvms != NULL) { + trap_method = alloc->jvms()->method(); + trap_bci = alloc->jvms()->bci(); + } + + if (!C->too_many_traps(trap_method, trap_bci, Deoptimization::Reason_intrinsic) && + can_emit_guards && + !src->is_top() && !dest->is_top()) { // validate arguments: enables transformation the ArrayCopyNode validated = true; @@ -4875,28 +5044,13 @@ Node* not_subtype_ctrl = gen_subtype_check(src_klass, dest_klass); if (not_subtype_ctrl != top()) { - if (sfpt != NULL) { - GraphKit kit(sfpt->jvms()); - PreserveJVMState pjvms(&kit); - kit.set_control(not_subtype_ctrl); - kit.uncommon_trap(Deoptimization::Reason_intrinsic, - Deoptimization::Action_make_not_entrant); - assert(kit.stopped(), "Should be stopped"); - } else { - PreserveJVMState pjvms(this); - set_control(not_subtype_ctrl); - uncommon_trap(Deoptimization::Reason_intrinsic, - Deoptimization::Action_make_not_entrant); - assert(stopped(), "Should be stopped"); - } + PreserveJVMState pjvms(this); + set_control(not_subtype_ctrl); + uncommon_trap(Deoptimization::Reason_intrinsic, + Deoptimization::Action_make_not_entrant); + assert(stopped(), "Should be stopped"); } - if (sfpt != NULL) { - GraphKit kit(sfpt->jvms()); - kit.set_control(_gvn.transform(slow_region)); - kit.uncommon_trap(Deoptimization::Reason_intrinsic, - Deoptimization::Action_make_not_entrant); - assert(kit.stopped(), "Should be stopped"); - } else { + { PreserveJVMState pjvms(this); set_control(_gvn.transform(slow_region)); uncommon_trap(Deoptimization::Reason_intrinsic, @@ -4905,6 +5059,8 @@ } } + arraycopy_move_allocation_here(alloc, dest, saved_jvms, saved_reexecute_sp); + if (stopped()) { return true; } @@ -5870,12 +6026,46 @@ Deoptimization::Action_reinterpret); return true; } + + // result is a boolean (0 or 1) and its profile (false_cnt & true_cnt) + // is a number of each value occurrences. + Node* result = argument(0); + if (false_cnt == 0 || true_cnt == 0) { + // According to profile, one value has been never seen. + int expected_val = (false_cnt == 0) ? 1 : 0; + + Node* cmp = _gvn.transform(new CmpINode(result, intcon(expected_val))); + Node* test = _gvn.transform(new BoolNode(cmp, BoolTest::eq)); + + IfNode* check = create_and_map_if(control(), test, PROB_ALWAYS, COUNT_UNKNOWN); + Node* fast_path = _gvn.transform(new IfTrueNode(check)); + Node* slow_path = _gvn.transform(new IfFalseNode(check)); + + { // Slow path: uncommon trap for never seen value and then reexecute + // MethodHandleImpl::profileBoolean() to bump the count, so JIT knows + // the value has been seen at least once. + PreserveJVMState pjvms(this); + PreserveReexecuteState preexecs(this); + jvms()->set_should_reexecute(true); + + set_control(slow_path); + set_i_o(i_o()); + + uncommon_trap_exact(Deoptimization::Reason_intrinsic, + Deoptimization::Action_reinterpret); + } + // The guard for never seen value enables sharpening of the result and + // returning a constant. It allows to eliminate branches on the same value + // later on. + set_control(fast_path); + result = intcon(expected_val); + } // Stop profiling. - // MethodHandleImpl::profileBoolean() has profiling logic in it's bytecode. - // By replacing method's body with profile data (represented as ProfileBooleanNode + // MethodHandleImpl::profileBoolean() has profiling logic in its bytecode. + // By replacing method body with profile data (represented as ProfileBooleanNode // on IR level) we effectively disable profiling. // It enables full speed execution once optimized code is generated. - Node* profile = _gvn.transform(new ProfileBooleanNode(argument(0), false_cnt, true_cnt)); + Node* profile = _gvn.transform(new ProfileBooleanNode(result, false_cnt, true_cnt)); C->record_for_igvn(profile); set_result(profile); return true; @@ -5888,3 +6078,9 @@ return false; } } + +bool LibraryCallKit::inline_isCompileConstant() { + Node* n = argument(0); + set_result(n->is_Con() ? intcon(1) : intcon(0)); + return true; +} diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/loopPredicate.cpp --- a/hotspot/src/share/vm/opto/loopPredicate.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/loopPredicate.cpp Thu May 07 20:51:12 2015 -0700 @@ -89,7 +89,7 @@ // // We will create a region to guard the uct call if there is no one there. // The true projecttion (if_cont) of the new_iff is returned. -// This code is also used to clone predicates to clonned loops. +// This code is also used to clone predicates to cloned loops. ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry, Deoptimization::DeoptReason reason) { assert(cont_proj->is_uncommon_trap_if_pattern(reason), "must be a uct if pattern!"); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/loopTransform.cpp --- a/hotspot/src/share/vm/opto/loopTransform.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/loopTransform.cpp Thu May 07 20:51:12 2015 -0700 @@ -38,6 +38,7 @@ #include "opto/rootnode.hpp" #include "opto/runtime.hpp" #include "opto/subnode.hpp" +#include "opto/vectornode.hpp" //------------------------------is_loop_exit----------------------------------- // Given an IfNode, return the loop-exiting projection or NULL if both @@ -1524,6 +1525,44 @@ } } +void PhaseIdealLoop::mark_reductions(IdealLoopTree *loop) { + if (SuperWordReductions == false) return; + + CountedLoopNode* loop_head = loop->_head->as_CountedLoop(); + if (loop_head->unrolled_count() > 1) { + return; + } + + Node* trip_phi = loop_head->phi(); + for (DUIterator_Fast imax, i = loop_head->fast_outs(imax); i < imax; i++) { + Node* phi = loop_head->fast_out(i); + if (phi->is_Phi() && phi->outcnt() > 0 && phi != trip_phi) { + // For definitions which are loop inclusive and not tripcounts. + Node* def_node = phi->in(LoopNode::LoopBackControl); + + if (def_node != NULL) { + Node* n_ctrl = get_ctrl(def_node); + if (n_ctrl != NULL && loop->is_member(get_loop(n_ctrl))) { + // Now test it to see if it fits the standard pattern for a reduction operator. + int opc = def_node->Opcode(); + if (opc != ReductionNode::opcode(opc, def_node->bottom_type()->basic_type())) { + if (!def_node->is_reduction()) { // Not marked yet + // To be a reduction, the arithmetic node must have the phi as input and provide a def to it + for (unsigned j = 1; j < def_node->req(); j++) { + Node* in = def_node->in(j); + if (in == phi) { + def_node->add_flag(Node::Flag_is_reduction); + break; + } + } + } + } + } + } + } + } +} + //------------------------------dominates_backedge--------------------------------- // Returns true if ctrl is executed on every complete iteration bool IdealLoopTree::dominates_backedge(Node* ctrl) { @@ -2361,8 +2400,10 @@ // an even number of trips). If we are peeling, we might enable some RCE // and we'd rather unroll the post-RCE'd loop SO... do not unroll if // peeling. - if (should_unroll && !should_peel) - phase->do_unroll(this,old_new, true); + if (should_unroll && !should_peel) { + phase->mark_reductions(this); + phase->do_unroll(this, old_new, true); + } // Adjust the pre-loop limits to align the main body // iterations. diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/loopnode.hpp --- a/hotspot/src/share/vm/opto/loopnode.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/loopnode.hpp Thu May 07 20:51:12 2015 -0700 @@ -872,6 +872,9 @@ // Unroll the loop body one step - make each trip do 2 iterations. void do_unroll( IdealLoopTree *loop, Node_List &old_new, bool adjust_min_trip ); + // Mark vector reduction candidates before loop unrolling + void mark_reductions( IdealLoopTree *loop ); + // Return true if exp is a constant times an induction var bool is_scaled_iv(Node* exp, Node* iv, int* p_scale); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/loopopts.cpp --- a/hotspot/src/share/vm/opto/loopopts.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/loopopts.cpp Thu May 07 20:51:12 2015 -0700 @@ -241,8 +241,8 @@ ProjNode* dp_proj = dp->as_Proj(); ProjNode* unc_proj = iff->as_If()->proj_out(1 - dp_proj->_con)->as_Proj(); if (exclude_loop_predicate && - (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate) || - unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_range_check))) { + (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate) != NULL || + unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_range_check) != NULL)) { // If this is a range check (IfNode::is_range_check), do not // reorder because Compile::allow_range_check_smearing might have // changed the check. diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/macro.cpp --- a/hotspot/src/share/vm/opto/macro.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/macro.cpp Thu May 07 20:51:12 2015 -0700 @@ -144,7 +144,9 @@ } //------------------------------make_slow_call--------------------------------- -CallNode* PhaseMacroExpand::make_slow_call(CallNode *oldcall, const TypeFunc* slow_call_type, address slow_call, const char* leaf_name, Node* slow_path, Node* parm0, Node* parm1) { +CallNode* PhaseMacroExpand::make_slow_call(CallNode *oldcall, const TypeFunc* slow_call_type, + address slow_call, const char* leaf_name, Node* slow_path, + Node* parm0, Node* parm1, Node* parm2) { // Slow-path call CallNode *call = leaf_name @@ -155,6 +157,7 @@ copy_predefined_input_for_runtime_call(slow_path, oldcall, call ); if (parm0 != NULL) call->init_req(TypeFunc::Parms+0, parm0); if (parm1 != NULL) call->init_req(TypeFunc::Parms+1, parm1); + if (parm2 != NULL) call->init_req(TypeFunc::Parms+2, parm2); copy_call_debug_info(oldcall, call); call->set_cnt(PROB_UNLIKELY_MAG(4)); // Same effect as RC_UNCOMMON. _igvn.replace_node(oldcall, call); @@ -2328,7 +2331,9 @@ } // Make slow path call - CallNode *call = make_slow_call( (CallNode *) lock, OptoRuntime::complete_monitor_enter_Type(), OptoRuntime::complete_monitor_locking_Java(), NULL, slow_path, obj, box ); + CallNode *call = make_slow_call((CallNode *) lock, OptoRuntime::complete_monitor_enter_Type(), + OptoRuntime::complete_monitor_locking_Java(), NULL, slow_path, + obj, box, NULL); extract_call_projections(call); @@ -2395,8 +2400,11 @@ funlock = transform_later( funlock )->as_FastUnlock(); // Optimize test; set region slot 2 Node *slow_path = opt_bits_test(ctrl, region, 2, funlock, 0, 0); + Node *thread = transform_later(new ThreadLocalNode()); - CallNode *call = make_slow_call( (CallNode *) unlock, OptoRuntime::complete_monitor_exit_Type(), CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_unlocking_C), "complete_monitor_unlocking_C", slow_path, obj, box ); + CallNode *call = make_slow_call((CallNode *) unlock, OptoRuntime::complete_monitor_exit_Type(), + CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_unlocking_C), + "complete_monitor_unlocking_C", slow_path, obj, box, thread); extract_call_projections(call); @@ -2535,7 +2543,7 @@ (bol->_test._test == BoolTest::ne), ""); IfNode* ifn = bol->unique_out()->as_If(); assert((ifn->outcnt() == 2) && - ifn->proj_out(1)->is_uncommon_trap_proj(Deoptimization::Reason_rtm_state_change), ""); + ifn->proj_out(1)->is_uncommon_trap_proj(Deoptimization::Reason_rtm_state_change) != NULL, ""); #endif Node* repl = n->in(1); if (!_has_locks) { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/macro.hpp --- a/hotspot/src/share/vm/opto/macro.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/macro.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -186,7 +186,8 @@ Node* opt_bits_test(Node* ctrl, Node* region, int edge, Node* word, int mask, int bits, bool return_fast_path = false); void copy_predefined_input_for_runtime_call(Node * ctrl, CallNode* oldcall, CallNode* call); CallNode* make_slow_call(CallNode *oldcall, const TypeFunc* slow_call_type, address slow_call, - const char* leaf_name, Node* slow_path, Node* parm0, Node* parm1); + const char* leaf_name, Node* slow_path, Node* parm0, Node* parm1, + Node* parm2); void extract_call_projections(CallNode *call); Node* initialize_object(AllocateNode* alloc, diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/matcher.cpp --- a/hotspot/src/share/vm/opto/matcher.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/matcher.cpp Thu May 07 20:51:12 2015 -0700 @@ -1049,6 +1049,15 @@ mstack.push(m, Visit, n, -1); } + // Handle precedence edges for interior nodes + for (i = n->len()-1; (uint)i >= n->req(); i--) { + Node *m = n->in(i); + if (m == NULL || C->node_arena()->contains(m)) continue; + n->rm_prec(i); + // set -1 to call add_prec() instead of set_req() during Step1 + mstack.push(m, Visit, n, -1); + } + // For constant debug info, I'd rather have unmatched constants. int cnt = n->req(); JVMState* jvms = n->jvms(); @@ -1738,6 +1747,14 @@ return ex; } +void Matcher::handle_precedence_edges(Node* n, MachNode *mach) { + for (uint i = n->req(); i < n->len(); i++) { + if (n->in(i) != NULL) { + mach->add_prec(n->in(i)); + } + } +} + void Matcher::ReduceInst_Chain_Rule( State *s, int rule, Node *&mem, MachNode *mach ) { // 'op' is what I am expecting to receive int op = _leftOp[rule]; @@ -1772,6 +1789,8 @@ uint Matcher::ReduceInst_Interior( State *s, int rule, Node *&mem, MachNode *mach, uint num_opnds ) { + handle_precedence_edges(s->_leaf, mach); + if( s->_leaf->is_Load() ) { Node *mem2 = s->_leaf->in(MemNode::Memory); assert( mem == (Node*)1 || mem == mem2, "multiple Memories being matched at once?" ); @@ -1854,6 +1873,9 @@ mem = s->_leaf->in(MemNode::Memory); debug_only(_mem_node = s->_leaf;) } + + handle_precedence_edges(s->_leaf, mach); + if( s->_leaf->in(0) && s->_leaf->req() > 1) { if( !mach->in(0) ) mach->set_req(0,s->_leaf->in(0)); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/matcher.hpp --- a/hotspot/src/share/vm/opto/matcher.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/matcher.hpp Thu May 07 20:51:12 2015 -0700 @@ -124,6 +124,8 @@ // Mach node for ConP #NULL MachNode* _mach_null; + void handle_precedence_edges(Node* n, MachNode *mach); + public: int LabelRootDepth; // Convert ideal machine register to a register mask for spill-loads diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/memnode.cpp --- a/hotspot/src/share/vm/opto/memnode.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/memnode.cpp Thu May 07 20:51:12 2015 -0700 @@ -652,216 +652,6 @@ } } -//------------------------adr_phi_is_loop_invariant---------------------------- -// A helper function for Ideal_DU_postCCP to check if a Phi in a counted -// loop is loop invariant. Make a quick traversal of Phi and associated -// CastPP nodes, looking to see if they are a closed group within the loop. -bool MemNode::adr_phi_is_loop_invariant(Node* adr_phi, Node* cast) { - // The idea is that the phi-nest must boil down to only CastPP nodes - // with the same data. This implies that any path into the loop already - // includes such a CastPP, and so the original cast, whatever its input, - // must be covered by an equivalent cast, with an earlier control input. - ResourceMark rm; - - // The loop entry input of the phi should be the unique dominating - // node for every Phi/CastPP in the loop. - Unique_Node_List closure; - closure.push(adr_phi->in(LoopNode::EntryControl)); - - // Add the phi node and the cast to the worklist. - Unique_Node_List worklist; - worklist.push(adr_phi); - if( cast != NULL ){ - if( !cast->is_ConstraintCast() ) return false; - worklist.push(cast); - } - - // Begin recursive walk of phi nodes. - while( worklist.size() ){ - // Take a node off the worklist - Node *n = worklist.pop(); - if( !closure.member(n) ){ - // Add it to the closure. - closure.push(n); - // Make a sanity check to ensure we don't waste too much time here. - if( closure.size() > 20) return false; - // This node is OK if: - // - it is a cast of an identical value - // - or it is a phi node (then we add its inputs to the worklist) - // Otherwise, the node is not OK, and we presume the cast is not invariant - if( n->is_ConstraintCast() ){ - worklist.push(n->in(1)); - } else if( n->is_Phi() ) { - for( uint i = 1; i < n->req(); i++ ) { - worklist.push(n->in(i)); - } - } else { - return false; - } - } - } - - // Quit when the worklist is empty, and we've found no offending nodes. - return true; -} - -//------------------------------Ideal_DU_postCCP------------------------------- -// Find any cast-away of null-ness and keep its control. Null cast-aways are -// going away in this pass and we need to make this memory op depend on the -// gating null check. -Node *MemNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { - return Ideal_common_DU_postCCP(ccp, this, in(MemNode::Address)); -} - -// I tried to leave the CastPP's in. This makes the graph more accurate in -// some sense; we get to keep around the knowledge that an oop is not-null -// after some test. Alas, the CastPP's interfere with GVN (some values are -// the regular oop, some are the CastPP of the oop, all merge at Phi's which -// cannot collapse, etc). This cost us 10% on SpecJVM, even when I removed -// some of the more trivial cases in the optimizer. Removing more useless -// Phi's started allowing Loads to illegally float above null checks. I gave -// up on this approach. CNC 10/20/2000 -// This static method may be called not from MemNode (EncodePNode calls it). -// Only the control edge of the node 'n' might be updated. -Node *MemNode::Ideal_common_DU_postCCP( PhaseCCP *ccp, Node* n, Node* adr ) { - Node *skipped_cast = NULL; - // Need a null check? Regular static accesses do not because they are - // from constant addresses. Array ops are gated by the range check (which - // always includes a NULL check). Just check field ops. - if( n->in(MemNode::Control) == NULL ) { - // Scan upwards for the highest location we can place this memory op. - while( true ) { - switch( adr->Opcode() ) { - - case Op_AddP: // No change to NULL-ness, so peek thru AddP's - adr = adr->in(AddPNode::Base); - continue; - - case Op_DecodeN: // No change to NULL-ness, so peek thru - case Op_DecodeNKlass: - adr = adr->in(1); - continue; - - case Op_EncodeP: - case Op_EncodePKlass: - // EncodeP node's control edge could be set by this method - // when EncodeP node depends on CastPP node. - // - // Use its control edge for memory op because EncodeP may go away - // later when it is folded with following or preceding DecodeN node. - if (adr->in(0) == NULL) { - // Keep looking for cast nodes. - adr = adr->in(1); - continue; - } - ccp->hash_delete(n); - n->set_req(MemNode::Control, adr->in(0)); - ccp->hash_insert(n); - return n; - - case Op_CastPP: - // If the CastPP is useless, just peek on through it. - if( ccp->type(adr) == ccp->type(adr->in(1)) ) { - // Remember the cast that we've peeked though. If we peek - // through more than one, then we end up remembering the highest - // one, that is, if in a loop, the one closest to the top. - skipped_cast = adr; - adr = adr->in(1); - continue; - } - // CastPP is going away in this pass! We need this memory op to be - // control-dependent on the test that is guarding the CastPP. - ccp->hash_delete(n); - n->set_req(MemNode::Control, adr->in(0)); - ccp->hash_insert(n); - return n; - - case Op_Phi: - // Attempt to float above a Phi to some dominating point. - if (adr->in(0) != NULL && adr->in(0)->is_CountedLoop()) { - // If we've already peeked through a Cast (which could have set the - // control), we can't float above a Phi, because the skipped Cast - // may not be loop invariant. - if (adr_phi_is_loop_invariant(adr, skipped_cast)) { - adr = adr->in(1); - continue; - } - } - - // Intentional fallthrough! - - // No obvious dominating point. The mem op is pinned below the Phi - // by the Phi itself. If the Phi goes away (no true value is merged) - // then the mem op can float, but not indefinitely. It must be pinned - // behind the controls leading to the Phi. - case Op_CheckCastPP: - // These usually stick around to change address type, however a - // useless one can be elided and we still need to pick up a control edge - if (adr->in(0) == NULL) { - // This CheckCastPP node has NO control and is likely useless. But we - // need check further up the ancestor chain for a control input to keep - // the node in place. 4959717. - skipped_cast = adr; - adr = adr->in(1); - continue; - } - ccp->hash_delete(n); - n->set_req(MemNode::Control, adr->in(0)); - ccp->hash_insert(n); - return n; - - // List of "safe" opcodes; those that implicitly block the memory - // op below any null check. - case Op_CastX2P: // no null checks on native pointers - case Op_Parm: // 'this' pointer is not null - case Op_LoadP: // Loading from within a klass - case Op_LoadN: // Loading from within a klass - case Op_LoadKlass: // Loading from within a klass - case Op_LoadNKlass: // Loading from within a klass - case Op_ConP: // Loading from a klass - case Op_ConN: // Loading from a klass - case Op_ConNKlass: // Loading from a klass - case Op_CreateEx: // Sucking up the guts of an exception oop - case Op_Con: // Reading from TLS - case Op_CMoveP: // CMoveP is pinned - case Op_CMoveN: // CMoveN is pinned - break; // No progress - - case Op_Proj: // Direct call to an allocation routine - case Op_SCMemProj: // Memory state from store conditional ops -#ifdef ASSERT - { - assert(adr->as_Proj()->_con == TypeFunc::Parms, "must be return value"); - const Node* call = adr->in(0); - if (call->is_CallJava()) { - const CallJavaNode* call_java = call->as_CallJava(); - const TypeTuple *r = call_java->tf()->range(); - assert(r->cnt() > TypeFunc::Parms, "must return value"); - const Type* ret_type = r->field_at(TypeFunc::Parms); - assert(ret_type && ret_type->isa_ptr(), "must return pointer"); - // We further presume that this is one of - // new_instance_Java, new_array_Java, or - // the like, but do not assert for this. - } else if (call->is_Allocate()) { - // similar case to new_instance_Java, etc. - } else if (!call->is_CallLeaf()) { - // Projections from fetch_oop (OSR) are allowed as well. - ShouldNotReachHere(); - } - } -#endif - break; - default: - ShouldNotReachHere(); - } - break; - } - } - - return NULL; // No progress -} - - //============================================================================= // Should LoadNode::Ideal() attempt to remove control edges? bool LoadNode::can_remove_control() const { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/memnode.hpp --- a/hotspot/src/share/vm/opto/memnode.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/memnode.hpp Thu May 07 20:51:12 2015 -0700 @@ -84,10 +84,6 @@ // This one should probably be a phase-specific function: static bool all_controls_dominate(Node* dom, Node* sub); - // Find any cast-away of null-ness and keep its control. - static Node *Ideal_common_DU_postCCP( PhaseCCP *ccp, Node* n, Node* adr ); - virtual Node *Ideal_DU_postCCP( PhaseCCP *ccp ); - virtual const class TypePtr *adr_type() const; // returns bottom_type of address // Shared code for Ideal methods: diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/multnode.cpp --- a/hotspot/src/share/vm/opto/multnode.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/multnode.cpp Thu May 07 20:51:12 2015 -0700 @@ -150,59 +150,67 @@ } //-------------------------------is_uncommon_trap_proj---------------------------- -// Return true if proj is the form of "proj->[region->..]call_uct" -bool ProjNode::is_uncommon_trap_proj(Deoptimization::DeoptReason reason) { +// Return uncommon trap call node if proj is for "proj->[region->..]call_uct" +// NULL otherwise +CallStaticJavaNode* ProjNode::is_uncommon_trap_proj(Deoptimization::DeoptReason reason) { int path_limit = 10; Node* out = this; for (int ct = 0; ct < path_limit; ct++) { out = out->unique_ctrl_out(); if (out == NULL) - return false; + return NULL; if (out->is_CallStaticJava()) { - int req = out->as_CallStaticJava()->uncommon_trap_request(); + CallStaticJavaNode* call = out->as_CallStaticJava(); + int req = call->uncommon_trap_request(); if (req != 0) { Deoptimization::DeoptReason trap_reason = Deoptimization::trap_request_reason(req); if (trap_reason == reason || reason == Deoptimization::Reason_none) { - return true; + return call; } } - return false; // don't do further after call + return NULL; // don't do further after call } if (out->Opcode() != Op_Region) - return false; + return NULL; } - return false; + return NULL; } //-------------------------------is_uncommon_trap_if_pattern------------------------- -// Return true for "if(test)-> proj -> ... -// | -// V -// other_proj->[region->..]call_uct" -// +// Return uncommon trap call node for "if(test)-> proj -> ... +// | +// V +// other_proj->[region->..]call_uct" +// NULL otherwise // "must_reason_predicate" means the uct reason must be Reason_predicate -bool ProjNode::is_uncommon_trap_if_pattern(Deoptimization::DeoptReason reason) { +CallStaticJavaNode* ProjNode::is_uncommon_trap_if_pattern(Deoptimization::DeoptReason reason) { Node *in0 = in(0); - if (!in0->is_If()) return false; + if (!in0->is_If()) return NULL; // Variation of a dead If node. - if (in0->outcnt() < 2) return false; + if (in0->outcnt() < 2) return NULL; IfNode* iff = in0->as_If(); // we need "If(Conv2B(Opaque1(...)))" pattern for reason_predicate if (reason != Deoptimization::Reason_none) { if (iff->in(1)->Opcode() != Op_Conv2B || iff->in(1)->in(1)->Opcode() != Op_Opaque1) { - return false; + return NULL; } } ProjNode* other_proj = iff->proj_out(1-_con); if (other_proj == NULL) // Should never happen, but make Parfait happy. - return false; - if (other_proj->is_uncommon_trap_proj(reason)) { + return NULL; + CallStaticJavaNode* call = other_proj->is_uncommon_trap_proj(reason); + if (call != NULL) { assert(reason == Deoptimization::Reason_none || Compile::current()->is_predicate_opaq(iff->in(1)->in(1)), "should be on the list"); - return true; + return call; } - return false; + return NULL; } + +ProjNode* ProjNode::other_if_proj() const { + assert(_con == 0 || _con == 1, "not an if?"); + return in(0)->as_If()->proj_out(1-_con); +} diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/multnode.hpp --- a/hotspot/src/share/vm/opto/multnode.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/multnode.hpp Thu May 07 20:51:12 2015 -0700 @@ -89,13 +89,18 @@ virtual void dump_spec(outputStream *st) const; #endif - // Return true if proj is for "proj->[region->..]call_uct" - bool is_uncommon_trap_proj(Deoptimization::DeoptReason reason); - // Return true for "if(test)-> proj -> ... - // | - // V - // other_proj->[region->..]call_uct" - bool is_uncommon_trap_if_pattern(Deoptimization::DeoptReason reason); + // Return uncommon trap call node if proj is for "proj->[region->..]call_uct" + // NULL otherwise + CallStaticJavaNode* is_uncommon_trap_proj(Deoptimization::DeoptReason reason); + // Return uncommon trap call node for "if(test)-> proj -> ... + // | + // V + // other_proj->[region->..]call_uct" + // NULL otherwise + CallStaticJavaNode* is_uncommon_trap_if_pattern(Deoptimization::DeoptReason reason); + + // Return other proj node when this is a If proj node + ProjNode* other_if_proj() const; }; #endif // SHARE_VM_OPTO_MULTNODE_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/narrowptrnode.cpp --- a/hotspot/src/share/vm/opto/narrowptrnode.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/narrowptrnode.cpp Thu May 07 20:51:12 2015 -0700 @@ -67,10 +67,6 @@ } -Node *EncodeNarrowPtrNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { - return MemNode::Ideal_common_DU_postCCP(ccp, this, in(1)); -} - Node* DecodeNKlassNode::Identity(PhaseTransform* phase) { const Type *t = phase->type( in(1) ); if( t == Type::TOP ) return in(1); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/narrowptrnode.hpp --- a/hotspot/src/share/vm/opto/narrowptrnode.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/narrowptrnode.hpp Thu May 07 20:51:12 2015 -0700 @@ -39,7 +39,6 @@ } public: virtual uint ideal_reg() const { return Op_RegN; } - virtual Node *Ideal_DU_postCCP( PhaseCCP *ccp ); }; //------------------------------EncodeP-------------------------------- diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/node.cpp --- a/hotspot/src/share/vm/opto/node.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/node.cpp Thu May 07 20:51:12 2015 -0700 @@ -1387,12 +1387,6 @@ return false; } -//------------------------------Ideal_DU_postCCP------------------------------- -// Idealize graph, using DU info. Must clone result into new-space -Node *Node::Ideal_DU_postCCP( PhaseCCP * ) { - return NULL; // Default to no change -} - //------------------------------hash------------------------------------------- // Hash function over Nodes. uint Node::hash() const { @@ -2069,7 +2063,7 @@ //--------------------------unique_ctrl_out------------------------------ // Return the unique control out if only one. Null if none or more than one. -Node* Node::unique_ctrl_out() { +Node* Node::unique_ctrl_out() const { Node* found = NULL; for (uint i = 0; i < outcnt(); i++) { Node* use = raw_out(i); @@ -2081,6 +2075,14 @@ return found; } +void Node::ensure_control_or_add_prec(Node* c) { + if (in(0) == NULL) { + set_req(0, c); + } else if (in(0) != c) { + add_prec(c); + } +} + //============================================================================= //------------------------------yank------------------------------------------- // Find and remove diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/node.hpp --- a/hotspot/src/share/vm/opto/node.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/node.hpp Thu May 07 20:51:12 2015 -0700 @@ -673,7 +673,8 @@ Flag_avoid_back_to_back_before = Flag_may_be_short_branch << 1, Flag_avoid_back_to_back_after = Flag_avoid_back_to_back_before << 1, Flag_has_call = Flag_avoid_back_to_back_after << 1, - Flag_is_expensive = Flag_has_call << 1, + Flag_is_reduction = Flag_has_call << 1, + Flag_is_expensive = Flag_is_reduction << 1, _max_flags = (Flag_is_expensive << 1) - 1 // allow flags combination }; @@ -701,6 +702,10 @@ const jushort flags() const { return _flags; } + void add_flag(jushort fl) { init_flags(fl); } + + void remove_flag(jushort fl) { clear_flag(fl); } + // Return a dense integer opcode number virtual int Opcode() const; @@ -852,6 +857,10 @@ // The node is expensive: the best control is set during loop opts bool is_expensive() const { return (_flags & Flag_is_expensive) != 0 && in(0) != NULL; } + // An arithmetic node which accumulates a data in a loop. + // It must have the loop's phi as input and provide a def to the phi. + bool is_reduction() const { return (_flags & Flag_is_reduction) != 0; } + //----------------- Optimization // Get the worst-case Type output for this Node. @@ -897,9 +906,6 @@ bool remove_dead_region(PhaseGVN *phase, bool can_reshape); public: - // Idealize graph, using DU info. Done after constant propagation - virtual Node *Ideal_DU_postCCP( PhaseCCP *ccp ); - // See if there is valid pipeline info static const Pipeline *pipeline_class(); virtual const Pipeline *pipeline() const; @@ -931,7 +937,10 @@ Node* find_similar(int opc); // Return the unique control out if only one. Null if none or more than one. - Node* unique_ctrl_out(); + Node* unique_ctrl_out() const; + + // Set control or add control as precedence edge + void ensure_control_or_add_prec(Node* c); //----------------- Code Generation diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/phaseX.cpp --- a/hotspot/src/share/vm/opto/phaseX.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/phaseX.cpp Thu May 07 20:51:12 2015 -0700 @@ -1605,21 +1605,6 @@ C->set_root( transform(C->root())->as_Root() ); assert( C->top(), "missing TOP node" ); assert( C->root(), "missing root" ); - - // Eagerly remove castPP nodes here. CastPP nodes might not be - // removed in the subsequent IGVN phase if a node that changes - // in(1) of a castPP is processed prior to the castPP node. - for (uint i = 0; i < _worklist.size(); i++) { - Node* n = _worklist.at(i); - - if (n->is_ConstraintCast()) { - Node* nn = n->Identity(this); - if (nn != n) { - replace_node(n, nn); - --i; - } - } - } } //------------------------------transform-------------------------------------- @@ -1700,11 +1685,6 @@ _worklist.push(n); // n re-enters the hash table via the worklist } - // Idealize graph using DU info. Must clone() into new-space. - // DU info is generally used to show profitability, progress or safety - // (but generally not needed for correctness). - Node *nn = n->Ideal_DU_postCCP(this); - // TEMPORARY fix to ensure that 2nd GVN pass eliminates NULL checks switch( n->Opcode() ) { case Op_FastLock: // Revisit FastLocks for lock coarsening @@ -1721,12 +1701,6 @@ default: break; } - if( nn ) { - _worklist.push(n); - // Put users of 'n' onto worklist for second igvn transform - add_users_to_worklist(n); - return nn; - } return n; } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/runtime.cpp --- a/hotspot/src/share/vm/opto/runtime.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/runtime.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -600,10 +600,11 @@ //----------------------------------------------------------------------------- const TypeFunc *OptoRuntime::complete_monitor_exit_Type() { // create input type (domain) - const Type **fields = TypeTuple::fields(2); + const Type **fields = TypeTuple::fields(3); fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; // Object to be Locked - fields[TypeFunc::Parms+1] = TypeRawPtr::BOTTOM; // Address of stack location for lock - const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+2,fields); + fields[TypeFunc::Parms+1] = TypeRawPtr::BOTTOM; // Address of stack location for lock - BasicLock + fields[TypeFunc::Parms+2] = TypeRawPtr::BOTTOM; // Thread pointer (Self) + const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+3,fields); // create result type (range) fields = TypeTuple::fields(0); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/runtime.hpp --- a/hotspot/src/share/vm/opto/runtime.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/runtime.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -184,7 +184,7 @@ public: // Slow-path Locking and Unlocking static void complete_monitor_locking_C(oopDesc* obj, BasicLock* lock, JavaThread* thread); - static void complete_monitor_unlocking_C(oopDesc* obj, BasicLock* lock); + static void complete_monitor_unlocking_C(oopDesc* obj, BasicLock* lock, JavaThread* thread); private: diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/subnode.hpp --- a/hotspot/src/share/vm/opto/subnode.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/subnode.hpp Thu May 07 20:51:12 2015 -0700 @@ -275,6 +275,8 @@ mask commute( ) const { return mask("032147658"[_test]-'0'); } mask negate( ) const { return mask(_test^4); } bool is_canonical( ) const { return (_test == BoolTest::ne || _test == BoolTest::lt || _test == BoolTest::le || _test == BoolTest::overflow); } + bool is_less( ) const { return _test == BoolTest::lt || _test == BoolTest::le; } + bool is_greater( ) const { return _test == BoolTest::gt || _test == BoolTest::ge; } void dump_on(outputStream *st) const; }; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/superword.cpp --- a/hotspot/src/share/vm/opto/superword.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/superword.cpp Thu May 07 20:51:12 2015 -0700 @@ -65,7 +65,8 @@ _lpt(NULL), // loop tree node _lp(NULL), // LoopNode _bb(NULL), // basic block - _iv(NULL) // induction var + _iv(NULL), // induction var + _race_possible(false) // cases where SDMU is true {} //------------------------------transform_loop--------------------------- @@ -145,7 +146,6 @@ void SuperWord::SLP_extract() { // Ready the block - if (!construct_bb()) return; // Exit if no interesting nodes or complex graph. @@ -449,11 +449,13 @@ int preloop_stride = pre_end->stride_con(); int span = preloop_stride * p.scale_in_bytes(); - - // Stride one accesses are alignable. - if (ABS(span) == p.memory_size()) + int mem_size = p.memory_size(); + int offset = p.offset_in_bytes(); + // Stride one accesses are alignable if offset is aligned to memory operation size. + // Offset can be unaligned when UseUnalignedAccesses is used. + if (ABS(span) == mem_size && (ABS(offset) % mem_size) == 0) { return true; - + } // If initial offset from start of object is computable, // compute alignment within the vector. int vw = vector_width_in_bytes(p.mem()); @@ -463,7 +465,7 @@ if (init_nd->is_Con() && p.invar() == NULL) { int init = init_nd->bottom_type()->is_int()->get_con(); - int init_offset = init * p.scale_in_bytes() + p.offset_in_bytes(); + int init_offset = init * p.scale_in_bytes() + offset; assert(init_offset >= 0, "positive offset from object start"); if (span > 0) { @@ -640,7 +642,7 @@ } if (isomorphic(s1, s2)) { - if (independent(s1, s2)) { + if (independent(s1, s2) || reduction(s1, s2)) { if (!exists_at(s1, 0) && !exists_at(s2, 1)) { if (!s1->is_Mem() || are_adjacent_refs(s1, s2)) { int s1_align = alignment(s1); @@ -718,6 +720,28 @@ return independent_path(shallow, deep); } +//------------------------------reduction--------------------------- +// Is there a data path between s1 and s2 and the nodes reductions? +bool SuperWord::reduction(Node* s1, Node* s2) { + bool retValue = false; + int d1 = depth(s1); + int d2 = depth(s2); + if (d1 + 1 == d2) { + if (s1->is_reduction() && s2->is_reduction()) { + // This is an ordered set, so s1 should define s2 + for (DUIterator_Fast imax, i = s1->fast_outs(imax); i < imax; i++) { + Node* t1 = s1->fast_out(i); + if (t1 == s2) { + // both nodes are reductions and connected + retValue = true; + } + } + } + } + + return retValue; +} + //------------------------------independent_path------------------------------ // Helper for independent bool SuperWord::independent_path(Node* shallow, Node* deep, uint dp) { @@ -761,6 +785,7 @@ void SuperWord::extend_packlist() { bool changed; do { + packset_sort(_packset.length()); changed = false; for (int i = 0; i < _packset.length(); i++) { Node_List* p = _packset.at(i); @@ -769,6 +794,13 @@ } } while (changed); + if (_race_possible) { + for (int i = 0; i < _packset.length(); i++) { + Node_List* p = _packset.at(i); + order_def_uses(p); + } + } + #ifndef PRODUCT if (TraceSuperWord) { tty->print_cr("\nAfter extend_packlist"); @@ -825,10 +857,12 @@ int align = alignment(s1); int savings = -1; + int num_s1_uses = 0; Node* u1 = NULL; Node* u2 = NULL; for (DUIterator_Fast imax, i = s1->fast_outs(imax); i < imax; i++) { Node* t1 = s1->fast_out(i); + num_s1_uses++; if (!in_bb(t1)) continue; for (DUIterator_Fast jmax, j = s2->fast_outs(jmax); j < jmax; j++) { Node* t2 = s2->fast_out(j); @@ -845,6 +879,9 @@ } } } + if (num_s1_uses > 1) { + _race_possible = true; + } if (savings >= 0) { Node_List* pair = new Node_List(); pair->push(u1); @@ -856,9 +893,64 @@ return changed; } +//------------------------------order_def_uses--------------------------- +// For extended packsets, ordinally arrange uses packset by major component +void SuperWord::order_def_uses(Node_List* p) { + Node* s1 = p->at(0); + + if (s1->is_Store()) return; + + // reductions are always managed beforehand + if (s1->is_reduction()) return; + + for (DUIterator_Fast imax, i = s1->fast_outs(imax); i < imax; i++) { + Node* t1 = s1->fast_out(i); + + // Only allow operand swap on commuting operations + if (!t1->is_Add() && !t1->is_Mul()) { + break; + } + + // Now find t1's packset + Node_List* p2 = NULL; + for (int j = 0; j < _packset.length(); j++) { + p2 = _packset.at(j); + Node* first = p2->at(0); + if (t1 == first) { + break; + } + p2 = NULL; + } + // Arrange all sub components by the major component + if (p2 != NULL) { + for (uint j = 1; j < p->size(); j++) { + Node* d1 = p->at(j); + Node* u1 = p2->at(j); + opnd_positions_match(s1, t1, d1, u1); + } + } + } +} + //---------------------------opnd_positions_match------------------------- // Is the use of d1 in u1 at the same operand position as d2 in u2? bool SuperWord::opnd_positions_match(Node* d1, Node* u1, Node* d2, Node* u2) { + // check reductions to see if they are marshalled to represent the reduction + // operator in a specified opnd + if (u1->is_reduction() && u2->is_reduction()) { + // ensure reductions have phis and reduction definitions feeding the 1st operand + Node* first = u1->in(2); + if (first->is_Phi() || first->is_reduction()) { + u1->swap_edges(1, 2); + } + // ensure reductions have phis and reduction definitions feeding the 1st operand + first = u2->in(2); + if (first->is_Phi() || first->is_reduction()) { + u2->swap_edges(1, 2); + } + return true; + } + uint ct = u1->req(); if (ct != u2->req()) return false; uint i1 = 0; @@ -940,7 +1032,8 @@ for (int i = 0; i < _packset.length(); i++) { Node_List* p1 = _packset.at(i); if (p1 == NULL) continue; - for (int j = 0; j < _packset.length(); j++) { + // Because of sorting we can start at i + 1 + for (int j = i + 1; j < _packset.length(); j++) { Node_List* p2 = _packset.at(j); if (p2 == NULL) continue; if (i == j) continue; @@ -1067,8 +1160,19 @@ //------------------------------implemented--------------------------- // Can code be generated for pack p? bool SuperWord::implemented(Node_List* p) { + bool retValue = false; Node* p0 = p->at(0); - return VectorNode::implemented(p0->Opcode(), p->size(), velt_basic_type(p0)); + if (p0 != NULL) { + int opc = p0->Opcode(); + uint size = p->size(); + if (p0->is_reduction()) { + const Type *arith_type = p0->bottom_type(); + retValue = ReductionNode::implemented(opc, size, arith_type->basic_type()); + } else { + retValue = VectorNode::implemented(opc, size, velt_basic_type(p0)); + } + } + return retValue; } //------------------------------same_inputs-------------------------- @@ -1102,6 +1206,18 @@ if (!is_vector_use(p0, i)) return false; } + // Check if reductions are connected + if (p0->is_reduction()) { + Node* second_in = p0->in(2); + Node_List* second_pk = my_pack(second_in); + if (second_pk == NULL) { + // Remove reduction flag if no parent pack, it is not profitable + p0->remove_flag(Node::Flag_is_reduction); + return false; + } else if (second_pk->size() != p->size()) { + return false; + } + } if (VectorNode::is_shift(p0)) { // For now, return false if shift count is vector or not scalar promotion // case (different shift counts) because it is not supported yet. @@ -1123,6 +1239,9 @@ for (uint k = 0; k < use->req(); k++) { Node* n = use->in(k); if (def == n) { + // reductions can be loop carried dependences + if (def->is_reduction() && use->is_Phi()) + continue; if (!is_vector_use(use, k)) { return false; } @@ -1407,16 +1526,33 @@ vlen_in_bytes = vn->as_StoreVector()->memory_size(); } else if (n->req() == 3) { // Promote operands to vector - Node* in1 = vector_opd(p, 1); + Node* in1 = NULL; + bool node_isa_reduction = n->is_reduction(); + if (node_isa_reduction) { + // the input to the first reduction operation is retained + in1 = low_adr->in(1); + } else { + in1 = vector_opd(p, 1); + } Node* in2 = vector_opd(p, 2); - if (VectorNode::is_invariant_vector(in1) && (n->is_Add() || n->is_Mul())) { + if (VectorNode::is_invariant_vector(in1) && (node_isa_reduction == false) && (n->is_Add() || n->is_Mul())) { // Move invariant vector input into second position to avoid register spilling. Node* tmp = in1; in1 = in2; in2 = tmp; } - vn = VectorNode::make(opc, in1, in2, vlen, velt_basic_type(n)); - vlen_in_bytes = vn->as_Vector()->length_in_bytes(); + if (node_isa_reduction) { + const Type *arith_type = n->bottom_type(); + vn = ReductionNode::make(opc, NULL, in1, in2, arith_type->basic_type()); + if (in2->is_Load()) { + vlen_in_bytes = in2->as_LoadVector()->memory_size(); + } else { + vlen_in_bytes = in2->as_Vector()->length_in_bytes(); + } + } else { + vn = VectorNode::make(opc, in1, in2, vlen, velt_basic_type(n)); + vlen_in_bytes = vn->as_Vector()->length_in_bytes(); + } } else { ShouldNotReachHere(); } @@ -1556,6 +1692,8 @@ _n_idx_list.pop(); Node* def = use->in(idx); + if (def->is_reduction()) continue; + // Insert extract operation _igvn.hash_delete(def); int def_pos = alignment(def) / data_size(def); @@ -1576,6 +1714,7 @@ bool SuperWord::is_vector_use(Node* use, int u_idx) { Node_List* u_pk = my_pack(use); if (u_pk == NULL) return false; + if (use->is_reduction()) return true; Node* def = use->in(u_idx); Node_List* d_pk = my_pack(def); if (d_pk == NULL) { @@ -1613,7 +1752,7 @@ // by the visited and post_visited sets, // and count number of nodes in block. int bb_ct = 0; - for (uint i = 0; i < lpt()->_body.size(); i++ ) { + for (uint i = 0; i < lpt()->_body.size(); i++) { Node *n = lpt()->_body.at(i); set_bb_idx(n, i); // Create a temporary map if (in_bb(n)) { @@ -1674,6 +1813,7 @@ // Do a depth first walk over out edges int rpo_idx = bb_ct - 1; int size; + int reduction_uses = 0; while ((size = _stk.length()) > 0) { Node* n = _stk.top(); // Leave node on stack if (!visited_test_set(n)) { @@ -1685,6 +1825,14 @@ if (in_bb(use) && !visited_test(use) && // Don't go around backedge (!use->is_Phi() || n == entry)) { + if (use->is_reduction()) { + // First see if we can map the reduction on the given system we are on, then + // make a data entry operation for each reduction we see. + BasicType bt = use->bottom_type()->basic_type(); + if (ReductionNode::implemented(use->Opcode(), Matcher::min_vector_size(bt), bt)) { + reduction_uses++; + } + } _stk.push(use); } } @@ -1708,7 +1856,8 @@ set_bb_idx(n, j); } - initialize_bb(); // Ensure extra info is allocated. + // Ensure extra info is allocated. + initialize_bb(); #ifndef PRODUCT if (TraceSuperWord) { @@ -1726,7 +1875,7 @@ } #endif assert(rpo_idx == -1 && bb_ct == _block.length(), "all block members found"); - return (_mem_slice_head.length() > 0) || (_data_entry.length() > 0); + return (_mem_slice_head.length() > 0) || (reduction_uses > 0) || (_data_entry.length() > 0); } //------------------------------initialize_bb--------------------------- @@ -1959,6 +2108,27 @@ _packset.remove_at(pos); } +void SuperWord::packset_sort(int n) { + // simple bubble sort so that we capitalize with O(n) when its already sorted + while (n != 0) { + bool swapped = false; + for (int i = 1; i < n; i++) { + Node_List* q_low = _packset.at(i-1); + Node_List* q_i = _packset.at(i); + + // only swap when we find something to swap + if (alignment(q_low->at(0)) > alignment(q_i->at(0))) { + Node_List* t = q_i; + *(_packset.adr_at(i)) = q_low; + *(_packset.adr_at(i-1)) = q_i; + swapped = true; + } + } + if (swapped == false) break; + n--; + } +} + //------------------------------executed_first--------------------------- // Return the node executed first in pack p. Uses the RPO block list // to determine order. diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/superword.hpp --- a/hotspot/src/share/vm/opto/superword.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/superword.hpp Thu May 07 20:51:12 2015 -0700 @@ -249,6 +249,7 @@ LoopNode* _lp; // Current LoopNode Node* _bb; // Current basic block PhiNode* _iv; // Induction var + bool _race_possible; // In cases where SDMU is true // Accessors Arena* arena() { return _arena; } @@ -337,6 +338,8 @@ bool isomorphic(Node* s1, Node* s2); // Is there no data path from s1 to s2 or s2 to s1? bool independent(Node* s1, Node* s2); + // Is there a data path between s1 and s2 and both are reductions? + bool reduction(Node* s1, Node* s2); // Helper for independent bool independent_path(Node* shallow, Node* deep, uint dp=0); void set_alignment(Node* s1, Node* s2, int align); @@ -347,6 +350,8 @@ bool follow_use_defs(Node_List* p); // Extend the packset by visiting uses of nodes in pack p bool follow_def_uses(Node_List* p); + // For extended packsets, ordinally arrange uses packset by major component + void order_def_uses(Node_List* p); // Estimate the savings from executing s1 and s2 as a pack int est_savings(Node* s1, Node* s2); int adjacent_profit(Node* s1, Node* s2); @@ -419,9 +424,12 @@ void print_bb(); void print_stmt(Node* s); char* blank(uint depth); + + void packset_sort(int n); }; + //------------------------------SWPointer--------------------------- // Information about an address for dependence checking and vector alignment class SWPointer VALUE_OBJ_CLASS_SPEC { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/type.cpp --- a/hotspot/src/share/vm/opto/type.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/type.cpp Thu May 07 20:51:12 2015 -0700 @@ -1158,11 +1158,11 @@ // Certain normalizations keep us sane when comparing types. // The 'SMALLINT' covers constants and also CC and its relatives. if (lo <= hi) { - if ((juint)(hi - lo) <= SMALLINT) w = Type::WidenMin; - if ((juint)(hi - lo) >= max_juint) w = Type::WidenMax; // TypeInt::INT + if (((juint)hi - lo) <= SMALLINT) w = Type::WidenMin; + if (((juint)hi - lo) >= max_juint) w = Type::WidenMax; // TypeInt::INT } else { - if ((juint)(lo - hi) <= SMALLINT) w = Type::WidenMin; - if ((juint)(lo - hi) >= max_juint) w = Type::WidenMin; // dual TypeInt::INT + if (((juint)lo - hi) <= SMALLINT) w = Type::WidenMin; + if (((juint)lo - hi) >= max_juint) w = Type::WidenMin; // dual TypeInt::INT } return w; } @@ -1416,11 +1416,11 @@ // Certain normalizations keep us sane when comparing types. // The 'SMALLINT' covers constants. if (lo <= hi) { - if ((julong)(hi - lo) <= SMALLINT) w = Type::WidenMin; - if ((julong)(hi - lo) >= max_julong) w = Type::WidenMax; // TypeLong::LONG + if (((julong)hi - lo) <= SMALLINT) w = Type::WidenMin; + if (((julong)hi - lo) >= max_julong) w = Type::WidenMax; // TypeLong::LONG } else { - if ((julong)(lo - hi) <= SMALLINT) w = Type::WidenMin; - if ((julong)(lo - hi) >= max_julong) w = Type::WidenMin; // dual TypeLong::LONG + if (((julong)lo - hi) <= SMALLINT) w = Type::WidenMin; + if (((julong)lo - hi) >= max_julong) w = Type::WidenMin; // dual TypeLong::LONG } return w; } @@ -4083,7 +4083,9 @@ (tap->_klass_is_exact && !tap->klass()->is_subtype_of(klass())) || // 'this' is exact and super or unrelated: (this->_klass_is_exact && !klass()->is_subtype_of(tap->klass())))) { - tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable); + if (above_centerline(ptr)) { + tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable); + } return make(NotNull, NULL, tary, lazy_klass, false, off, InstanceBot, speculative, depth); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/vectornode.cpp --- a/hotspot/src/share/vm/opto/vectornode.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/vectornode.cpp Thu May 07 20:51:12 2015 -0700 @@ -250,7 +250,6 @@ int vopc = VectorNode::opcode(opc, bt); // This method should not be called for unimplemented vectors. guarantee(vopc > 0, err_msg_res("Vector for '%s' is not implemented", NodeClassNames[opc])); - switch (vopc) { case Op_AddVB: return new AddVBNode(n1, n2, vt); case Op_AddVS: return new AddVSNode(n1, n2, vt); @@ -441,3 +440,72 @@ return NULL; } +int ReductionNode::opcode(int opc, BasicType bt) { + int vopc = opc; + switch (opc) { + case Op_AddI: + assert(bt == T_INT, "must be"); + vopc = Op_AddReductionVI; + break; + case Op_AddL: + assert(bt == T_LONG, "must be"); + vopc = Op_AddReductionVL; + break; + case Op_AddF: + assert(bt == T_FLOAT, "must be"); + vopc = Op_AddReductionVF; + break; + case Op_AddD: + assert(bt == T_DOUBLE, "must be"); + vopc = Op_AddReductionVD; + break; + case Op_MulI: + assert(bt == T_INT, "must be"); + vopc = Op_MulReductionVI; + break; + case Op_MulF: + assert(bt == T_FLOAT, "must be"); + vopc = Op_MulReductionVF; + break; + case Op_MulD: + assert(bt == T_DOUBLE, "must be"); + vopc = Op_MulReductionVD; + break; + // TODO: add MulL for targets that support it + default: + break; + } + return vopc; +} + +// Return the appropriate reduction node. +ReductionNode* ReductionNode::make(int opc, Node *ctrl, Node* n1, Node* n2, BasicType bt) { + + int vopc = opcode(opc, bt); + + // This method should not be called for unimplemented vectors. + guarantee(vopc != opc, err_msg_res("Vector for '%s' is not implemented", NodeClassNames[opc])); + + switch (vopc) { + case Op_AddReductionVI: return new AddReductionVINode(ctrl, n1, n2); + case Op_AddReductionVL: return new AddReductionVLNode(ctrl, n1, n2); + case Op_AddReductionVF: return new AddReductionVFNode(ctrl, n1, n2); + case Op_AddReductionVD: return new AddReductionVDNode(ctrl, n1, n2); + case Op_MulReductionVI: return new MulReductionVINode(ctrl, n1, n2); + case Op_MulReductionVF: return new MulReductionVFNode(ctrl, n1, n2); + case Op_MulReductionVD: return new MulReductionVDNode(ctrl, n1, n2); + } + fatal(err_msg_res("Missed vector creation for '%s'", NodeClassNames[vopc])); + return NULL; +} + +bool ReductionNode::implemented(int opc, uint vlen, BasicType bt) { + if (is_java_primitive(bt) && + (vlen > 1) && is_power_of_2(vlen) && + Matcher::vector_size_supported(bt, vlen)) { + int vopc = ReductionNode::opcode(opc, bt); + return vopc != opc && Matcher::match_rule_supported(vopc); + } + return false; +} + diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/opto/vectornode.hpp --- a/hotspot/src/share/vm/opto/vectornode.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/opto/vectornode.hpp Thu May 07 20:51:12 2015 -0700 @@ -90,6 +90,37 @@ virtual int Opcode() const; }; +//------------------------------ReductionNode------------------------------------ +// Perform reduction of a vector +class ReductionNode : public Node { + public: + ReductionNode(Node *ctrl, Node* in1, Node* in2) : Node(ctrl, in1, in2) {} + + static ReductionNode* make(int opc, Node *ctrl, Node* in1, Node* in2, BasicType bt); + static int opcode(int opc, BasicType bt); + static bool implemented(int opc, uint vlen, BasicType bt); +}; + +//------------------------------AddReductionVINode-------------------------------------- +// Vector add int as a reduction +class AddReductionVINode : public ReductionNode { +public: + AddReductionVINode(Node * ctrl, Node* in1, Node* in2) : ReductionNode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual const Type* bottom_type() const { return TypeInt::INT; } + virtual uint ideal_reg() const { return Op_RegI; } +}; + +//------------------------------AddReductionVLNode-------------------------------------- +// Vector add long as a reduction +class AddReductionVLNode : public ReductionNode { +public: + AddReductionVLNode(Node *ctrl, Node* in1, Node* in2) : ReductionNode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual const Type* bottom_type() const { return TypeLong::LONG; } + virtual uint ideal_reg() const { return Op_RegL; } +}; + //------------------------------AddVLNode-------------------------------------- // Vector add long class AddVLNode : public VectorNode { @@ -106,6 +137,16 @@ virtual int Opcode() const; }; +//------------------------------AddReductionVFNode-------------------------------------- +// Vector add float as a reduction +class AddReductionVFNode : public ReductionNode { +public: + AddReductionVFNode(Node *ctrl, Node* in1, Node* in2) : ReductionNode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual const Type* bottom_type() const { return Type::FLOAT; } + virtual uint ideal_reg() const { return Op_RegF; } +}; + //------------------------------AddVDNode-------------------------------------- // Vector add double class AddVDNode : public VectorNode { @@ -114,6 +155,16 @@ virtual int Opcode() const; }; +//------------------------------AddReductionVDNode-------------------------------------- +// Vector add double as a reduction +class AddReductionVDNode : public ReductionNode { +public: + AddReductionVDNode(Node *ctrl, Node* in1, Node* in2) : ReductionNode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual const Type* bottom_type() const { return Type::DOUBLE; } + virtual uint ideal_reg() const { return Op_RegD; } +}; + //------------------------------SubVBNode-------------------------------------- // Vector subtract byte class SubVBNode : public VectorNode { @@ -178,6 +229,16 @@ virtual int Opcode() const; }; +//------------------------------MulReductionVINode-------------------------------------- +// Vector multiply int as a reduction +class MulReductionVINode : public ReductionNode { +public: + MulReductionVINode(Node *ctrl, Node* in1, Node* in2) : ReductionNode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual const Type* bottom_type() const { return TypeInt::INT; } + virtual uint ideal_reg() const { return Op_RegI; } +}; + //------------------------------MulVFNode-------------------------------------- // Vector multiply float class MulVFNode : public VectorNode { @@ -186,6 +247,16 @@ virtual int Opcode() const; }; +//------------------------------MulReductionVFNode-------------------------------------- +// Vector multiply float as a reduction +class MulReductionVFNode : public ReductionNode { +public: + MulReductionVFNode(Node *ctrl, Node* in1, Node* in2) : ReductionNode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual const Type* bottom_type() const { return Type::FLOAT; } + virtual uint ideal_reg() const { return Op_RegF; } +}; + //------------------------------MulVDNode-------------------------------------- // Vector multiply double class MulVDNode : public VectorNode { @@ -194,6 +265,16 @@ virtual int Opcode() const; }; +//------------------------------MulReductionVDNode-------------------------------------- +// Vector multiply double as a reduction +class MulReductionVDNode : public ReductionNode { +public: + MulReductionVDNode(Node *ctrl, Node* in1, Node* in2) : ReductionNode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual const Type* bottom_type() const { return Type::DOUBLE; } + virtual uint ideal_reg() const { return Op_RegD; } +}; + //------------------------------DivVFNode-------------------------------------- // Vector divide float class DivVFNode : public VectorNode { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/precompiled/precompiled.hpp --- a/hotspot/src/share/vm/precompiled/precompiled.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/precompiled/precompiled.hpp Thu May 07 20:51:12 2015 -0700 @@ -94,7 +94,6 @@ # include "gc_implementation/shared/spaceCounters.hpp" # include "gc_implementation/shared/spaceDecorator.hpp" # include "gc_interface/collectedHeap.hpp" -# include "gc_interface/collectedHeap.inline.hpp" # include "gc_interface/gcCause.hpp" # include "interpreter/abstractInterpreter.hpp" # include "interpreter/bytecode.hpp" @@ -114,15 +113,12 @@ # include "memory/allocation.hpp" # include "memory/allocation.inline.hpp" # include "memory/barrierSet.hpp" -# include "memory/barrierSet.inline.hpp" # include "memory/blockOffsetTable.hpp" -# include "memory/blockOffsetTable.inline.hpp" # include "memory/cardTableModRefBS.hpp" # include "memory/collectorPolicy.hpp" # include "memory/defNewGeneration.hpp" # include "memory/gcLocker.hpp" # include "memory/genCollectedHeap.hpp" -# include "memory/genOopClosures.hpp" # include "memory/genRemSet.hpp" # include "memory/generation.hpp" # include "memory/heap.hpp" @@ -133,12 +129,11 @@ # include "memory/referencePolicy.hpp" # include "memory/referenceProcessor.hpp" # include "memory/resourceArea.hpp" -# include "memory/sharedHeap.hpp" # include "memory/space.hpp" # include "memory/threadLocalAllocBuffer.hpp" -# include "memory/threadLocalAllocBuffer.inline.hpp" # include "memory/universe.hpp" # include "memory/universe.inline.hpp" +# include "memory/virtualspace.hpp" # include "memory/watermark.hpp" # include "oops/arrayKlass.hpp" # include "oops/arrayOop.hpp" @@ -147,7 +142,6 @@ # include "oops/instanceOop.hpp" # include "oops/instanceRefKlass.hpp" # include "oops/klass.hpp" -# include "oops/klassPS.hpp" # include "oops/klassVtable.hpp" # include "oops/markOop.hpp" # include "oops/markOop.inline.hpp" @@ -211,7 +205,6 @@ # include "runtime/timer.hpp" # include "runtime/unhandledOops.hpp" # include "runtime/vframe.hpp" -# include "runtime/virtualspace.hpp" # include "runtime/vmThread.hpp" # include "runtime/vm_operations.hpp" # include "runtime/vm_version.hpp" @@ -305,7 +298,6 @@ # include "gc_implementation/concurrentMarkSweep/promotionInfo.hpp" # include "gc_implementation/g1/dirtyCardQueue.hpp" # include "gc_implementation/g1/g1BlockOffsetTable.hpp" -# include "gc_implementation/g1/g1BlockOffsetTable.inline.hpp" # include "gc_implementation/g1/g1OopClosures.hpp" # include "gc_implementation/g1/g1_globals.hpp" # include "gc_implementation/g1/ptrQueue.hpp" @@ -319,12 +311,11 @@ # include "gc_implementation/parallelScavenge/psGCAdaptivePolicyCounters.hpp" # include "gc_implementation/parallelScavenge/psGenerationCounters.hpp" # include "gc_implementation/parallelScavenge/psOldGen.hpp" -# include "gc_implementation/parallelScavenge/psParallelCompact.hpp" # include "gc_implementation/parallelScavenge/psVirtualspace.hpp" # include "gc_implementation/parallelScavenge/psYoungGen.hpp" # include "gc_implementation/shared/gcAdaptivePolicyCounters.hpp" # include "gc_implementation/shared/gcPolicyCounters.hpp" -# include "gc_implementation/shared/parGCAllocBuffer.hpp" +# include "gc_implementation/shared/plab.hpp" #endif // INCLUDE_ALL_GCS #endif // !DONT_USE_PRECOMPILED_HEADER diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/prims/forte.cpp --- a/hotspot/src/share/vm/prims/forte.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/prims/forte.cpp Thu May 07 20:51:12 2015 -0700 @@ -171,8 +171,27 @@ // Now do we have a useful PcDesc? if (pc_desc == NULL || pc_desc->scope_decode_offset() == DebugInformationRecorder::serialized_null) { - // No debug information available for this pc - // vframeStream would explode if we try and walk the frames. + // No debug information is available for this PC. + // + // vframeStreamCommon::fill_from_frame() will decode the frame depending + // on the state of the thread. + // + // Case #1: If the thread is in Java (state == _thread_in_Java), then + // the vframeStreamCommon object will be filled as if the frame were a native + // compiled frame. Therefore, no debug information is needed. + // + // Case #2: If the thread is in any other state, then two steps will be performed: + // - if asserts are enabled, found_bad_method_frame() will be called and + // the assert in found_bad_method_frame() will be triggered; + // - if asserts are disabled, the vframeStreamCommon object will be filled + // as if it were a native compiled frame. + // + // Case (2) is similar to the way interpreter frames are processed in + // vframeStreamCommon::fill_from_interpreter_frame in case no valid BCI + // was found for an interpreted frame. If asserts are enabled, the assert + // in found_bad_method_frame() will be triggered. If asserts are disabled, + // the vframeStreamCommon object will be filled afterwards as if the + // interpreter were at the point of entering into the method. return false; } @@ -229,9 +248,10 @@ // a valid method. Then again we may have caught an interpreter // frame in the middle of construction and the bci field is // not yet valid. - - *method_p = method; if (!method->is_valid_method()) return false; + *method_p = method; // If the Method* found is invalid, it is + // ignored by forte_fill_call_trace_given_top(). + // So set method_p only if the Method is valid. address bcp = fr->interpreter_frame_bcp(); int bci = method->validate_bci_from_bcp(bcp); @@ -245,18 +265,33 @@ } -// Determine if 'fr' can be used to find an initial Java frame. -// Return false if it can not find a fully decipherable Java frame -// (in other words a frame that isn't safe to use in a vframe stream). -// Obviously if it can't even find a Java frame false will also be returned. +// Determine if a Java frame can be found starting with the frame 'fr'. +// +// Check the return value of find_initial_Java_frame and the value of +// 'method_p' to decide on how use the results returned by this method. +// +// If 'method_p' is not NULL, an initial Java frame has been found and +// the stack can be walked starting from that initial frame. In this case, +// 'method_p' points to the Method that the initial frame belongs to and +// the initial Java frame is returned in initial_frame_p. +// +// find_initial_Java_frame() returns true if a Method has been found (i.e., +// 'method_p' is not NULL) and the initial frame that belongs to that Method +// is decipherable. // -// If we find a Java frame decipherable or not then by definition we have -// identified a method and that will be returned to the caller via method_p. -// If we can determine a bci that is returned also. (Hmm is it possible -// to return a method and bci and still return false? ) +// A frame is considered to be decipherable: +// +// - if the frame is a compiled frame and a PCDesc is available; +// +// - if the frame is an interpreter frame that is valid or the thread is +// state (_thread_in_native || state == _thread_in_vm || state == _thread_blocked). // -// The initial Java frame we find (if any) is return via initial_frame_p. +// Note that find_initial_Java_frame() can return false even if an initial +// Java method was found (e.g., there is no PCDesc available for the method). // +// If 'method_p' is NULL, it was not possible to find a Java frame when +// walking the stack starting from 'fr'. In this case find_initial_Java_frame +// returns false. static bool find_initial_Java_frame(JavaThread* thread, frame* fr, @@ -276,8 +311,6 @@ // recognizable to us. This should only happen if we are in a JRT_LEAF // or something called by a JRT_LEAF method. - - frame candidate = *fr; // If the starting frame we were given has no codeBlob associated with @@ -332,9 +365,11 @@ nmethod* nm = (nmethod*) candidate.cb(); *method_p = nm->method(); - // If the frame isn't fully decipherable then the default - // value for the bci is a signal that we don't have a bci. - // If we have a decipherable frame this bci value will + // If the frame is not decipherable, then the value of -1 + // for the BCI is used to signal that no BCI is available. + // Furthermore, the method returns false in this case. + // + // If a decipherable frame is available, the BCI value will // not be used. *bci_p = -1; @@ -345,9 +380,9 @@ if (nm->is_native_method()) return true; - // If it isn't decipherable then we have found a pc that doesn't - // have a PCDesc that can get us a bci however we did find - // a method + // If the frame is not decipherable, then a PC was found + // that does not have a PCDesc from which a BCI can be obtained. + // Nevertheless, a Method was found. if (!is_decipherable_compiled_frame(thread, &candidate, nm)) { return false; @@ -356,7 +391,7 @@ // is_decipherable_compiled_frame may modify candidate's pc *initial_frame_p = candidate; - assert(nm->pc_desc_at(candidate.pc()) != NULL, "if it's decipherable then pc must be valid"); + assert(nm->pc_desc_at(candidate.pc()) != NULL, "debug information must be available if the frame is decipherable"); return true; } @@ -386,17 +421,17 @@ frame initial_Java_frame; Method* method; - int bci; + int bci = -1; // assume BCI is not available for method + // update with correct information if available int count; count = 0; assert(trace->frames != NULL, "trace->frames must be non-NULL"); - bool fully_decipherable = find_initial_Java_frame(thd, &top_frame, &initial_Java_frame, &method, &bci); + // Walk the stack starting from 'top_frame' and search for an initial Java frame. + find_initial_Java_frame(thd, &top_frame, &initial_Java_frame, &method, &bci); - // The frame might not be walkable but still recovered a method - // (e.g. an nmethod with no scope info for the pc) - + // Check if a Java Method has been found. if (method == NULL) return; if (!method->is_valid_method()) { @@ -404,29 +439,6 @@ return; } - // We got a Java frame however it isn't fully decipherable - // so it won't necessarily be safe to use it for the - // initial frame in the vframe stream. - - if (!fully_decipherable) { - // Take whatever method the top-frame decoder managed to scrape up. - // We look further at the top frame only if non-safepoint - // debugging information is available. - count++; - trace->num_frames = count; - trace->frames[0].method_id = method->find_jmethod_id_or_null(); - if (!method->is_native()) { - trace->frames[0].lineno = bci; - } else { - trace->frames[0].lineno = -3; - } - - if (!initial_Java_frame.safe_for_sender(thd)) return; - - RegisterMap map(thd, false); - initial_Java_frame = initial_Java_frame.sender(&map); - } - vframeStreamForte st(thd, initial_Java_frame, false); for (; !st.at_end() && count < depth; st.forte_next(), count++) { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/prims/jni.cpp --- a/hotspot/src/share/vm/prims/jni.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/prims/jni.cpp Thu May 07 20:51:12 2015 -0700 @@ -84,6 +84,9 @@ static jint CurrentVersion = JNI_VERSION_1_8; +#ifdef _WIN32 +extern LONG WINAPI topLevelExceptionFilter(_EXCEPTION_POINTERS* ); +#endif // The DT_RETURN_MARK macros create a scoped object to fire the dtrace // '-return' probe regardless of the return path is taken out of the function. @@ -3924,7 +3927,7 @@ DT_RETURN_MARK_DECL(CreateJavaVM, jint , HOTSPOT_JNI_CREATEJAVAVM_RETURN(_ret_ref)); -_JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, void *args) { +static jint JNI_CreateJavaVM_inner(JavaVM **vm, void **penv, void *args) { HOTSPOT_JNI_CREATEJAVAVM_ENTRY((void **) vm, penv, args); jint result = JNI_ERR; @@ -4001,18 +4004,14 @@ } #ifndef PRODUCT - #ifndef CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED - #define CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(f) f() - #endif - // Check if we should compile all classes on bootclasspath if (CompileTheWorld) ClassLoader::compile_the_world(); if (ReplayCompiles) ciReplay::replay(thread); // Some platforms (like Win*) need a wrapper around these test // functions in order to properly handle error conditions. - CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(test_error_handler); - CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(execute_internal_vm_tests); + test_error_handler(); + execute_internal_vm_tests(); #endif // Since this is not a JVM_ENTRY we have to set the thread state manually before leaving. @@ -4045,8 +4044,23 @@ } return result; + } +_JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, void *args) { + jint result = 0; + // On Windows, let CreateJavaVM run with SEH protection +#ifdef _WIN32 + __try { +#endif + result = JNI_CreateJavaVM_inner(vm, penv, args); +#ifdef _WIN32 + } __except(topLevelExceptionFilter((_EXCEPTION_POINTERS*)_exception_info())) { + // Nothing to do. + } +#endif + return result; +} _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_GetCreatedJavaVMs(JavaVM **vm_buf, jsize bufLen, jsize *numVMs) { // See bug 4367188, the wrapper can sometimes cause VM crashes diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/prims/jvm.cpp --- a/hotspot/src/share/vm/prims/jvm.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/prims/jvm.cpp Thu May 07 20:51:12 2015 -0700 @@ -1465,63 +1465,26 @@ } JVM_END -// should be in InstanceKlass.cpp, but is here for historical reasons -Klass* InstanceKlass::compute_enclosing_class_impl(instanceKlassHandle k, - bool* inner_is_member, - TRAPS) { - Thread* thread = THREAD; - InnerClassesIterator iter(k); - if (iter.length() == 0) { - // No inner class info => no declaring class +JVM_ENTRY(jstring, JVM_GetSimpleBinaryName(JNIEnv *env, jclass cls)) +{ + oop mirror = JNIHandles::resolve_non_null(cls); + if (java_lang_Class::is_primitive(mirror) || + !java_lang_Class::as_Klass(mirror)->oop_is_instance()) { return NULL; } - - constantPoolHandle i_cp(thread, k->constants()); - - bool found = false; - Klass* ok; - instanceKlassHandle outer_klass; - *inner_is_member = false; - - // Find inner_klass attribute - for (; !iter.done() && !found; iter.next()) { - int ioff = iter.inner_class_info_index(); - int ooff = iter.outer_class_info_index(); - int noff = iter.inner_name_index(); - if (ioff != 0) { - // Check to see if the name matches the class we're looking for - // before attempting to find the class. - if (i_cp->klass_name_at_matches(k, ioff)) { - Klass* inner_klass = i_cp->klass_at(ioff, CHECK_NULL); - found = (k() == inner_klass); - if (found && ooff != 0) { - ok = i_cp->klass_at(ooff, CHECK_NULL); - outer_klass = instanceKlassHandle(thread, ok); - *inner_is_member = true; - } - } + instanceKlassHandle k(THREAD, InstanceKlass::cast(java_lang_Class::as_Klass(mirror))); + int ooff = 0, noff = 0; + if (InstanceKlass::find_inner_classes_attr(k, &ooff, &noff, THREAD)) { + if (noff != 0) { + constantPoolHandle i_cp(thread, k->constants()); + Symbol* name = i_cp->symbol_at(noff); + Handle str = java_lang_String::create_from_symbol(name, CHECK_NULL); + return (jstring) JNIHandles::make_local(env, str()); } } - - if (found && outer_klass.is_null()) { - // It may be anonymous; try for that. - int encl_method_class_idx = k->enclosing_method_class_index(); - if (encl_method_class_idx != 0) { - ok = i_cp->klass_at(encl_method_class_idx, CHECK_NULL); - outer_klass = instanceKlassHandle(thread, ok); - *inner_is_member = false; - } - } - - // If no inner class attribute found for this class. - if (outer_klass.is_null()) return NULL; - - // Throws an exception if outer klass has not declared k as an inner klass - // We need evidence that each klass knows about the other, or else - // the system could allow a spoof of an inner class to gain access rights. - Reflection::check_for_inner_class(outer_klass, k, *inner_is_member, CHECK_NULL); - return outer_klass(); + return NULL; } +JVM_END JVM_ENTRY(jstring, JVM_GetClassSignature(JNIEnv *env, jclass cls)) assert (cls != NULL, "illegal class"); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/prims/jvm.h --- a/hotspot/src/share/vm/prims/jvm.h Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/prims/jvm.h Thu May 07 20:51:12 2015 -0700 @@ -426,6 +426,9 @@ JNIEXPORT jclass JNICALL JVM_GetDeclaringClass(JNIEnv *env, jclass ofClass); +JNIEXPORT jstring JNICALL +JVM_GetSimpleBinaryName(JNIEnv *env, jclass ofClass); + /* Generics support (JDK 1.5) */ JNIEXPORT jstring JNICALL JVM_GetClassSignature(JNIEnv *env, jclass cls); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp --- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Thu May 07 20:51:12 2015 -0700 @@ -3433,10 +3433,7 @@ pv_node = pv_node->previous_versions()) { cp_cache = pv_node->constants()->cache(); if (cp_cache != NULL) { - cp_cache->adjust_method_entries(_matching_old_methods, - _matching_new_methods, - _matching_methods_length, - &trace_name_printed); + cp_cache->adjust_method_entries(pv_node, &trace_name_printed); } } } @@ -3992,14 +3989,13 @@ // the_class doesn't have a cache yet so copy it the_class->set_cached_class_file(scratch_class->get_cached_class_file()); } -#ifndef PRODUCT - else { - assert(the_class->get_cached_class_file_bytes() == - scratch_class->get_cached_class_file_bytes(), "cache ptrs must match"); - assert(the_class->get_cached_class_file_len() == - scratch_class->get_cached_class_file_len(), "cache lens must match"); + else if (scratch_class->get_cached_class_file_bytes() != + the_class->get_cached_class_file_bytes()) { + // The same class can be present twice in the scratch classes list or there + // are multiple concurrent RetransformClasses calls on different threads. + // In such cases we have to deallocate scratch_class cached_class_file_bytes. + os::free(scratch_class->get_cached_class_file_bytes()); } -#endif // NULL out in scratch class to not delete twice. The class to be redefined // always owns these bytes. @@ -4086,10 +4082,7 @@ MemberNameTable* mnt = the_class->member_names(); if (mnt != NULL) { bool trace_name_printed = false; - mnt->adjust_method_entries(_matching_old_methods, - _matching_new_methods, - _matching_methods_length, - &trace_name_printed); + mnt->adjust_method_entries(the_class(), &trace_name_printed); } // Fix Resolution Error table also to remove old constant pools diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/prims/methodHandles.cpp --- a/hotspot/src/share/vm/prims/methodHandles.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/prims/methodHandles.cpp Thu May 07 20:51:12 2015 -0700 @@ -35,6 +35,7 @@ #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "prims/methodHandles.hpp" +#include "prims/jvmtiRedefineClassesTrace.hpp" #include "runtime/compilationPolicy.hpp" #include "runtime/javaCalls.hpp" #include "runtime/reflection.hpp" @@ -939,6 +940,24 @@ return rfill + overflow; } +// Get context class for a CallSite instance: either extract existing context or use default one. +InstanceKlass* MethodHandles::get_call_site_context(oop call_site) { + // In order to extract a context the following traversal is performed: + // CallSite.context => Cleaner.referent => Class._klass => Klass + assert(java_lang_invoke_CallSite::is_instance(call_site), ""); + oop context_oop = java_lang_invoke_CallSite::context_volatile(call_site); + if (oopDesc::is_null(context_oop)) { + return NULL; // The context hasn't been initialized yet. + } + oop context_class_oop = java_lang_ref_Reference::referent(context_oop); + if (oopDesc::is_null(context_class_oop)) { + // The context reference was cleared by GC, so current dependency context + // isn't usable anymore. Context should be fetched from CallSite again. + return NULL; + } + return InstanceKlass::cast(java_lang_Class::as_Klass(context_class_oop)); +} + //------------------------------------------------------------------------------ // MemberNameTable // @@ -965,21 +984,41 @@ #if INCLUDE_JVMTI // It is called at safepoint only for RedefineClasses -void MemberNameTable::adjust_method_entries(Method** old_methods, Method** new_methods, - int methods_length, bool *trace_name_printed) { +void MemberNameTable::adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed) { assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); // For each redefined method - for (int j = 0; j < methods_length; j++) { - Method* old_method = old_methods[j]; - Method* new_method = new_methods[j]; + for (int idx = 0; idx < length(); idx++) { + oop mem_name = JNIHandles::resolve(this->at(idx)); + if (mem_name == NULL) { + continue; + } + Method* old_method = (Method*)java_lang_invoke_MemberName::vmtarget(mem_name); + + if (old_method == NULL || !old_method->is_old()) { + continue; // skip uninteresting entries + } + if (old_method->is_deleted()) { + // skip entries with deleted methods + continue; + } + Method* new_method = holder->method_with_idnum(old_method->orig_method_idnum()); - // search the MemberNameTable for uses of either obsolete or EMCP methods - for (int idx = 0; idx < length(); idx++) { - oop mem_name = JNIHandles::resolve(this->at(idx)); - if (mem_name != NULL) { - java_lang_invoke_MemberName::adjust_vmtarget(mem_name, old_method, new_method, - trace_name_printed); + assert(new_method != NULL, "method_with_idnum() should not be NULL"); + assert(old_method != new_method, "sanity check"); + + java_lang_invoke_MemberName::set_vmtarget(mem_name, new_method); + + if (RC_TRACE_IN_RANGE(0x00100000, 0x00400000)) { + if (!(*trace_name_printed)) { + // RC_TRACE_MESG macro has an embedded ResourceMark + RC_TRACE_MESG(("adjust: name=%s", + old_method->method_holder()->external_name())); + *trace_name_printed = true; } + // RC_TRACE macro has an embedded ResourceMark + RC_TRACE(0x00400000, ("MemberName method update: %s(%s)", + new_method->name()->as_C_string(), + new_method->signature()->as_C_string())); } } } @@ -994,22 +1033,8 @@ // that intrinsic (non-JNI) native methods are defined in HotSpot. // -JVM_ENTRY(jint, MHN_getConstant(JNIEnv *env, jobject igcls, jint which)) { - switch (which) { - case MethodHandles::GC_COUNT_GWT: -#ifdef COMPILER2 - return true; -#else - return false; -#endif - } - return 0; -} -JVM_END - #ifndef PRODUCT #define EACH_NAMED_CON(template, requirement) \ - template(MethodHandles,GC_COUNT_GWT) \ template(java_lang_invoke_MemberName,MN_IS_METHOD) \ template(java_lang_invoke_MemberName,MN_IS_CONSTRUCTOR) \ template(java_lang_invoke_MemberName,MN_IS_FIELD) \ @@ -1019,7 +1044,6 @@ template(java_lang_invoke_MemberName,MN_SEARCH_INTERFACES) \ template(java_lang_invoke_MemberName,MN_REFERENCE_KIND_SHIFT) \ template(java_lang_invoke_MemberName,MN_REFERENCE_KIND_MASK) \ - template(MethodHandles,GC_LAMBDA_SUPPORT) \ /*end*/ #define IGNORE_REQ(req_expr) /* req_expr */ @@ -1246,7 +1270,7 @@ JVM_ENTRY(void, MHN_setCallSiteTargetNormal(JNIEnv* env, jobject igcls, jobject call_site_jh, jobject target_jh)) { Handle call_site(THREAD, JNIHandles::resolve_non_null(call_site_jh)); - Handle target (THREAD, JNIHandles::resolve(target_jh)); + Handle target (THREAD, JNIHandles::resolve_non_null(target_jh)); { // Walk all nmethods depending on this call site. MutexLocker mu(Compile_lock, thread); @@ -1258,7 +1282,7 @@ JVM_ENTRY(void, MHN_setCallSiteTargetVolatile(JNIEnv* env, jobject igcls, jobject call_site_jh, jobject target_jh)) { Handle call_site(THREAD, JNIHandles::resolve_non_null(call_site_jh)); - Handle target (THREAD, JNIHandles::resolve(target_jh)); + Handle target (THREAD, JNIHandles::resolve_non_null(target_jh)); { // Walk all nmethods depending on this call site. MutexLocker mu(Compile_lock, thread); @@ -1268,6 +1292,33 @@ } JVM_END +JVM_ENTRY(void, MHN_invalidateDependentNMethods(JNIEnv* env, jobject igcls, jobject call_site_jh)) { + Handle call_site(THREAD, JNIHandles::resolve_non_null(call_site_jh)); + { + // Walk all nmethods depending on this call site. + MutexLocker mu1(Compile_lock, thread); + + CallSiteDepChange changes(call_site(), Handle()); + + InstanceKlass* ctxk = MethodHandles::get_call_site_context(call_site()); + if (ctxk == NULL) { + return; // No dependencies to invalidate yet. + } + int marked = 0; + { + MutexLockerEx mu2(CodeCache_lock, Mutex::_no_safepoint_check_flag); + marked = ctxk->mark_dependent_nmethods(changes); + } + java_lang_invoke_CallSite::set_context_volatile(call_site(), NULL); // Reset call site to initial state + if (marked > 0) { + // At least one nmethod has been marked for deoptimization + VM_Deoptimize op; + VMThread::execute(&op); + } + } +} +JVM_END + /** * Throws a java/lang/UnsupportedOperationException unconditionally. * This is required by the specification of MethodHandle.invoke if @@ -1313,7 +1364,6 @@ {CC"init", CC"("MEM""OBJ")V", FN_PTR(MHN_init_Mem)}, {CC"expand", CC"("MEM")V", FN_PTR(MHN_expand_Mem)}, {CC"resolve", CC"("MEM""CLS")"MEM, FN_PTR(MHN_resolve_Mem)}, - {CC"getConstant", CC"(I)I", FN_PTR(MHN_getConstant)}, // static native int getNamedCon(int which, Object[] name) {CC"getNamedCon", CC"(I["OBJ")I", FN_PTR(MHN_getNamedCon)}, // static native int getMembers(Class defc, String matchName, String matchSig, @@ -1322,6 +1372,7 @@ {CC"objectFieldOffset", CC"("MEM")J", FN_PTR(MHN_objectFieldOffset)}, {CC"setCallSiteTargetNormal", CC"("CS""MH")V", FN_PTR(MHN_setCallSiteTargetNormal)}, {CC"setCallSiteTargetVolatile", CC"("CS""MH")V", FN_PTR(MHN_setCallSiteTargetVolatile)}, + {CC"invalidateDependentNMethods", CC"("CS")V", FN_PTR(MHN_invalidateDependentNMethods)}, {CC"staticFieldOffset", CC"("MEM")J", FN_PTR(MHN_staticFieldOffset)}, {CC"staticFieldBase", CC"("MEM")"OBJ, FN_PTR(MHN_staticFieldBase)}, {CC"getMemberVMInfo", CC"("MEM")"OBJ, FN_PTR(MHN_getMemberVMInfo)} diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/prims/methodHandles.hpp --- a/hotspot/src/share/vm/prims/methodHandles.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/prims/methodHandles.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,6 +68,9 @@ // bit values for suppress argument to expand_MemberName: enum { _suppress_defc = 1, _suppress_name = 2, _suppress_type = 4 }; + // CallSite support + static InstanceKlass* get_call_site_context(oop call_site); + // Generate MethodHandles adapters. static bool generate_adapters(); @@ -125,11 +128,6 @@ return signature_polymorphic_name_id(klass, name) != vmIntrinsics::_none; } - enum { - // format of query to getConstant: - GC_COUNT_GWT = 4, - GC_LAMBDA_SUPPORT = 5 - }; static int get_named_constant(int which, Handle name_box, TRAPS); public: @@ -243,10 +241,8 @@ #if INCLUDE_JVMTI // RedefineClasses() API support: - // If a MemberName refers to old_method then update it - // to refer to new_method. - void adjust_method_entries(Method** old_methods, Method** new_methods, - int methods_length, bool *trace_name_printed); + // If a MemberName refers to old_method then update it to refer to new_method. + void adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed); #endif // INCLUDE_JVMTI }; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/prims/unsafe.cpp --- a/hotspot/src/share/vm/prims/unsafe.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/prims/unsafe.cpp Thu May 07 20:51:12 2015 -0700 @@ -172,18 +172,6 @@ oop p = JNIHandles::resolve(obj); \ OrderAccess::release_store_fence((volatile type_name*)index_oop_from_field_offset_long(p, offset), x); -// Macros for oops that check UseCompressedOops - -#define GET_OOP_FIELD(obj, offset, v) \ - oop p = JNIHandles::resolve(obj); \ - oop v; \ - if (UseCompressedOops) { \ - narrowOop n = *(narrowOop*)index_oop_from_field_offset_long(p, offset); \ - v = oopDesc::decode_heap_oop(n); \ - } else { \ - v = *(oop*)index_oop_from_field_offset_long(p, offset); \ - } - // Get/SetObject must be special-cased, since it works with handles. @@ -192,7 +180,14 @@ // That is, it should be in the range [0, MAX_OBJECT_SIZE]. UNSAFE_ENTRY(jobject, Unsafe_GetObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) UnsafeWrapper("Unsafe_GetObject"); - GET_OOP_FIELD(obj, offset, v) + oop p = JNIHandles::resolve(obj); + oop v; + if (UseCompressedOops) { + narrowOop n = *(narrowOop*)index_oop_from_field_offset_long(p, offset); + v = oopDesc::decode_heap_oop(n); + } else { + v = *(oop*)index_oop_from_field_offset_long(p, offset); + } jobject ret = JNIHandles::make_local(env, v); #if INCLUDE_ALL_GCS // We could be accessing the referent field in a reference @@ -261,6 +256,25 @@ OrderAccess::fence(); UNSAFE_END +UNSAFE_ENTRY(jobject, Unsafe_GetUncompressedObject(JNIEnv *env, jobject unsafe, jlong addr)) + UnsafeWrapper("Unsafe_GetUncompressedObject"); + oop v = *(oop*) (address) addr; + return JNIHandles::make_local(env, v); +UNSAFE_END + +UNSAFE_ENTRY(jclass, Unsafe_GetJavaMirror(JNIEnv *env, jobject unsafe, jlong metaspace_klass)) + UnsafeWrapper("Unsafe_GetJavaMirror"); + Klass* klass = (Klass*) (address) metaspace_klass; + return (jclass) JNIHandles::make_local(klass->java_mirror()); +UNSAFE_END + +UNSAFE_ENTRY(jlong, Unsafe_GetKlassPointer(JNIEnv *env, jobject unsafe, jobject obj)) + UnsafeWrapper("Unsafe_GetKlassPointer"); + oop o = JNIHandles::resolve(obj); + jlong klass = (jlong) (address) o->klass(); + return klass; +UNSAFE_END + #ifndef SUPPORTS_NATIVE_CX8 // VM_Version::supports_cx8() is a surrogate for 'supports atomic long memory ops'. @@ -324,6 +338,24 @@ #endif // not SUPPORTS_NATIVE_CX8 +UNSAFE_ENTRY(jboolean, Unsafe_isBigEndian0(JNIEnv *env, jobject unsafe)) + UnsafeWrapper("Unsafe_IsBigEndian0"); + { +#ifdef VM_LITTLE_ENDIAN + return false; +#else + return true; +#endif + } +UNSAFE_END + +UNSAFE_ENTRY(jint, Unsafe_unalignedAccess0(JNIEnv *env, jobject unsafe)) + UnsafeWrapper("Unsafe_UnalignedAccess0"); + { + return UseUnalignedAccesses; + } +UNSAFE_END + #define DEFINE_GETSETOOP(jboolean, Boolean) \ \ UNSAFE_ENTRY(jboolean, Unsafe_Get##Boolean##140(JNIEnv *env, jobject unsafe, jobject obj, jint offset)) \ @@ -1204,6 +1236,10 @@ {CC"getObjectVolatile",CC"("OBJ"J)"OBJ"", FN_PTR(Unsafe_GetObjectVolatile)}, {CC"putObjectVolatile",CC"("OBJ"J"OBJ")V", FN_PTR(Unsafe_SetObjectVolatile)}, + {CC"getUncompressedObject", CC"("ADR")"OBJ, FN_PTR(Unsafe_GetUncompressedObject)}, + {CC"getJavaMirror", CC"("ADR")"CLS, FN_PTR(Unsafe_GetJavaMirror)}, + {CC"getKlassPointer", CC"("OBJ")"ADR, FN_PTR(Unsafe_GetKlassPointer)}, + DECLARE_GETPUTOOP(Boolean, Z), DECLARE_GETPUTOOP(Byte, B), DECLARE_GETPUTOOP(Short, S), @@ -1261,6 +1297,9 @@ {CC"loadFence", CC"()V", FN_PTR(Unsafe_LoadFence)}, {CC"storeFence", CC"()V", FN_PTR(Unsafe_StoreFence)}, {CC"fullFence", CC"()V", FN_PTR(Unsafe_FullFence)}, + + {CC"isBigEndian0", CC"()Z", FN_PTR(Unsafe_isBigEndian0)}, + {CC"unalignedAccess0", CC"()Z", FN_PTR(Unsafe_unalignedAccess0)} }; #undef CC diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/prims/whitebox.cpp --- a/hotspot/src/share/vm/prims/whitebox.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/prims/whitebox.cpp Thu May 07 20:51:12 2015 -0700 @@ -89,6 +89,10 @@ return os::vm_page_size(); WB_END +WB_ENTRY(jlong, WB_GetVMLargePageSize(JNIEnv* env, jobject o)) + return os::large_page_size(); +WB_END + class WBIsKlassAliveClosure : public KlassClosure { Symbol* _name; bool _found; @@ -819,46 +823,9 @@ mo.notify_all(); WB_END -void WhiteBox::sweeper_thread_entry(JavaThread* thread, TRAPS) { - guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to be enabled"); - { - MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - NMethodSweeper::_should_sweep = true; - } - NMethodSweeper::possibly_sweep(); -} - -JavaThread* WhiteBox::create_sweeper_thread(TRAPS) { - // create sweeper thread w/ custom entry -- one iteration instead of loop - CodeCacheSweeperThread* sweeper_thread = new CodeCacheSweeperThread(); - sweeper_thread->set_entry_point(&WhiteBox::sweeper_thread_entry); - - // create j.l.Thread object and associate it w/ sweeper thread - { - // inherit deamon property from current thread - bool is_daemon = java_lang_Thread::is_daemon(JavaThread::current()->threadObj()); - - HandleMark hm(THREAD); - Handle thread_group(THREAD, Universe::system_thread_group()); - const char* name = "WB Sweeper thread"; - sweeper_thread->allocate_threadObj(thread_group, name, is_daemon, THREAD); - } - - { - MutexLocker mu(Threads_lock, THREAD); - Threads::add(sweeper_thread); - } - return sweeper_thread; -} - -WB_ENTRY(jobject, WB_ForceNMethodSweep(JNIEnv* env, jobject o)) - JavaThread* sweeper_thread = WhiteBox::create_sweeper_thread(Thread::current()); - if (sweeper_thread == NULL) { - return NULL; - } - jobject result = JNIHandles::make_local(env, sweeper_thread->threadObj()); - Thread::start(sweeper_thread); - return result; +WB_ENTRY(void, WB_ForceNMethodSweep(JNIEnv* env, jobject o)) + // Force a code cache sweep and block until it finished + NMethodSweeper::force_sweep(); WB_END WB_ENTRY(jboolean, WB_IsInStringTable(JNIEnv* env, jobject o, jstring javaString)) @@ -1234,7 +1201,7 @@ if (res == NULL) { tty->print_cr("Invalid layout of %s at %s", ik->external_name(), name_symbol->as_C_string()); - fatal("Invalid layout of preloaded class"); + vm_exit_during_initialization("Invalid layout of preloaded class: use -XX:+TraceClassLoading to see the origin of the problem class"); } //fetch the field at the offset we've found @@ -1296,19 +1263,20 @@ #define CC (char*) static JNINativeMethod methods[] = { - {CC"getObjectAddress", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectAddress }, - {CC"getObjectSize", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectSize }, - {CC"isObjectInOldGen", CC"(Ljava/lang/Object;)Z", (void*)&WB_isObjectInOldGen }, + {CC"getObjectAddress0", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectAddress }, + {CC"getObjectSize0", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectSize }, + {CC"isObjectInOldGen0", CC"(Ljava/lang/Object;)Z", (void*)&WB_isObjectInOldGen }, {CC"getHeapOopSize", CC"()I", (void*)&WB_GetHeapOopSize }, {CC"getVMPageSize", CC"()I", (void*)&WB_GetVMPageSize }, + {CC"getVMLargePageSize", CC"()J", (void*)&WB_GetVMLargePageSize}, {CC"isClassAlive0", CC"(Ljava/lang/String;)Z", (void*)&WB_IsClassAlive }, - {CC"parseCommandLine", + {CC"parseCommandLine0", CC"(Ljava/lang/String;C[Lsun/hotspot/parser/DiagnosticCommand;)[Ljava/lang/Object;", (void*) &WB_ParseCommandLine }, - {CC"addToBootstrapClassLoaderSearch", CC"(Ljava/lang/String;)V", + {CC"addToBootstrapClassLoaderSearch0", CC"(Ljava/lang/String;)V", (void*)&WB_AddToBootstrapClassLoaderSearch}, - {CC"addToSystemClassLoaderSearch", CC"(Ljava/lang/String;)V", + {CC"addToSystemClassLoaderSearch0", CC"(Ljava/lang/String;)V", (void*)&WB_AddToSystemClassLoaderSearch}, {CC"getCompressedOopsMaxHeapSize", CC"()J", (void*)&WB_GetCompressedOopsMaxHeapSize}, @@ -1318,7 +1286,7 @@ {CC"stressVirtualSpaceResize",CC"(JJJ)I", (void*)&WB_StressVirtualSpaceResize}, #if INCLUDE_ALL_GCS {CC"g1InConcurrentMark", CC"()Z", (void*)&WB_G1InConcurrentMark}, - {CC"g1IsHumongous", CC"(Ljava/lang/Object;)Z", (void*)&WB_G1IsHumongous }, + {CC"g1IsHumongous0", CC"(Ljava/lang/Object;)Z", (void*)&WB_G1IsHumongous }, {CC"g1NumMaxRegions", CC"()J", (void*)&WB_G1NumMaxRegions }, {CC"g1NumFreeRegions", CC"()J", (void*)&WB_G1NumFreeRegions }, {CC"g1RegionSize", CC"()I", (void*)&WB_G1RegionSize }, @@ -1339,29 +1307,29 @@ #endif // INCLUDE_NMT {CC"deoptimizeFrames", CC"(Z)I", (void*)&WB_DeoptimizeFrames }, {CC"deoptimizeAll", CC"()V", (void*)&WB_DeoptimizeAll }, - {CC"deoptimizeMethod", CC"(Ljava/lang/reflect/Executable;Z)I", + {CC"deoptimizeMethod0", CC"(Ljava/lang/reflect/Executable;Z)I", (void*)&WB_DeoptimizeMethod }, - {CC"isMethodCompiled", CC"(Ljava/lang/reflect/Executable;Z)Z", + {CC"isMethodCompiled0", CC"(Ljava/lang/reflect/Executable;Z)Z", (void*)&WB_IsMethodCompiled }, - {CC"isMethodCompilable", CC"(Ljava/lang/reflect/Executable;IZ)Z", + {CC"isMethodCompilable0", CC"(Ljava/lang/reflect/Executable;IZ)Z", (void*)&WB_IsMethodCompilable}, - {CC"isMethodQueuedForCompilation", + {CC"isMethodQueuedForCompilation0", CC"(Ljava/lang/reflect/Executable;)Z", (void*)&WB_IsMethodQueuedForCompilation}, - {CC"makeMethodNotCompilable", + {CC"makeMethodNotCompilable0", CC"(Ljava/lang/reflect/Executable;IZ)V", (void*)&WB_MakeMethodNotCompilable}, - {CC"testSetDontInlineMethod", + {CC"testSetDontInlineMethod0", CC"(Ljava/lang/reflect/Executable;Z)Z", (void*)&WB_TestSetDontInlineMethod}, - {CC"getMethodCompilationLevel", + {CC"getMethodCompilationLevel0", CC"(Ljava/lang/reflect/Executable;Z)I", (void*)&WB_GetMethodCompilationLevel}, - {CC"getMethodEntryBci", + {CC"getMethodEntryBci0", CC"(Ljava/lang/reflect/Executable;)I", (void*)&WB_GetMethodEntryBci}, {CC"getCompileQueueSize", CC"(I)I", (void*)&WB_GetCompileQueueSize}, - {CC"testSetForceInlineMethod", + {CC"testSetForceInlineMethod0", CC"(Ljava/lang/reflect/Executable;Z)Z", (void*)&WB_TestSetForceInlineMethod}, - {CC"enqueueMethodForCompilation", + {CC"enqueueMethodForCompilation0", CC"(Ljava/lang/reflect/Executable;II)Z", (void*)&WB_EnqueueMethodForCompilation}, - {CC"clearMethodState", + {CC"clearMethodState0", CC"(Ljava/lang/reflect/Executable;)V", (void*)&WB_ClearMethodState}, {CC"lockCompilation", CC"()V", (void*)&WB_LockCompilation}, {CC"unlockCompilation", CC"()V", (void*)&WB_UnlockCompilation}, @@ -1400,9 +1368,9 @@ {CC"incMetaspaceCapacityUntilGC", CC"(J)J", (void*)&WB_IncMetaspaceCapacityUntilGC }, {CC"metaspaceCapacityUntilGC", CC"()J", (void*)&WB_MetaspaceCapacityUntilGC }, {CC"getCPUFeatures", CC"()Ljava/lang/String;", (void*)&WB_GetCPUFeatures }, - {CC"getNMethod", CC"(Ljava/lang/reflect/Executable;Z)[Ljava/lang/Object;", + {CC"getNMethod0", CC"(Ljava/lang/reflect/Executable;Z)[Ljava/lang/Object;", (void*)&WB_GetNMethod }, - {CC"forceNMethodSweep0", CC"()Ljava/lang/Thread;", (void*)&WB_ForceNMethodSweep }, + {CC"forceNMethodSweep", CC"()V", (void*)&WB_ForceNMethodSweep }, {CC"allocateCodeBlob", CC"(II)J", (void*)&WB_AllocateCodeBlob }, {CC"freeCodeBlob", CC"(J)V", (void*)&WB_FreeCodeBlob }, {CC"getCodeHeapEntries", CC"(I)[Ljava/lang/Object;",(void*)&WB_GetCodeHeapEntries }, @@ -1412,7 +1380,7 @@ {CC"getThreadStackSize", CC"()J", (void*)&WB_GetThreadStackSize }, {CC"getThreadRemainingStackSize", CC"()J", (void*)&WB_GetThreadRemainingStackSize }, {CC"assertMatchingSafepointCalls", CC"(ZZ)V", (void*)&WB_AssertMatchingSafepointCalls }, - {CC"isMonitorInflated", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsMonitorInflated }, + {CC"isMonitorInflated0", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsMonitorInflated }, {CC"forceSafepoint", CC"()V", (void*)&WB_ForceSafepoint }, {CC"getMethodBooleanOption", CC"(Ljava/lang/reflect/Executable;Ljava/lang/String;)Ljava/lang/Boolean;", diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/prims/whitebox.hpp --- a/hotspot/src/share/vm/prims/whitebox.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/prims/whitebox.hpp Thu May 07 20:51:12 2015 -0700 @@ -70,8 +70,6 @@ Symbol* signature_symbol); static const char* lookup_jstring(const char* field_name, oop object); static bool lookup_bool(const char* field_name, oop object); - static void sweeper_thread_entry(JavaThread* thread, TRAPS); - static JavaThread* create_sweeper_thread(TRAPS); static int get_blob_type(const CodeBlob* code); static CodeHeap* get_code_heap(int blob_type); static CodeBlob* allocate_code_blob(int size, int blob_type); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/arguments.cpp --- a/hotspot/src/share/vm/runtime/arguments.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/runtime/arguments.cpp Thu May 07 20:51:12 2015 -0700 @@ -92,6 +92,8 @@ bool Arguments::_UseOnStackReplacement = UseOnStackReplacement; bool Arguments::_BackgroundCompilation = BackgroundCompilation; bool Arguments::_ClipInlining = ClipInlining; +intx Arguments::_Tier3InvokeNotifyFreqLog = Tier3InvokeNotifyFreqLog; +intx Arguments::_Tier4InvocationThreshold = Tier4InvocationThreshold; char* Arguments::SharedArchivePath = NULL; @@ -240,6 +242,9 @@ * and ignoring the value. Once the JDK version reaches the 'accept_until' * limit, we flatly refuse to admit the existence of the flag. This allows * a flag to die correctly over JDK releases using HSX. + * But now that HSX is no longer supported only options with a future + * accept_until value need to be listed, and the list can be pruned + * on each major release. */ typedef struct { const char* name; @@ -248,63 +253,8 @@ } ObsoleteFlag; static ObsoleteFlag obsolete_jvm_flags[] = { - { "UseTrainGC", JDK_Version::jdk(5), JDK_Version::jdk(7) }, - { "UseSpecialLargeObjectHandling", JDK_Version::jdk(5), JDK_Version::jdk(7) }, - { "UseOversizedCarHandling", JDK_Version::jdk(5), JDK_Version::jdk(7) }, - { "TraceCarAllocation", JDK_Version::jdk(5), JDK_Version::jdk(7) }, - { "PrintTrainGCProcessingStats", JDK_Version::jdk(5), JDK_Version::jdk(7) }, - { "LogOfCarSpaceSize", JDK_Version::jdk(5), JDK_Version::jdk(7) }, - { "OversizedCarThreshold", JDK_Version::jdk(5), JDK_Version::jdk(7) }, - { "MinTickInterval", JDK_Version::jdk(5), JDK_Version::jdk(7) }, - { "DefaultTickInterval", JDK_Version::jdk(5), JDK_Version::jdk(7) }, - { "MaxTickInterval", JDK_Version::jdk(5), JDK_Version::jdk(7) }, - { "DelayTickAdjustment", JDK_Version::jdk(5), JDK_Version::jdk(7) }, - { "ProcessingToTenuringRatio", JDK_Version::jdk(5), JDK_Version::jdk(7) }, - { "MinTrainLength", JDK_Version::jdk(5), JDK_Version::jdk(7) }, - { "AppendRatio", JDK_Version::jdk_update(6,10), JDK_Version::jdk(7) }, - { "DefaultMaxRAM", JDK_Version::jdk_update(6,18), JDK_Version::jdk(7) }, - { "DefaultInitialRAMFraction", - JDK_Version::jdk_update(6,18), JDK_Version::jdk(7) }, - { "UseDepthFirstScavengeOrder", - JDK_Version::jdk_update(6,22), JDK_Version::jdk(7) }, - { "HandlePromotionFailure", - JDK_Version::jdk_update(6,24), JDK_Version::jdk(8) }, - { "MaxLiveObjectEvacuationRatio", - JDK_Version::jdk_update(6,24), JDK_Version::jdk(8) }, - { "ForceSharedSpaces", JDK_Version::jdk_update(6,25), JDK_Version::jdk(8) }, - { "UseParallelOldGCCompacting", - JDK_Version::jdk_update(6,27), JDK_Version::jdk(8) }, - { "UseParallelDensePrefixUpdate", - JDK_Version::jdk_update(6,27), JDK_Version::jdk(8) }, - { "UseParallelOldGCDensePrefix", - JDK_Version::jdk_update(6,27), JDK_Version::jdk(8) }, - { "AllowTransitionalJSR292", JDK_Version::jdk(7), JDK_Version::jdk(8) }, - { "UseCompressedStrings", JDK_Version::jdk(7), JDK_Version::jdk(8) }, - { "CMSPermGenPrecleaningEnabled", JDK_Version::jdk(8), JDK_Version::jdk(9) }, - { "CMSTriggerPermRatio", JDK_Version::jdk(8), JDK_Version::jdk(9) }, - { "CMSInitiatingPermOccupancyFraction", JDK_Version::jdk(8), JDK_Version::jdk(9) }, - { "AdaptivePermSizeWeight", JDK_Version::jdk(8), JDK_Version::jdk(9) }, - { "PermGenPadding", JDK_Version::jdk(8), JDK_Version::jdk(9) }, - { "PermMarkSweepDeadRatio", JDK_Version::jdk(8), JDK_Version::jdk(9) }, - { "PermSize", JDK_Version::jdk(8), JDK_Version::jdk(9) }, - { "MaxPermSize", JDK_Version::jdk(8), JDK_Version::jdk(9) }, - { "MinPermHeapExpansion", JDK_Version::jdk(8), JDK_Version::jdk(9) }, - { "MaxPermHeapExpansion", JDK_Version::jdk(8), JDK_Version::jdk(9) }, - { "CMSRevisitStackSize", JDK_Version::jdk(8), JDK_Version::jdk(9) }, - { "PrintRevisitStats", JDK_Version::jdk(8), JDK_Version::jdk(9) }, - { "UseVectoredExceptions", JDK_Version::jdk(8), JDK_Version::jdk(9) }, - { "UseSplitVerifier", JDK_Version::jdk(8), JDK_Version::jdk(9) }, - { "UseISM", JDK_Version::jdk(8), JDK_Version::jdk(9) }, - { "UsePermISM", JDK_Version::jdk(8), JDK_Version::jdk(9) }, - { "UseMPSS", JDK_Version::jdk(8), JDK_Version::jdk(9) }, - { "UseStringCache", JDK_Version::jdk(8), JDK_Version::jdk(9) }, { "UseOldInlining", JDK_Version::jdk(9), JDK_Version::jdk(10) }, { "SafepointPollOffset", JDK_Version::jdk(9), JDK_Version::jdk(10) }, -#ifdef PRODUCT - { "DesiredMethodLimit", - JDK_Version::jdk_update(7, 2), JDK_Version::jdk(8) }, -#endif // PRODUCT - { "UseVMInterruptibleIO", JDK_Version::jdk(8), JDK_Version::jdk(9) }, { "UseBoundThreads", JDK_Version::jdk(9), JDK_Version::jdk(10) }, { "DefaultThreadPriority", JDK_Version::jdk(9), JDK_Version::jdk(10) }, { "NoYieldsInMicrolock", JDK_Version::jdk(9), JDK_Version::jdk(10) }, @@ -338,11 +288,8 @@ // =xxx form // [-|+] form size_t len = strlen(flag_status.name); - if (((strncmp(flag_status.name, s, len) == 0) && - (strlen(s) == len)) || - ((s[0] == '+' || s[0] == '-') && - (strncmp(flag_status.name, &s[1], len) == 0) && - (strlen(&s[1]) == len))) { + if ((strncmp(flag_status.name, s, len) == 0) && + (strlen(s) == len)){ if (JDK_Version::current().compare(flag_status.accept_until) == -1) { *version = flag_status.obsoleted_in; return true; @@ -858,17 +805,9 @@ return true; } + // Determine if the flag has '+', '-', or '=' characters. bool has_plus_minus = (*arg == '+' || *arg == '-'); const char* const argname = has_plus_minus ? arg + 1 : arg; - if (is_newly_obsolete(arg, &since)) { - char version[256]; - since.to_string(version, sizeof(version)); - warning("ignoring option %s; support was removed in %s", argname, version); - return true; - } - - // For locked flags, report a custom error message if available. - // Otherwise, report the standard unrecognized VM option. size_t arg_len; const char* equal_sign = strchr(argname, '='); @@ -878,6 +817,20 @@ arg_len = equal_sign - argname; } + // Construct a string which consists only of the argument name without '+', '-', or '='. + char stripped_argname[256]; + strncpy(stripped_argname, argname, arg_len); + stripped_argname[arg_len] = '\0'; //strncpy doesn't null terminate. + + if (is_newly_obsolete(stripped_argname, &since)) { + char version[256]; + since.to_string(version, sizeof(version)); + warning("ignoring option %s; support was removed in %s", stripped_argname, version); + return true; + } + + // For locked flags, report a custom error message if available. + // Otherwise, report the standard unrecognized VM option. Flag* found_flag = Flag::find_flag((const char*)argname, arg_len, true, true); if (found_flag != NULL) { char locked_message_buf[BUFLEN]; @@ -906,16 +859,8 @@ (fuzzy_matched->is_bool()) ? "(+/-)" : "", fuzzy_matched->_name, (fuzzy_matched->is_bool()) ? "" : "="); - if (is_newly_obsolete(fuzzy_matched->_name, &since)) { - char version[256]; - since.to_string(version, sizeof(version)); - jio_fprintf(defaultStream::error_stream(), - "Warning: support for %s was removed in %s\n", - fuzzy_matched->_name, - version); } } - } // allow for commandline "commenting out" options like -XX:#+Verbose return arg[0] == '#'; @@ -1069,6 +1014,14 @@ AlwaysCompileLoopMethods = Arguments::_AlwaysCompileLoopMethods; UseOnStackReplacement = Arguments::_UseOnStackReplacement; BackgroundCompilation = Arguments::_BackgroundCompilation; + if (TieredCompilation) { + if (FLAG_IS_DEFAULT(Tier3InvokeNotifyFreqLog)) { + Tier3InvokeNotifyFreqLog = Arguments::_Tier3InvokeNotifyFreqLog; + } + if (FLAG_IS_DEFAULT(Tier4InvocationThreshold)) { + Tier4InvocationThreshold = Arguments::_Tier4InvocationThreshold; + } + } // Change from defaults based on mode switch (mode) { @@ -1607,12 +1560,15 @@ } else { FLAG_SET_ERGO(bool, UseParallelGC, true); } + } else { + FLAG_SET_ERGO(bool, UseSerialGC, true); } } void Arguments::select_gc() { if (!gc_selected()) { select_gc_ergonomically(); + guarantee(gc_selected(), "No GC selected"); } } @@ -1900,15 +1856,8 @@ } } -// This must be called after ergonomics because we want bytecode rewriting -// if the server compiler is used, or if UseSharedSpaces is disabled. +// This must be called after ergonomics. void Arguments::set_bytecode_flags() { - // Better not attempt to store into a read-only space. - if (UseSharedSpaces) { - FLAG_SET_DEFAULT(RewriteBytecodes, false); - FLAG_SET_DEFAULT(RewriteFrequentPairs, false); - } - if (!RewriteBytecodes) { FLAG_SET_DEFAULT(RewriteFrequentPairs, false); } @@ -2145,10 +2094,8 @@ } if (UseParNewGC && !UseConcMarkSweepGC) { - // !UseConcMarkSweepGC means that we are using serial old gc. Unfortunately we don't - // set up UseSerialGC properly, so that can't be used in the check here. jio_fprintf(defaultStream::error_stream(), - "It is not possible to combine the ParNew young collector with the Serial old collector.\n"); + "It is not possible to combine the ParNew young collector with any collector other than CMS.\n"); return false; } @@ -2589,6 +2536,10 @@ Arguments::_UseOnStackReplacement = UseOnStackReplacement; Arguments::_ClipInlining = ClipInlining; Arguments::_BackgroundCompilation = BackgroundCompilation; + if (TieredCompilation) { + Arguments::_Tier3InvokeNotifyFreqLog = Tier3InvokeNotifyFreqLog; + Arguments::_Tier4InvocationThreshold = Tier4InvocationThreshold; + } // Setup flags for mixed which is the default set_mode_flags(_mixed); @@ -2764,7 +2715,7 @@ char *options = NULL; if(pos != NULL) { - options = strcpy(NEW_C_HEAP_ARRAY(char, strlen(pos + 1) + 1, mtInternal), pos + 1); + options = os::strdup_check_oom(pos + 1, mtInternal); } #if !INCLUDE_JVMTI if (valid_hprof_or_jdwp_agent(name, is_absolute_path)) { @@ -3070,8 +3021,7 @@ } else if (match_option(option, "-Xnoagent")) { // For compatibility with classic. HotSpot refuses to load the old style agent.dll. } else if (match_option(option, "-Xboundthreads")) { - // Bind user level threads to kernel threads (Solaris only) - FLAG_SET_CMDLINE(bool, UseBoundThreads, true); + // Ignore silently for compatibility } else if (match_option(option, "-Xloggc:", &tail)) { // Redirect GC output to the file. -Xloggc: // ostream_init_log(), when called will use this filename @@ -3150,7 +3100,7 @@ FLAG_SET_CMDLINE(size_t, MaxNewSize, NewSize); } -#ifndef _ALLBSD_SOURCE // UseLargePages is not yet supported on BSD. +#if !defined(_ALLBSD_SOURCE) && !defined(AIX) // UseLargePages is not yet supported on BSD and AIX. FLAG_SET_DEFAULT(UseLargePages, true); #endif @@ -3209,7 +3159,8 @@ uintx max_tenuring_thresh = 0; if(!parse_uintx(tail, &max_tenuring_thresh, 0)) { jio_fprintf(defaultStream::error_stream(), - "Invalid MaxTenuringThreshold: %s\n", option->optionString); + "Improperly specified VM option 'MaxTenuringThreshold=%s'\n", tail); + return JNI_EINVAL; } FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, max_tenuring_thresh); @@ -3300,6 +3251,15 @@ "ManagementServer is not supported in this VM.\n"); return JNI_ERR; #endif // INCLUDE_MANAGEMENT + // CreateMinidumpOnCrash is removed, and replaced by CreateCoredumpOnCrash + } else if (match_option(option, "-XX:+CreateMinidumpOnCrash")) { + FLAG_SET_CMDLINE(bool, CreateCoredumpOnCrash, true); + jio_fprintf(defaultStream::output_stream(), + "CreateMinidumpOnCrash is replaced by CreateCoredumpOnCrash: CreateCoredumpOnCrash is on\n"); + } else if (match_option(option, "-XX:-CreateMinidumpOnCrash")) { + FLAG_SET_CMDLINE(bool, CreateCoredumpOnCrash, false); + jio_fprintf(defaultStream::output_stream(), + "CreateMinidumpOnCrash is replaced by CreateCoredumpOnCrash: CreateCoredumpOnCrash is off\n"); } else if (match_option(option, "-XX:", &tail)) { // -XX:xxxx // Skip -XX:Flags= since that case has already been handled if (strncmp(tail, "Flags=", strlen("Flags=")) != 0) { @@ -3355,8 +3315,7 @@ src ++; } - char* copy = AllocateHeap(strlen(src) + 1, mtInternal); - strncpy(copy, src, strlen(src) + 1); + char* copy = os::strdup_check_oom(src, mtInternal); // trim all trailing empty paths for (char* tail = copy + strlen(copy) - 1; tail >= copy && *tail == separator; tail--) { @@ -3514,15 +3473,14 @@ if (os::is_headless_jre()) { const char* headless = Arguments::get_property("java.awt.headless"); if (headless == NULL) { - char envbuffer[128]; - if (!os::getenv("JAVA_AWT_HEADLESS", envbuffer, sizeof(envbuffer))) { + const char *headless_env = ::getenv("JAVA_AWT_HEADLESS"); + if (headless_env == NULL) { if (!add_property("java.awt.headless=true")) { return JNI_ENOMEM; } } else { char buffer[256]; - strcpy(buffer, "java.awt.headless="); - strcat(buffer, envbuffer); + jio_snprintf(buffer, sizeof(buffer), "java.awt.headless=%s", headless_env); if (!add_property(buffer)) { return JNI_ENOMEM; } @@ -3553,75 +3511,95 @@ } jint Arguments::parse_options_environment_variable(const char* name, SysClassPath* scp_p, bool* scp_assembly_required_p) { - const int N_MAX_OPTIONS = 64; - const int OPTION_BUFFER_SIZE = 1024; - char buffer[OPTION_BUFFER_SIZE]; - - // The variable will be ignored if it exceeds the length of the buffer. + char *buffer = ::getenv(name); + // Don't check this variable if user has special privileges // (e.g. unix su command). - if (os::getenv(name, buffer, sizeof(buffer)) && - !os::have_special_privileges()) { - JavaVMOption options[N_MAX_OPTIONS]; // Construct option array - jio_fprintf(defaultStream::error_stream(), - "Picked up %s: %s\n", name, buffer); - char* rd = buffer; // pointer to the input string (rd) - int i; - for (i = 0; i < N_MAX_OPTIONS;) { // repeat for all options in the input string - while (isspace(*rd)) rd++; // skip whitespace - if (*rd == 0) break; // we re done when the input string is read completely - - // The output, option string, overwrites the input string. - // Because of quoting, the pointer to the option string (wrt) may lag the pointer to - // input string (rd). - char* wrt = rd; - - options[i++].optionString = wrt; // Fill in option - while (*rd != 0 && !isspace(*rd)) { // unquoted strings terminate with a space or NULL - if (*rd == '\'' || *rd == '"') { // handle a quoted string - int quote = *rd; // matching quote to look for - rd++; // don't copy open quote - while (*rd != quote) { // include everything (even spaces) up until quote - if (*rd == 0) { // string termination means unmatched string - jio_fprintf(defaultStream::error_stream(), - "Unmatched quote in %s\n", name); - return JNI_ERR; - } - *wrt++ = *rd++; // copy to option string + if (buffer == NULL || os::have_special_privileges()) { + return JNI_OK; + } + + if ((buffer = os::strdup(buffer)) == NULL) { + return JNI_ENOMEM; + } + + GrowableArray *options = new (ResourceObj::C_HEAP, mtInternal) GrowableArray(2, true); // Construct option array + jio_fprintf(defaultStream::error_stream(), + "Picked up %s: %s\n", name, buffer); + char* rd = buffer; // pointer to the input string (rd) + while (true) { // repeat for all options in the input string + while (isspace(*rd)) rd++; // skip whitespace + if (*rd == 0) break; // we re done when the input string is read completely + + // The output, option string, overwrites the input string. + // Because of quoting, the pointer to the option string (wrt) may lag the pointer to + // input string (rd). + char* wrt = rd; + + JavaVMOption option; + option.optionString = wrt; + options->append(option); // Fill in option + while (*rd != 0 && !isspace(*rd)) { // unquoted strings terminate with a space or NULL + if (*rd == '\'' || *rd == '"') { // handle a quoted string + int quote = *rd; // matching quote to look for + rd++; // don't copy open quote + while (*rd != quote) { // include everything (even spaces) up until quote + if (*rd == 0) { // string termination means unmatched string + jio_fprintf(defaultStream::error_stream(), + "Unmatched quote in %s\n", name); + delete options; + os::free(buffer); + return JNI_ERR; } - rd++; // don't copy close quote - } else { - *wrt++ = *rd++; // copy to option string + *wrt++ = *rd++; // copy to option string } - } - // Need to check if we're done before writing a NULL, - // because the write could be to the byte that rd is pointing to. - if (*rd++ == 0) { - *wrt = 0; - break; - } - *wrt = 0; // Zero terminate option - } - // Construct JavaVMInitArgs structure and parse as if it was part of the command line - JavaVMInitArgs vm_args; - vm_args.version = JNI_VERSION_1_2; - vm_args.options = options; - vm_args.nOptions = i; - vm_args.ignoreUnrecognized = IgnoreUnrecognizedVMOptions; - - if (PrintVMOptions) { - const char* tail; - for (int i = 0; i < vm_args.nOptions; i++) { - const JavaVMOption *option = vm_args.options + i; - if (match_option(option, "-XX:", &tail)) { - logOption(tail); - } + rd++; // don't copy close quote + } else { + *wrt++ = *rd++; // copy to option string } } - - return(parse_each_vm_init_arg(&vm_args, scp_p, scp_assembly_required_p, Flag::ENVIRON_VAR)); + // Need to check if we're done before writing a NULL, + // because the write could be to the byte that rd is pointing to. + if (*rd++ == 0) { + *wrt = 0; + break; + } + *wrt = 0; // Zero terminate option + } + JavaVMOption* options_arr = + NEW_C_HEAP_ARRAY_RETURN_NULL(JavaVMOption, options->length(), mtInternal); + if (options_arr == NULL) { + delete options; + os::free(buffer); + return JNI_ENOMEM; + } + for (int i = 0; i < options->length(); i++) { + options_arr[i] = options->at(i); } - return JNI_OK; + + // Construct JavaVMInitArgs structure and parse as if it was part of the command line + JavaVMInitArgs vm_args; + vm_args.version = JNI_VERSION_1_2; + vm_args.options = options_arr; + vm_args.nOptions = options->length(); + vm_args.ignoreUnrecognized = IgnoreUnrecognizedVMOptions; + + if (PrintVMOptions) { + const char* tail; + for (int i = 0; i < vm_args.nOptions; i++) { + const JavaVMOption *option = vm_args.options + i; + if (match_option(option, "-XX:", &tail)) { + logOption(tail); + } + } + } + + jint result = parse_each_vm_init_arg(&vm_args, scp_p, scp_assembly_required_p, + Flag::ENVIRON_VAR); + FREE_C_HEAP_ARRAY(JavaVMOption, options_arr); + delete options; + os::free(buffer); + return result; } void Arguments::set_shared_spaces_flags() { @@ -3665,18 +3643,14 @@ if (end != NULL) *end = '\0'; size_t jvm_path_len = strlen(jvm_path); size_t file_sep_len = strlen(os::file_separator()); - shared_archive_path = NEW_C_HEAP_ARRAY(char, jvm_path_len + - file_sep_len + 20, mtInternal); + const size_t len = jvm_path_len + file_sep_len + 20; + shared_archive_path = NEW_C_HEAP_ARRAY(char, len, mtInternal); if (shared_archive_path != NULL) { - strncpy(shared_archive_path, jvm_path, jvm_path_len + 1); - strncat(shared_archive_path, os::file_separator(), file_sep_len); - strncat(shared_archive_path, "classes.jsa", 11); + jio_snprintf(shared_archive_path, len, "%s%sclasses.jsa", + jvm_path, os::file_separator()); } } else { - shared_archive_path = NEW_C_HEAP_ARRAY(char, strlen(SharedArchiveFile) + 1, mtInternal); - if (shared_archive_path != NULL) { - strncpy(shared_archive_path, SharedArchiveFile, strlen(SharedArchiveFile) + 1); - } + shared_archive_path = os::strdup_check_oom(SharedArchiveFile, mtInternal); } return shared_archive_path; } @@ -3752,8 +3726,8 @@ CommandLineFlags::printFlags(tty, false); vm_exit(0); } + if (match_option(option, "-XX:NativeMemoryTracking", &tail)) { #if INCLUDE_NMT - if (match_option(option, "-XX:NativeMemoryTracking", &tail)) { // The launcher did not setup nmt environment variable properly. if (!MemTracker::check_launcher_nmt_support(tail)) { warning("Native Memory Tracking did not setup properly, using wrong launcher?"); @@ -3769,9 +3743,12 @@ vm_exit_during_initialization("Syntax error, expecting -XX:NativeMemoryTracking=[off|summary|detail]", NULL); } continue; - } +#else + jio_fprintf(defaultStream::error_stream(), + "Native Memory Tracking is not supported in this VM\n"); + return JNI_ERR; #endif - + } #ifndef PRODUCT if (match_option(option, "-XX:+PrintFlagsWithComments")) { @@ -3839,7 +3816,7 @@ hotspotrc, hotspotrc); } -#ifdef _ALLBSD_SOURCE // UseLargePages is not yet supported on BSD. +#if defined(_ALLBSD_SOURCE) || defined(AIX) // UseLargePages is not yet supported on BSD and AIX. UNSUPPORTED_OPTION(UseLargePages, "-XX:+UseLargePages"); #endif diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/arguments.hpp --- a/hotspot/src/share/vm/runtime/arguments.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/runtime/arguments.hpp Thu May 07 20:51:12 2015 -0700 @@ -323,6 +323,8 @@ static bool _BackgroundCompilation; static bool _ClipInlining; static bool _CIDynamicCompilePriority; + static intx _Tier3InvokeNotifyFreqLog; + static intx _Tier4InvocationThreshold; // Tiered static void set_tiered_flags(); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/deoptimization.cpp --- a/hotspot/src/share/vm/runtime/deoptimization.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/runtime/deoptimization.cpp Thu May 07 20:51:12 2015 -0700 @@ -1861,6 +1861,7 @@ "speculate_null_check", "rtm_state_change", "unstable_if", + "unstable_fused_if", "tenured" }; const char* Deoptimization::_trap_action_name[] = { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/deoptimization.hpp --- a/hotspot/src/share/vm/runtime/deoptimization.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/runtime/deoptimization.hpp Thu May 07 20:51:12 2015 -0700 @@ -63,6 +63,7 @@ Reason_speculate_null_check, // saw unexpected null from type speculation Reason_rtm_state_change, // rtm state change detected Reason_unstable_if, // a branch predicted always false was taken + Reason_unstable_fused_if, // fused two ifs that had each one untaken branch. One is now taken. // Reason_tenured is counted separately, add normal counted Reasons above. // Related to MethodData::_trap_hist_limit where Reason_tenured isn't included @@ -326,6 +327,8 @@ return Reason_null_check; else if (reason == Reason_unstable_if) return Reason_intrinsic; + else if (reason == Reason_unstable_fused_if) + return Reason_range_check; else return Reason_none; } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/frame.cpp --- a/hotspot/src/share/vm/runtime/frame.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/runtime/frame.cpp Thu May 07 20:51:12 2015 -0700 @@ -1104,9 +1104,9 @@ // call f() on the interpreted Method*s in the stack. // Have to walk the entire code cache for the compiled frames Yuck. void frame::metadata_do(void f(Metadata*)) { - if (_cb != NULL && Interpreter::contains(pc())) { + if (is_interpreted_frame()) { Method* m = this->interpreter_frame_method(); - assert(m != NULL, "huh?"); + assert(m != NULL, "expecting a method in this frame"); f(m); } } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/globals.hpp --- a/hotspot/src/share/vm/runtime/globals.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/runtime/globals.hpp Thu May 07 20:51:12 2015 -0700 @@ -677,9 +677,6 @@ product(bool, PrintVMQWaitTime, false, \ "Print out the waiting time in VM operation queue") \ \ - develop(bool, NoYieldsInMicrolock, false, \ - "Disable yields in microlock") \ - \ develop(bool, TraceOopMapGeneration, false, \ "Show OopMapGeneration") \ \ @@ -936,8 +933,8 @@ product(bool, ShowMessageBoxOnError, false, \ "Keep process alive on VM fatal error") \ \ - product(bool, CreateMinidumpOnCrash, false, \ - "Create minidump on VM fatal error") \ + product(bool, CreateCoredumpOnCrash, true, \ + "Create core/mini dump on VM fatal error") \ \ product_pd(bool, UseOSErrorReporting, \ "Let VM fatal error propagate to the OS (ie. WER on Windows)") \ @@ -1157,9 +1154,6 @@ "Convert yield to a sleep of MinSleepInterval to simulate Win32 " \ "behavior") \ \ - product(bool, UseBoundThreads, true, \ - "Bind user level threads to kernel threads (for Solaris only)") \ - \ develop(bool, UseDetachedThreads, true, \ "Use detached threads that are recycled upon termination " \ "(for Solaris only)") \ @@ -1342,9 +1336,6 @@ product(intx, TraceRedefineClasses, 0, \ "Trace level for JVMTI RedefineClasses") \ \ - develop(bool, StressMethodComparator, false, \ - "Run the MethodComparator on all loaded methods") \ - \ /* change to false by default sometime after Mustang */ \ product(bool, VerifyMergedCPBytecodes, true, \ "Verify bytecodes after RedefineClasses constant pool merging") \ @@ -1963,7 +1954,7 @@ "collection") \ \ develop(uintx, PromotionFailureALotCount, 1000, \ - "Number of promotion failures occurring at ParGCAllocBuffer " \ + "Number of promotion failures occurring at PLAB " \ "refill attempts (ParNew) or promotion attempts " \ "(other young collectors)") \ \ @@ -2235,6 +2226,9 @@ "When +ReduceInitialCardMarks, explicitly defer any that " \ "may arise from new_pre_store_barrier") \ \ + product(bool, UseCondCardMark, false, \ + "Check for already marked card before updating card table") \ + \ diagnostic(bool, VerifyRememberedSets, false, \ "Verify GC remembered sets") \ \ @@ -2293,9 +2287,6 @@ "If non-zero, assert that GC threads yield within this " \ "number of milliseconds") \ \ - notproduct(bool, TraceMarkSweep, false, \ - "Trace mark sweep") \ - \ product(bool, PrintReferenceGC, false, \ "Print times spent handling reference objects during GC " \ "(enabled only when PrintGCDetails)") \ @@ -3447,10 +3438,6 @@ product(bool, ThreadPriorityVerbose, false, \ "Print priority changes") \ \ - product(intx, DefaultThreadPriority, -1, \ - "The native priority at which threads run if not elsewhere " \ - "specified (-1 means no change)") \ - \ product(intx, CompilerThreadPriority, -1, \ "The native priority at which compiler threads should run " \ "(-1 means no change)") \ @@ -3912,7 +3899,14 @@ "Enable event-based tracing") \ \ product(bool, UseLockedTracing, false, \ - "Use locked-tracing when doing event-based tracing") + "Use locked-tracing when doing event-based tracing") \ + \ + diagnostic(bool, UseUnalignedAccesses, false, \ + "Use unaligned memory accesses in sun.misc.Unsafe") \ + \ + product_pd(bool, PreserveFramePointer, \ + "Use the FP register for holding the frame pointer " \ + "and not as a general purpose register.") /* * Macros for factoring of globals diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/mutexLocker.cpp --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp Thu May 07 20:51:12 2015 -0700 @@ -169,7 +169,7 @@ #define def(var, type, pri, vm_block, safepoint_check_allowed ) { \ var = new type(Mutex::pri, #var, vm_block, safepoint_check_allowed); \ assert(_num_mutex < MAX_NUM_MUTEX, "increase MAX_NUM_MUTEX"); \ - _mutex_array[_num_mutex] = var; \ + _mutex_array[_num_mutex++] = var; \ } void mutex_init() { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/os.cpp --- a/hotspot/src/share/vm/runtime/os.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/runtime/os.cpp Thu May 07 20:51:12 2015 -0700 @@ -813,16 +813,16 @@ st->cr(); } -void os::print_environment_variables(outputStream* st, const char** env_list, - char* buffer, int len) { +void os::print_environment_variables(outputStream* st, const char** env_list) { if (env_list) { st->print_cr("Environment Variables:"); for (int i = 0; env_list[i] != NULL; i++) { - if (getenv(env_list[i], buffer, len)) { + char *envvar = ::getenv(env_list[i]); + if (envvar != NULL) { st->print("%s", env_list[i]); st->print("="); - st->print_cr("%s", buffer); + st->print_cr("%s", envvar); } } } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/os.hpp --- a/hotspot/src/share/vm/runtime/os.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/runtime/os.hpp Thu May 07 20:51:12 2015 -0700 @@ -164,8 +164,7 @@ // Override me as needed static int file_name_strcmp(const char* s1, const char* s2); - // get/unset environment variable - static bool getenv(const char* name, char* buffer, int len); + // unset environment variable static bool unsetenv(const char* name); static bool have_special_privileges(); @@ -493,6 +492,7 @@ // Terminate with an error. Default is to generate a core file on platforms // that support such things. This calls shutdown() and then aborts. + static void abort(bool dump_core, void *siginfo, void *context); static void abort(bool dump_core = true); // Die immediately, no exit hook, no abort hook, no cleanup. @@ -591,7 +591,7 @@ static void pd_print_cpu_info(outputStream* st); static void print_memory_info(outputStream* st); static void print_dll_info(outputStream* st); - static void print_environment_variables(outputStream* st, const char** env_list, char* buffer, int len); + static void print_environment_variables(outputStream* st, const char** env_list); static void print_context(outputStream* st, void* context); static void print_register_info(outputStream* st, void* context); static void print_siginfo(outputStream* st, void* siginfo); @@ -717,8 +717,13 @@ // Structured OS Exception support static void os_exception_wrapper(java_call_t f, JavaValue* value, methodHandle* method, JavaCallArguments* args, Thread* thread); - // On Windows this will create an actual minidump, on Linux/Solaris it will simply check core dump limits - static void check_or_create_dump(void* exceptionRecord, void* contextRecord, char* buffer, size_t bufferSize); + // On Posix compatible OS it will simply check core dump limits while on Windows + // it will check if dump file can be created. Check or prepare a core dump to be + // taken at a later point in the same thread in os::abort(). Use the caller + // provided buffer as a scratch buffer. The status message which will be written + // into the error log either is file location or a short error message, depending + // on the checking result. + static void check_dump_limit(char* buffer, size_t bufferSize); // Get the default path to the core file // Returns the length of the string diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/rtmLocking.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/runtime/rtmLocking.cpp Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "utilities/globalDefinitions.hpp" + +#if INCLUDE_RTM_OPT + +#include "memory/allocation.inline.hpp" +#include "runtime/task.hpp" +#include "runtime/rtmLocking.hpp" + + +// One-shot PeriodicTask subclass for enabling RTM locking +uintx RTMLockingCounters::_calculation_flag = 0; + +class RTMLockingCalculationTask : public PeriodicTask { + public: + RTMLockingCalculationTask(size_t interval_time) : PeriodicTask(interval_time){ } + + virtual void task() { + RTMLockingCounters::_calculation_flag = 1; + // Reclaim our storage and disenroll ourself + delete this; + } +}; + +void RTMLockingCounters::init() { + if (UseRTMLocking && RTMLockingCalculationDelay > 0) { + RTMLockingCalculationTask* task = new RTMLockingCalculationTask(RTMLockingCalculationDelay); + task->enroll(); + } else { + _calculation_flag = 1; + } +} + +//------------------------------print_on------------------------------- +void RTMLockingCounters::print_on(outputStream* st) { + tty->print_cr("# rtm locks total (estimated): " UINTX_FORMAT, _total_count * RTMTotalCountIncrRate); + tty->print_cr("# rtm lock aborts : " UINTX_FORMAT, _abort_count); + for (int i = 0; i < ABORT_STATUS_LIMIT; i++) { + tty->print_cr("# rtm lock aborts %d: " UINTX_FORMAT, i, _abortX_count[i]); + } +} + +#endif diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/sharedRuntime.cpp --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp Thu May 07 20:51:12 2015 -0700 @@ -1179,7 +1179,7 @@ #endif // JSR 292 key invariant: - // If the resolved method is a MethodHandle invoke target the call + // If the resolved method is a MethodHandle invoke target, the call // site must be a MethodHandle call site, because the lambda form might tail-call // leaving the stack in a state unknown to either caller or callee // TODO detune for now but we might need it again @@ -1793,7 +1793,9 @@ // Handles the uncommon case in locking, i.e., contention or an inflated lock. JRT_BLOCK_ENTRY(void, SharedRuntime::complete_monitor_locking_C(oopDesc* _obj, BasicLock* lock, JavaThread* thread)) - if (!SafepointSynchronize::is_synchronizing()) { + // Disable ObjectSynchronizer::quick_enter() in default config + // until JDK-8077392 is resolved. + if ((SyncFlags & 256) != 0 && !SafepointSynchronize::is_synchronizing()) { // Only try quick_enter() if we're not trying to reach a safepoint // so that the calling thread reaches the safepoint more quickly. if (ObjectSynchronizer::quick_enter(_obj, thread, lock)) return; @@ -1819,9 +1821,9 @@ JRT_END // Handles the uncommon cases of monitor unlocking in compiled code -JRT_LEAF(void, SharedRuntime::complete_monitor_unlocking_C(oopDesc* _obj, BasicLock* lock)) +JRT_LEAF(void, SharedRuntime::complete_monitor_unlocking_C(oopDesc* _obj, BasicLock* lock, JavaThread * THREAD)) oop obj(_obj); - Thread* THREAD = JavaThread::current(); + assert(JavaThread::current() == THREAD, "invariant"); // I'm not convinced we need the code contained by MIGHT_HAVE_PENDING anymore // testing was unable to ever fire the assert that guarded it so I have removed it. assert(!HAS_PENDING_EXCEPTION, "Do we need code below anymore?"); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/sharedRuntime.hpp --- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -472,7 +472,7 @@ // Slow-path Locking and Unlocking static void complete_monitor_locking_C(oopDesc* obj, BasicLock* lock, JavaThread* thread); - static void complete_monitor_unlocking_C(oopDesc* obj, BasicLock* lock); + static void complete_monitor_unlocking_C(oopDesc* obj, BasicLock* lock, JavaThread* thread); // Resolving of calls static address resolve_static_call_C (JavaThread *thread); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/stubRoutines.cpp --- a/hotspot/src/share/vm/runtime/stubRoutines.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/runtime/stubRoutines.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -213,31 +213,35 @@ // simple test for SafeFetch32 static void test_safefetch32() { - int dummy = 17; - int* const p_invalid = (int*) get_segfault_address(); - int* const p_valid = &dummy; - int result_invalid = SafeFetch32(p_invalid, 0xABC); - assert(result_invalid == 0xABC, "SafeFetch32 error"); - int result_valid = SafeFetch32(p_valid, 0xABC); - assert(result_valid == 17, "SafeFetch32 error"); + if (CanUseSafeFetch32()) { + int dummy = 17; + int* const p_invalid = (int*) get_segfault_address(); + int* const p_valid = &dummy; + int result_invalid = SafeFetch32(p_invalid, 0xABC); + assert(result_invalid == 0xABC, "SafeFetch32 error"); + int result_valid = SafeFetch32(p_valid, 0xABC); + assert(result_valid == 17, "SafeFetch32 error"); + } } // simple test for SafeFetchN static void test_safefetchN() { + if (CanUseSafeFetchN()) { #ifdef _LP64 - const intptr_t v1 = UCONST64(0xABCD00000000ABCD); - const intptr_t v2 = UCONST64(0xDEFD00000000DEFD); + const intptr_t v1 = UCONST64(0xABCD00000000ABCD); + const intptr_t v2 = UCONST64(0xDEFD00000000DEFD); #else - const intptr_t v1 = 0xABCDABCD; - const intptr_t v2 = 0xDEFDDEFD; + const intptr_t v1 = 0xABCDABCD; + const intptr_t v2 = 0xDEFDDEFD; #endif - intptr_t dummy = v1; - intptr_t* const p_invalid = (intptr_t*) get_segfault_address(); - intptr_t* const p_valid = &dummy; - intptr_t result_invalid = SafeFetchN(p_invalid, v2); - assert(result_invalid == v2, "SafeFetchN error"); - intptr_t result_valid = SafeFetchN(p_valid, v2); - assert(result_valid == v1, "SafeFetchN error"); + intptr_t dummy = v1; + intptr_t* const p_invalid = (intptr_t*) get_segfault_address(); + intptr_t* const p_valid = &dummy; + intptr_t result_invalid = SafeFetchN(p_invalid, v2); + assert(result_invalid == v2, "SafeFetchN error"); + intptr_t result_valid = SafeFetchN(p_valid, v2); + assert(result_valid == v1, "SafeFetchN error"); + } } #endif diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/stubRoutines.hpp --- a/hotspot/src/share/vm/runtime/stubRoutines.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/runtime/stubRoutines.hpp Thu May 07 20:51:12 2015 -0700 @@ -450,7 +450,11 @@ // returns true if SafeFetch32 and SafeFetchN can be used safely (stubroutines are already generated) -inline bool CanUseSafeFetch32() { return StubRoutines::SafeFetch32_stub() ? true : false; } -inline bool CanUseSafeFetchN() { return StubRoutines::SafeFetchN_stub() ? true : false; } +inline bool CanUseSafeFetch32() { + return StubRoutines::SafeFetch32_stub() ? true : false; +} +inline bool CanUseSafeFetchN() { + return StubRoutines::SafeFetchN_stub() ? true : false; +} #endif // SHARE_VM_RUNTIME_STUBROUTINES_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/sweeper.cpp --- a/hotspot/src/share/vm/runtime/sweeper.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/runtime/sweeper.cpp Thu May 07 20:51:12 2015 -0700 @@ -144,6 +144,7 @@ int NMethodSweeper::_seen = 0; // Nof. nmethod we have currently processed in current pass of CodeCache volatile bool NMethodSweeper::_should_sweep = true; // Indicates if we should invoke the sweeper +volatile bool NMethodSweeper::_force_sweep = false;// Indicates if we should force a sweep volatile int NMethodSweeper::_bytes_changed = 0; // Counts the total nmethod size if the nmethod changed from: // 1) alive -> not_entrant // 2) not_entrant -> zombie @@ -276,6 +277,23 @@ } /** + * Wakes up the sweeper thread and forces a sweep. Blocks until it finished. + */ +void NMethodSweeper::force_sweep() { + ThreadBlockInVM tbivm(JavaThread::current()); + MutexLockerEx waiter(CodeCache_lock, Mutex::_no_safepoint_check_flag); + // Request forced sweep + _force_sweep = true; + while (_force_sweep) { + // Notify sweeper that we want to force a sweep and wait for completion. + // In case a sweep currently takes place we timeout and try again because + // we want to enforce a full sweep. + CodeCache_lock->notify(); + CodeCache_lock->wait(Mutex::_no_safepoint_check_flag, 1000); + } +} + +/** * Handle a safepoint request */ void NMethodSweeper::handle_safepoint_request() { @@ -335,6 +353,9 @@ } } + // Remember if this was a forced sweep + bool forced = _force_sweep; + // Force stack scanning if there is only 10% free space in the code cache. // We force stack scanning only non-profiled code heap gets full, since critical // allocation go to the non-profiled heap and we must be make sure that there is @@ -344,7 +365,7 @@ do_stack_scanning(); } - if (_should_sweep) { + if (_should_sweep || forced) { init_sweeper_log(); sweep_code_cache(); } @@ -356,12 +377,20 @@ _should_sweep = false; // If there was enough state change, 'possibly_enable_sweeper()' // sets '_should_sweep' to true - possibly_enable_sweeper(); + possibly_enable_sweeper(); // Reset _bytes_changed only if there was enough state change. _bytes_changed // can further increase by calls to 'report_state_change'. if (_should_sweep) { _bytes_changed = 0; } + + if (forced) { + // Notify requester that forced sweep finished + assert(_force_sweep, "Should be a forced sweep"); + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + _force_sweep = false; + CodeCache_lock->notify(); + } } void NMethodSweeper::sweep_code_cache() { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/sweeper.hpp --- a/hotspot/src/share/vm/runtime/sweeper.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/runtime/sweeper.hpp Thu May 07 20:51:12 2015 -0700 @@ -54,7 +54,6 @@ // nmethod's space is freed. class NMethodSweeper : public AllStatic { - friend class WhiteBox; private: enum MethodStateChange { None, @@ -71,6 +70,7 @@ static volatile int _sweep_started; // Flag to control conc sweeper static volatile bool _should_sweep; // Indicates if we should invoke the sweeper + static volatile bool _force_sweep; // Indicates if we should force a sweep static volatile int _bytes_changed; // Counts the total nmethod size if the nmethod changed from: // 1) alive -> not_entrant // 2) not_entrant -> zombie @@ -117,6 +117,7 @@ static void mark_active_nmethods(); // Invoked at the end of each safepoint static void sweeper_loop(); static void notify(int code_blob_type); // Possibly start the sweeper thread. + static void force_sweep(); static int hotness_counter_reset_val(); static void report_state_change(nmethod* nm); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/synchronizer.cpp --- a/hotspot/src/share/vm/runtime/synchronizer.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/runtime/synchronizer.cpp Thu May 07 20:51:12 2015 -0700 @@ -109,17 +109,24 @@ } #define NINFLATIONLOCKS 256 -static volatile intptr_t InflationLocks[NINFLATIONLOCKS]; +static volatile intptr_t gInflationLocks[NINFLATIONLOCKS]; +// global list of blocks of monitors // gBlockList is really PaddedEnd *, but we don't // want to expose the PaddedEnd template more than necessary. ObjectMonitor * ObjectSynchronizer::gBlockList = NULL; +// global monitor free list ObjectMonitor * volatile ObjectSynchronizer::gFreeList = NULL; +// global monitor in-use list, for moribund threads, +// monitors they inflated need to be scanned for deflation ObjectMonitor * volatile ObjectSynchronizer::gOmInUseList = NULL; +// count of entries in gOmInUseList int ObjectSynchronizer::gOmInUseCount = 0; -static volatile intptr_t ListLock = 0; // protects global monitor free-list cache -static volatile int MonitorFreeCount = 0; // # on gFreeList -static volatile int MonitorPopulation = 0; // # Extant -- in circulation + +static volatile intptr_t gListLock = 0; // protects global monitor lists +static volatile int gMonitorFreeCount = 0; // # on gFreeList +static volatile int gMonitorPopulation = 0; // # Extant -- in circulation + #define CHAINMARKER (cast_to_oop(-1)) @@ -528,7 +535,7 @@ int YieldThenBlock = 0; assert(ix >= 0 && ix < NINFLATIONLOCKS, "invariant"); assert((NINFLATIONLOCKS & (NINFLATIONLOCKS-1)) == 0, "invariant"); - Thread::muxAcquire(InflationLocks + ix, "InflationLock"); + Thread::muxAcquire(gInflationLocks + ix, "gInflationLock"); while (obj->mark() == markOopDesc::INFLATING()) { // Beware: NakedYield() is advisory and has almost no effect on some platforms // so we periodically call Self->_ParkEvent->park(1). @@ -539,7 +546,7 @@ os::naked_yield(); } } - Thread::muxRelease(InflationLocks + ix); + Thread::muxRelease(gInflationLocks + ix); TEVENT(Inflate: INFLATING - yield/park); } } else { @@ -882,7 +889,7 @@ // STW-time -- disassociates idle monitors from objects. Such // scavenged monitors are returned to the gFreeList. // -// The global list is protected by ListLock. All the critical sections +// The global list is protected by gListLock. All the critical sections // are short and operate in constant-time. // // ObjectMonitors reside in type-stable memory (TSM) and are immortal. @@ -937,17 +944,17 @@ void ObjectSynchronizer::verifyInUse(Thread *Self) { ObjectMonitor* mid; - int inusetally = 0; + int in_use_tally = 0; for (mid = Self->omInUseList; mid != NULL; mid = mid->FreeNext) { - inusetally++; + in_use_tally++; } - assert(inusetally == Self->omInUseCount, "inuse count off"); + assert(in_use_tally == Self->omInUseCount, "in-use count off"); - int freetally = 0; + int free_tally = 0; for (mid = Self->omFreeList; mid != NULL; mid = mid->FreeNext) { - freetally++; + free_tally++; } - assert(freetally == Self->omFreeCount, "free count off"); + assert(free_tally == Self->omFreeCount, "free count off"); } ObjectMonitor * NOINLINE ObjectSynchronizer::omAlloc(Thread * Self) { @@ -964,7 +971,7 @@ // Threads will attempt to allocate first from their local list, then // from the global list, and only after those attempts fail will the thread // attempt to instantiate new monitors. Thread-local free lists take - // heat off the ListLock and improve allocation latency, as well as reducing + // heat off the gListLock and improve allocation latency, as well as reducing // coherency traffic on the shared global list. m = Self->omFreeList; if (m != NULL) { @@ -994,9 +1001,9 @@ // Reprovision the thread's omFreeList. // Use bulk transfers to reduce the allocation rate and heat // on various locks. - Thread::muxAcquire(&ListLock, "omAlloc"); + Thread::muxAcquire(&gListLock, "omAlloc"); for (int i = Self->omFreeProvision; --i >= 0 && gFreeList != NULL;) { - MonitorFreeCount--; + gMonitorFreeCount--; ObjectMonitor * take = gFreeList; gFreeList = take->FreeNext; guarantee(take->object() == NULL, "invariant"); @@ -1004,13 +1011,13 @@ take->Recycle(); omRelease(Self, take, false); } - Thread::muxRelease(&ListLock); + Thread::muxRelease(&gListLock); Self->omFreeProvision += 1 + (Self->omFreeProvision/2); if (Self->omFreeProvision > MAXPRIVATE) Self->omFreeProvision = MAXPRIVATE; TEVENT(omFirst - reprovision); const int mx = MonitorBound; - if (mx > 0 && (MonitorPopulation-MonitorFreeCount) > mx) { + if (mx > 0 && (gMonitorPopulation-gMonitorFreeCount) > mx) { // We can't safely induce a STW safepoint from omAlloc() as our thread // state may not be appropriate for such activities and callers may hold // naked oops, so instead we defer the action. @@ -1068,11 +1075,11 @@ // block in hand. This avoids some lock traffic and redundant // list activity. - // Acquire the ListLock to manipulate BlockList and FreeList. + // Acquire the gListLock to manipulate gBlockList and gFreeList. // An Oyama-Taura-Yonezawa scheme might be more efficient. - Thread::muxAcquire(&ListLock, "omAlloc [2]"); - MonitorPopulation += _BLOCKSIZE-1; - MonitorFreeCount += _BLOCKSIZE-1; + Thread::muxAcquire(&gListLock, "omAlloc [2]"); + gMonitorPopulation += _BLOCKSIZE-1; + gMonitorFreeCount += _BLOCKSIZE-1; // Add the new block to the list of extant blocks (gBlockList). // The very first objectMonitor in a block is reserved and dedicated. @@ -1083,7 +1090,7 @@ // Add the new string of objectMonitors to the global free list temp[_BLOCKSIZE - 1].FreeNext = gFreeList; gFreeList = temp + 1; - Thread::muxRelease(&ListLock); + Thread::muxRelease(&gListLock); TEVENT(Allocate block of monitors); } } @@ -1094,32 +1101,36 @@ // omRelease is to return a monitor to the free list after a CAS // attempt failed. This doesn't allow unbounded #s of monitors to // accumulate on a thread's free list. +// +// Key constraint: all ObjectMonitors on a thread's free list and the global +// free list must have their object field set to null. This prevents the +// scavenger -- deflate_idle_monitors -- from reclaiming them. void ObjectSynchronizer::omRelease(Thread * Self, ObjectMonitor * m, bool fromPerThreadAlloc) { guarantee(m->object() == NULL, "invariant"); - + guarantee(((m->is_busy()|m->_recursions) == 0), "freeing in-use monitor"); // Remove from omInUseList if (MonitorInUseLists && fromPerThreadAlloc) { - ObjectMonitor* curmidinuse = NULL; - for (ObjectMonitor* mid = Self->omInUseList; mid != NULL;) { + ObjectMonitor* cur_mid_in_use = NULL; + bool extracted = false; + for (ObjectMonitor* mid = Self->omInUseList; mid != NULL; cur_mid_in_use = mid, mid = mid->FreeNext) { if (m == mid) { - // extract from per-thread in-use-list + // extract from per-thread in-use list if (mid == Self->omInUseList) { Self->omInUseList = mid->FreeNext; - } else if (curmidinuse != NULL) { - curmidinuse->FreeNext = mid->FreeNext; // maintain the current thread inuselist + } else if (cur_mid_in_use != NULL) { + cur_mid_in_use->FreeNext = mid->FreeNext; // maintain the current thread in-use list } + extracted = true; Self->omInUseCount--; if (ObjectMonitor::Knob_VerifyInUse) { verifyInUse(Self); } break; - } else { - curmidinuse = mid; - mid = mid->FreeNext; } } + assert(extracted, "Should have extracted from in-use list"); } // FreeNext is used for both omInUseList and omFreeList, so clear old before setting new @@ -1149,52 +1160,60 @@ // operator. void ObjectSynchronizer::omFlush(Thread * Self) { - ObjectMonitor * List = Self->omFreeList; // Null-terminated SLL + ObjectMonitor * list = Self->omFreeList; // Null-terminated SLL Self->omFreeList = NULL; - ObjectMonitor * Tail = NULL; - int Tally = 0; - if (List != NULL) { + ObjectMonitor * tail = NULL; + int tally = 0; + if (list != NULL) { ObjectMonitor * s; - for (s = List; s != NULL; s = s->FreeNext) { - Tally++; - Tail = s; + // The thread is going away, the per-thread free monitors + // are freed via set_owner(NULL) + // Link them to tail, which will be linked into the global free list + // gFreeList below, under the gListLock + for (s = list; s != NULL; s = s->FreeNext) { + tally++; + tail = s; guarantee(s->object() == NULL, "invariant"); guarantee(!s->is_busy(), "invariant"); s->set_owner(NULL); // redundant but good hygiene TEVENT(omFlush - Move one); } - guarantee(Tail != NULL && List != NULL, "invariant"); + guarantee(tail != NULL && list != NULL, "invariant"); } - ObjectMonitor * InUseList = Self->omInUseList; - ObjectMonitor * InUseTail = NULL; - int InUseTally = 0; - if (InUseList != NULL) { + ObjectMonitor * inUseList = Self->omInUseList; + ObjectMonitor * inUseTail = NULL; + int inUseTally = 0; + if (inUseList != NULL) { Self->omInUseList = NULL; - ObjectMonitor *curom; - for (curom = InUseList; curom != NULL; curom = curom->FreeNext) { - InUseTail = curom; - InUseTally++; + ObjectMonitor *cur_om; + // The thread is going away, however the omInUseList inflated + // monitors may still be in-use by other threads. + // Link them to inUseTail, which will be linked into the global in-use list + // gOmInUseList below, under the gListLock + for (cur_om = inUseList; cur_om != NULL; cur_om = cur_om->FreeNext) { + inUseTail = cur_om; + inUseTally++; } - assert(Self->omInUseCount == InUseTally, "inuse count off"); + assert(Self->omInUseCount == inUseTally, "in-use count off"); Self->omInUseCount = 0; - guarantee(InUseTail != NULL && InUseList != NULL, "invariant"); + guarantee(inUseTail != NULL && inUseList != NULL, "invariant"); } - Thread::muxAcquire(&ListLock, "omFlush"); - if (Tail != NULL) { - Tail->FreeNext = gFreeList; - gFreeList = List; - MonitorFreeCount += Tally; + Thread::muxAcquire(&gListLock, "omFlush"); + if (tail != NULL) { + tail->FreeNext = gFreeList; + gFreeList = list; + gMonitorFreeCount += tally; } - if (InUseTail != NULL) { - InUseTail->FreeNext = gOmInUseList; - gOmInUseList = InUseList; - gOmInUseCount += InUseTally; + if (inUseTail != NULL) { + inUseTail->FreeNext = gOmInUseList; + gOmInUseList = inUseList; + gOmInUseCount += inUseTally; } - Thread::muxRelease(&ListLock); + Thread::muxRelease(&gListLock); TEVENT(omFlush); } @@ -1411,14 +1430,14 @@ // // We have added a flag, MonitorInUseLists, which creates a list // of active monitors for each thread. deflate_idle_monitors() -// only scans the per-thread inuse lists. omAlloc() puts all +// only scans the per-thread in-use lists. omAlloc() puts all // assigned monitors on the per-thread list. deflate_idle_monitors() // returns the non-busy monitors to the global free list. // When a thread dies, omFlush() adds the list of active monitors for // that thread to a global gOmInUseList acquiring the // global list lock. deflate_idle_monitors() acquires the global // list lock to scan for non-busy monitors to the global free list. -// An alternative could have used a single global inuse list. The +// An alternative could have used a single global in-use list. The // downside would have been the additional cost of acquiring the global list lock // for every omAlloc(). // @@ -1432,8 +1451,8 @@ MaximumRecheckInterval = 1000 }; -// Deflate a single monitor if not in use -// Return true if deflated, false if in use +// Deflate a single monitor if not in-use +// Return true if deflated, false if in-use bool ObjectSynchronizer::deflate_monitor(ObjectMonitor* mid, oop obj, ObjectMonitor** freeHeadp, ObjectMonitor** freeTailp) { @@ -1465,11 +1484,11 @@ assert(mid->object() == NULL, "invariant"); - // Move the object to the working free list defined by FreeHead,FreeTail. + // Move the object to the working free list defined by freeHeadp, freeTailp if (*freeHeadp == NULL) *freeHeadp = mid; if (*freeTailp != NULL) { ObjectMonitor * prevtail = *freeTailp; - assert(prevtail->FreeNext == NULL, "cleaned up deflated?"); // TODO KK + assert(prevtail->FreeNext == NULL, "cleaned up deflated?"); prevtail->FreeNext = mid; } *freeTailp = mid; @@ -1478,38 +1497,37 @@ return deflated; } -// Caller acquires ListLock -int ObjectSynchronizer::walk_monitor_list(ObjectMonitor** listheadp, - ObjectMonitor** freeHeadp, - ObjectMonitor** freeTailp) { +// Walk a given monitor list, and deflate idle monitors +// The given list could be a per-thread list or a global list +// Caller acquires gListLock +int ObjectSynchronizer::deflate_monitor_list(ObjectMonitor** listHeadp, + ObjectMonitor** freeHeadp, + ObjectMonitor** freeTailp) { ObjectMonitor* mid; ObjectMonitor* next; - ObjectMonitor* curmidinuse = NULL; - int deflatedcount = 0; + ObjectMonitor* cur_mid_in_use = NULL; + int deflated_count = 0; - for (mid = *listheadp; mid != NULL;) { + for (mid = *listHeadp; mid != NULL;) { oop obj = (oop) mid->object(); - bool deflated = false; - if (obj != NULL) { - deflated = deflate_monitor(mid, obj, freeHeadp, freeTailp); - } - if (deflated) { - // extract from per-thread in-use-list - if (mid == *listheadp) { - *listheadp = mid->FreeNext; - } else if (curmidinuse != NULL) { - curmidinuse->FreeNext = mid->FreeNext; // maintain the current thread inuselist + if (obj != NULL && deflate_monitor(mid, obj, freeHeadp, freeTailp)) { + // if deflate_monitor succeeded, + // extract from per-thread in-use list + if (mid == *listHeadp) { + *listHeadp = mid->FreeNext; + } else if (cur_mid_in_use != NULL) { + cur_mid_in_use->FreeNext = mid->FreeNext; // maintain the current thread in-use list } next = mid->FreeNext; - mid->FreeNext = NULL; // This mid is current tail in the FreeHead list + mid->FreeNext = NULL; // This mid is current tail in the freeHeadp list mid = next; - deflatedcount++; + deflated_count++; } else { - curmidinuse = mid; + cur_mid_in_use = mid; mid = mid->FreeNext; } } - return deflatedcount; + return deflated_count; } void ObjectSynchronizer::deflate_idle_monitors() { @@ -1519,34 +1537,34 @@ int nScavenged = 0; // reclaimed bool deflated = false; - ObjectMonitor * FreeHead = NULL; // Local SLL of scavenged monitors - ObjectMonitor * FreeTail = NULL; + ObjectMonitor * freeHeadp = NULL; // Local SLL of scavenged monitors + ObjectMonitor * freeTailp = NULL; TEVENT(deflate_idle_monitors); // Prevent omFlush from changing mids in Thread dtor's during deflation // And in case the vm thread is acquiring a lock during a safepoint // See e.g. 6320749 - Thread::muxAcquire(&ListLock, "scavenge - return"); + Thread::muxAcquire(&gListLock, "scavenge - return"); if (MonitorInUseLists) { int inUse = 0; for (JavaThread* cur = Threads::first(); cur != NULL; cur = cur->next()) { nInCirculation+= cur->omInUseCount; - int deflatedcount = walk_monitor_list(cur->omInUseList_addr(), &FreeHead, &FreeTail); - cur->omInUseCount-= deflatedcount; + int deflated_count = deflate_monitor_list(cur->omInUseList_addr(), &freeHeadp, &freeTailp); + cur->omInUseCount-= deflated_count; if (ObjectMonitor::Knob_VerifyInUse) { verifyInUse(cur); } - nScavenged += deflatedcount; + nScavenged += deflated_count; nInuse += cur->omInUseCount; } // For moribund threads, scan gOmInUseList if (gOmInUseList) { nInCirculation += gOmInUseCount; - int deflatedcount = walk_monitor_list((ObjectMonitor **)&gOmInUseList, &FreeHead, &FreeTail); - gOmInUseCount-= deflatedcount; - nScavenged += deflatedcount; + int deflated_count = deflate_monitor_list((ObjectMonitor **)&gOmInUseList, &freeHeadp, &freeTailp); + gOmInUseCount-= deflated_count; + nScavenged += deflated_count; nInuse += gOmInUseCount; } @@ -1568,7 +1586,7 @@ guarantee(!mid->is_busy(), "invariant"); continue; } - deflated = deflate_monitor(mid, obj, &FreeHead, &FreeTail); + deflated = deflate_monitor(mid, obj, &freeHeadp, &freeTailp); if (deflated) { mid->FreeNext = NULL; @@ -1579,28 +1597,28 @@ } } - MonitorFreeCount += nScavenged; + gMonitorFreeCount += nScavenged; - // Consider: audit gFreeList to ensure that MonitorFreeCount and list agree. + // Consider: audit gFreeList to ensure that gMonitorFreeCount and list agree. if (ObjectMonitor::Knob_Verbose) { ::printf("Deflate: InCirc=%d InUse=%d Scavenged=%d ForceMonitorScavenge=%d : pop=%d free=%d\n", nInCirculation, nInuse, nScavenged, ForceMonitorScavenge, - MonitorPopulation, MonitorFreeCount); + gMonitorPopulation, gMonitorFreeCount); ::fflush(stdout); } ForceMonitorScavenge = 0; // Reset // Move the scavenged monitors back to the global free list. - if (FreeHead != NULL) { - guarantee(FreeTail != NULL && nScavenged > 0, "invariant"); - assert(FreeTail->FreeNext == NULL, "invariant"); + if (freeHeadp != NULL) { + guarantee(freeTailp != NULL && nScavenged > 0, "invariant"); + assert(freeTailp->FreeNext == NULL, "invariant"); // constant-time list splice - prepend scavenged segment to gFreeList - FreeTail->FreeNext = gFreeList; - gFreeList = FreeHead; + freeTailp->FreeNext = gFreeList; + gFreeList = freeHeadp; } - Thread::muxRelease(&ListLock); + Thread::muxRelease(&gListLock); if (ObjectMonitor::_sync_Deflations != NULL) ObjectMonitor::_sync_Deflations->inc(nScavenged); if (ObjectMonitor::_sync_MonExtant != NULL) ObjectMonitor::_sync_MonExtant ->set_value(nInCirculation); @@ -1648,9 +1666,9 @@ assert(THREAD == JavaThread::current(), "must be current Java thread"); No_Safepoint_Verifier nsv; ReleaseJavaMonitorsClosure rjmc(THREAD); - Thread::muxAcquire(&ListLock, "release_monitors_owned_by_thread"); + Thread::muxAcquire(&gListLock, "release_monitors_owned_by_thread"); ObjectSynchronizer::monitors_iterate(&rjmc); - Thread::muxRelease(&ListLock); + Thread::muxRelease(&gListLock); THREAD->clear_pending_exception(); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/synchronizer.hpp --- a/hotspot/src/share/vm/runtime/synchronizer.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/runtime/synchronizer.hpp Thu May 07 20:51:12 2015 -0700 @@ -116,9 +116,10 @@ // Basically we deflate all monitors that are not busy. // An adaptive profile-based deflation policy could be used if needed static void deflate_idle_monitors(); - static int walk_monitor_list(ObjectMonitor** listheadp, - ObjectMonitor** freeHeadp, - ObjectMonitor** freeTailp); + // For a given monitor list: global or per-thread, deflate idle monitors + static int deflate_monitor_list(ObjectMonitor** listheadp, + ObjectMonitor** freeHeadp, + ObjectMonitor** freeTailp); static bool deflate_monitor(ObjectMonitor* mid, oop obj, ObjectMonitor** freeHeadp, ObjectMonitor** freeTailp); @@ -135,16 +136,17 @@ private: enum { _BLOCKSIZE = 128 }; + // global list of blocks of monitors // gBlockList is really PaddedEnd *, but we don't // want to expose the PaddedEnd template more than necessary. - static ObjectMonitor* gBlockList; + static ObjectMonitor * gBlockList; + // global monitor free list static ObjectMonitor * volatile gFreeList; - // global monitor in use list, for moribund threads, + // global monitor in-use list, for moribund threads, // monitors they inflated need to be scanned for deflation static ObjectMonitor * volatile gOmInUseList; // count of entries in gOmInUseList static int gOmInUseCount; - }; // ObjectLocker enforced balanced locking and can never thrown an diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/thread.cpp --- a/hotspot/src/share/vm/runtime/thread.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/runtime/thread.cpp Thu May 07 20:51:12 2015 -0700 @@ -272,6 +272,11 @@ #endif // ASSERT } +// Non-inlined version to be used where thread.inline.hpp shouldn't be included. +Thread* Thread::current_noinline() { + return Thread::current(); +} + void Thread::initialize_thread_local_storage() { // Note: Make sure this method only calls // non-blocking operations. Otherwise, it might not work @@ -754,13 +759,9 @@ return true; } else { guarantee(res == strong_roots_parity, "Or else what?"); - assert(SharedHeap::heap()->workers()->active_workers() > 0, - "Should only fail when parallel."); return false; } } - assert(SharedHeap::heap()->workers()->active_workers() > 0, - "Should only fail when parallel."); return false; } @@ -4056,7 +4057,7 @@ "Not in range."); } -#ifndef PRODUCT +#ifdef ASSERT void Threads::assert_all_threads_claimed() { ALL_JAVA_THREADS(p) { const int thread_parity = p->oops_do_parity(); @@ -4064,22 +4065,9 @@ err_msg("Thread " PTR_FORMAT " has incorrect parity %d != %d", p2i(p), thread_parity, _thread_claim_parity)); } } -#endif // PRODUCT - -void Threads::possibly_parallel_oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf) { - // Introduce a mechanism allowing parallel threads to claim threads as - // root groups. Overhead should be small enough to use all the time, - // even in sequential code. - SharedHeap* sh = SharedHeap::heap(); - // Cannot yet substitute active_workers for n_par_threads - // because of G1CollectedHeap::verify() use of - // SharedHeap::process_roots(). n_par_threads == 0 will - // turn off parallelism in process_roots while active_workers - // is being used for parallelism elsewhere. - bool is_par = sh->n_par_threads() > 0; - assert(!is_par || - (SharedHeap::heap()->n_par_threads() == - SharedHeap::heap()->workers()->active_workers()), "Mismatch"); +#endif // ASSERT + +void Threads::possibly_parallel_oops_do(bool is_par, OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf) { int cp = Threads::thread_claim_parity(); ALL_JAVA_THREADS(p) { if (p->claim_oops_do(is_par, cp)) { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/thread.hpp --- a/hotspot/src/share/vm/runtime/thread.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/runtime/thread.hpp Thu May 07 20:51:12 2015 -0700 @@ -324,6 +324,8 @@ // Returns the current thread static inline Thread* current(); + // ... without having to include thread.inline.hpp. + static Thread* current_noinline(); // Common thread operations static void set_priority(Thread* thread, ThreadPriority priority); @@ -1886,15 +1888,28 @@ // Does not include JNI_VERSION_1_1 static jboolean is_supported_jni_version(jint version); + // The "thread claim parity" provides a way for threads to be claimed + // by parallel worker tasks. + // + // Each thread contains a a "parity" field. A task will claim the + // thread only if its parity field is the same as the global parity, + // which is updated by calling change_thread_claim_parity(). + // + // For this to work change_thread_claim_parity() needs to be called + // exactly once in sequential code before starting parallel tasks + // that should claim threads. + // + // New threads get their parity set to 0 and change_thread_claim_parity() + // never set the global parity to 0. static int thread_claim_parity() { return _thread_claim_parity; } static void change_thread_claim_parity(); + static void assert_all_threads_claimed() NOT_DEBUG_RETURN; - static void assert_all_threads_claimed() PRODUCT_RETURN; // Apply "f->do_oop" to all root oops in all threads. // This version may only be called by sequential code. static void oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf); // This version may be called by sequential or parallel code. - static void possibly_parallel_oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf); + static void possibly_parallel_oops_do(bool is_par, OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf); // This creates a list of GCTasks, one per thread. static void create_thread_roots_tasks(GCTaskQueue* q); // This creates a list of GCTasks, one per thread, for marking objects. diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/vframe.hpp --- a/hotspot/src/share/vm/runtime/vframe.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/runtime/vframe.hpp Thu May 07 20:51:12 2015 -0700 @@ -389,12 +389,12 @@ decode_offset < 0 || decode_offset >= nm()->scopes_data_size()) { // 6379830 AsyncGetCallTrace sometimes feeds us wild frames. - // If we attempt to read nmethod::scopes_data at serialized_null (== 0), - // or if we read some at other crazy offset, - // we will decode garbage and make wild references into the heap, - // leading to crashes in product mode. - // (This isn't airtight, of course, since there are internal - // offsets which are also crazy.) + // If we read nmethod::scopes_data at serialized_null (== 0) + // or if read some at other invalid offset, invalid values will be decoded. + // Based on these values, invalid heap locations could be referenced + // that could lead to crashes in product mode. + // Therefore, do not use the decode offset if invalid, but fill the frame + // as it were a native compiled frame (no Java-level assumptions). #ifdef ASSERT if (WizardMode) { tty->print_cr("Error in fill_from_frame: pc_desc for " @@ -514,9 +514,15 @@ address bcp = _frame.interpreter_frame_bcp(); int bci = method->validate_bci_from_bcp(bcp); // 6379830 AsyncGetCallTrace sometimes feeds us wild frames. + // AsyncGetCallTrace interrupts the VM asynchronously. As a result + // it is possible to access an interpreter frame for which + // no Java-level information is yet available (e.g., becasue + // the frame was being created when the VM interrupted it). + // In this scenario, pretend that the interpreter is at the point + // of entering the method. if (bci < 0) { found_bad_method_frame(); - bci = 0; // pretend it's on the point of entering + bci = 0; } _mode = interpreted_mode; _method = method; diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/virtualspace.cpp --- a/hotspot/src/share/vm/runtime/virtualspace.cpp Thu May 07 10:19:31 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1372 +0,0 @@ -/* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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 "oops/markOop.hpp" -#include "oops/oop.inline.hpp" -#include "runtime/virtualspace.hpp" -#include "services/memTracker.hpp" - -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - -// ReservedSpace - -// Dummy constructor -ReservedSpace::ReservedSpace() : _base(NULL), _size(0), _noaccess_prefix(0), - _alignment(0), _special(false), _executable(false) { -} - -ReservedSpace::ReservedSpace(size_t size) { - // Want to use large pages where possible and pad with small pages. - size_t page_size = os::page_size_for_region_unaligned(size, 1); - bool large_pages = page_size != (size_t)os::vm_page_size(); - // Don't force the alignment to be large page aligned, - // since that will waste memory. - size_t alignment = os::vm_allocation_granularity(); - initialize(size, alignment, large_pages, NULL, false); -} - -ReservedSpace::ReservedSpace(size_t size, size_t alignment, - bool large, - char* requested_address) { - initialize(size, alignment, large, requested_address, false); -} - -ReservedSpace::ReservedSpace(size_t size, size_t alignment, - bool large, - bool executable) { - initialize(size, alignment, large, NULL, executable); -} - -// Helper method. -static bool failed_to_reserve_as_requested(char* base, char* requested_address, - const size_t size, bool special) -{ - if (base == requested_address || requested_address == NULL) - return false; // did not fail - - if (base != NULL) { - // Different reserve address may be acceptable in other cases - // but for compressed oops heap should be at requested address. - assert(UseCompressedOops, "currently requested address used only for compressed oops"); - if (PrintCompressedOopsMode) { - tty->cr(); - tty->print_cr("Reserved memory not at requested address: " PTR_FORMAT " vs " PTR_FORMAT, base, requested_address); - } - // OS ignored requested address. Try different address. - if (special) { - if (!os::release_memory_special(base, size)) { - fatal("os::release_memory_special failed"); - } - } else { - if (!os::release_memory(base, size)) { - fatal("os::release_memory failed"); - } - } - } - return true; -} - -void ReservedSpace::initialize(size_t size, size_t alignment, bool large, - char* requested_address, - bool executable) { - const size_t granularity = os::vm_allocation_granularity(); - assert((size & (granularity - 1)) == 0, - "size not aligned to os::vm_allocation_granularity()"); - assert((alignment & (granularity - 1)) == 0, - "alignment not aligned to os::vm_allocation_granularity()"); - assert(alignment == 0 || is_power_of_2((intptr_t)alignment), - "not a power of 2"); - - alignment = MAX2(alignment, (size_t)os::vm_page_size()); - - _base = NULL; - _size = 0; - _special = false; - _executable = executable; - _alignment = 0; - _noaccess_prefix = 0; - if (size == 0) { - return; - } - - // If OS doesn't support demand paging for large page memory, we need - // to use reserve_memory_special() to reserve and pin the entire region. - bool special = large && !os::can_commit_large_page_memory(); - char* base = NULL; - - if (special) { - - base = os::reserve_memory_special(size, alignment, requested_address, executable); - - if (base != NULL) { - if (failed_to_reserve_as_requested(base, requested_address, size, true)) { - // OS ignored requested address. Try different address. - return; - } - // Check alignment constraints. - assert((uintptr_t) base % alignment == 0, - err_msg("Large pages returned a non-aligned address, base: " - PTR_FORMAT " alignment: " PTR_FORMAT, - base, (void*)(uintptr_t)alignment)); - _special = true; - } else { - // failed; try to reserve regular memory below - if (UseLargePages && (!FLAG_IS_DEFAULT(UseLargePages) || - !FLAG_IS_DEFAULT(LargePageSizeInBytes))) { - if (PrintCompressedOopsMode) { - tty->cr(); - tty->print_cr("Reserve regular memory without large pages."); - } - } - } - } - - if (base == NULL) { - // Optimistically assume that the OSes returns an aligned base pointer. - // When reserving a large address range, most OSes seem to align to at - // least 64K. - - // If the memory was requested at a particular address, use - // os::attempt_reserve_memory_at() to avoid over mapping something - // important. If available space is not detected, return NULL. - - if (requested_address != 0) { - base = os::attempt_reserve_memory_at(size, requested_address); - if (failed_to_reserve_as_requested(base, requested_address, size, false)) { - // OS ignored requested address. Try different address. - base = NULL; - } - } else { - base = os::reserve_memory(size, NULL, alignment); - } - - if (base == NULL) return; - - // Check alignment constraints - if ((((size_t)base) & (alignment - 1)) != 0) { - // Base not aligned, retry - if (!os::release_memory(base, size)) fatal("os::release_memory failed"); - // Make sure that size is aligned - size = align_size_up(size, alignment); - base = os::reserve_memory_aligned(size, alignment); - - if (requested_address != 0 && - failed_to_reserve_as_requested(base, requested_address, size, false)) { - // As a result of the alignment constraints, the allocated base differs - // from the requested address. Return back to the caller who can - // take remedial action (like try again without a requested address). - assert(_base == NULL, "should be"); - return; - } - } - } - // Done - _base = base; - _size = size; - _alignment = alignment; -} - - -ReservedSpace::ReservedSpace(char* base, size_t size, size_t alignment, - bool special, bool executable) { - assert((size % os::vm_allocation_granularity()) == 0, - "size not allocation aligned"); - _base = base; - _size = size; - _alignment = alignment; - _noaccess_prefix = 0; - _special = special; - _executable = executable; -} - - -ReservedSpace ReservedSpace::first_part(size_t partition_size, size_t alignment, - bool split, bool realloc) { - assert(partition_size <= size(), "partition failed"); - if (split) { - os::split_reserved_memory(base(), size(), partition_size, realloc); - } - ReservedSpace result(base(), partition_size, alignment, special(), - executable()); - return result; -} - - -ReservedSpace -ReservedSpace::last_part(size_t partition_size, size_t alignment) { - assert(partition_size <= size(), "partition failed"); - ReservedSpace result(base() + partition_size, size() - partition_size, - alignment, special(), executable()); - return result; -} - - -size_t ReservedSpace::page_align_size_up(size_t size) { - return align_size_up(size, os::vm_page_size()); -} - - -size_t ReservedSpace::page_align_size_down(size_t size) { - return align_size_down(size, os::vm_page_size()); -} - - -size_t ReservedSpace::allocation_align_size_up(size_t size) { - return align_size_up(size, os::vm_allocation_granularity()); -} - - -size_t ReservedSpace::allocation_align_size_down(size_t size) { - return align_size_down(size, os::vm_allocation_granularity()); -} - - -void ReservedSpace::release() { - if (is_reserved()) { - char *real_base = _base - _noaccess_prefix; - const size_t real_size = _size + _noaccess_prefix; - if (special()) { - os::release_memory_special(real_base, real_size); - } else{ - os::release_memory(real_base, real_size); - } - _base = NULL; - _size = 0; - _noaccess_prefix = 0; - _alignment = 0; - _special = false; - _executable = false; - } -} - -static size_t noaccess_prefix_size(size_t alignment) { - return lcm(os::vm_page_size(), alignment); -} - -void ReservedHeapSpace::establish_noaccess_prefix() { - assert(_alignment >= (size_t)os::vm_page_size(), "must be at least page size big"); - _noaccess_prefix = noaccess_prefix_size(_alignment); - - if (base() && base() + _size > (char *)OopEncodingHeapMax) { - if (true - WIN64_ONLY(&& !UseLargePages) - AIX_ONLY(&& os::vm_page_size() != SIZE_64K)) { - // Protect memory at the base of the allocated region. - // If special, the page was committed (only matters on windows) - if (!os::protect_memory(_base, _noaccess_prefix, os::MEM_PROT_NONE, _special)) { - fatal("cannot protect protection page"); - } - if (PrintCompressedOopsMode) { - tty->cr(); - tty->print_cr("Protected page at the reserved heap base: " - PTR_FORMAT " / " INTX_FORMAT " bytes", _base, _noaccess_prefix); - } - assert(Universe::narrow_oop_use_implicit_null_checks() == true, "not initialized?"); - } else { - Universe::set_narrow_oop_use_implicit_null_checks(false); - } - } - - _base += _noaccess_prefix; - _size -= _noaccess_prefix; - assert(((uintptr_t)_base % _alignment == 0), "must be exactly of required alignment"); -} - -// Tries to allocate memory of size 'size' at address requested_address with alignment 'alignment'. -// Does not check whether the reserved memory actually is at requested_address, as the memory returned -// might still fulfill the wishes of the caller. -// Assures the memory is aligned to 'alignment'. -// NOTE: If ReservedHeapSpace already points to some reserved memory this is freed, first. -void ReservedHeapSpace::try_reserve_heap(size_t size, - size_t alignment, - bool large, - char* requested_address) { - if (_base != NULL) { - // We tried before, but we didn't like the address delivered. - release(); - } - - // If OS doesn't support demand paging for large page memory, we need - // to use reserve_memory_special() to reserve and pin the entire region. - bool special = large && !os::can_commit_large_page_memory(); - char* base = NULL; - - if (PrintCompressedOopsMode && Verbose) { - tty->print("Trying to allocate at address " PTR_FORMAT " heap of size " PTR_FORMAT ".\n", - requested_address, (address)size); - } - - if (special) { - base = os::reserve_memory_special(size, alignment, requested_address, false); - - if (base != NULL) { - // Check alignment constraints. - assert((uintptr_t) base % alignment == 0, - err_msg("Large pages returned a non-aligned address, base: " - PTR_FORMAT " alignment: " PTR_FORMAT, - base, (void*)(uintptr_t)alignment)); - _special = true; - } - } - - if (base == NULL) { - // Failed; try to reserve regular memory below - if (UseLargePages && (!FLAG_IS_DEFAULT(UseLargePages) || - !FLAG_IS_DEFAULT(LargePageSizeInBytes))) { - if (PrintCompressedOopsMode) { - tty->cr(); - tty->print_cr("Reserve regular memory without large pages."); - } - } - - // Optimistically assume that the OSes returns an aligned base pointer. - // When reserving a large address range, most OSes seem to align to at - // least 64K. - - // If the memory was requested at a particular address, use - // os::attempt_reserve_memory_at() to avoid over mapping something - // important. If available space is not detected, return NULL. - - if (requested_address != 0) { - base = os::attempt_reserve_memory_at(size, requested_address); - } else { - base = os::reserve_memory(size, NULL, alignment); - } - } - if (base == NULL) { return; } - - // Done - _base = base; - _size = size; - _alignment = alignment; - - // Check alignment constraints - if ((((size_t)base) & (alignment - 1)) != 0) { - // Base not aligned, retry. - release(); - } -} - -void ReservedHeapSpace::try_reserve_range(char *highest_start, - char *lowest_start, - size_t attach_point_alignment, - char *aligned_heap_base_min_address, - char *upper_bound, - size_t size, - size_t alignment, - bool large) { - const size_t attach_range = highest_start - lowest_start; - // Cap num_attempts at possible number. - // At least one is possible even for 0 sized attach range. - const uint64_t num_attempts_possible = (attach_range / attach_point_alignment) + 1; - const uint64_t num_attempts_to_try = MIN2((uint64_t)HeapSearchSteps, num_attempts_possible); - - const size_t stepsize = (attach_range == 0) ? // Only one try. - (size_t) highest_start : align_size_up(attach_range / num_attempts_to_try, attach_point_alignment); - - // Try attach points from top to bottom. - char* attach_point = highest_start; - while (attach_point >= lowest_start && - attach_point <= highest_start && // Avoid wrap around. - ((_base == NULL) || - (_base < aligned_heap_base_min_address || _base + size > upper_bound))) { - try_reserve_heap(size, alignment, large, attach_point); - attach_point -= stepsize; - } -} - -#define SIZE_64K ((uint64_t) UCONST64( 0x10000)) -#define SIZE_256M ((uint64_t) UCONST64( 0x10000000)) -#define SIZE_32G ((uint64_t) UCONST64( 0x800000000)) - -// Helper for heap allocation. Returns an array with addresses -// (OS-specific) which are suited for disjoint base mode. Array is -// NULL terminated. -static char** get_attach_addresses_for_disjoint_mode() { - static uint64_t addresses[] = { - 2 * SIZE_32G, - 3 * SIZE_32G, - 4 * SIZE_32G, - 8 * SIZE_32G, - 10 * SIZE_32G, - 1 * SIZE_64K * SIZE_32G, - 2 * SIZE_64K * SIZE_32G, - 3 * SIZE_64K * SIZE_32G, - 4 * SIZE_64K * SIZE_32G, - 16 * SIZE_64K * SIZE_32G, - 32 * SIZE_64K * SIZE_32G, - 34 * SIZE_64K * SIZE_32G, - 0 - }; - - // Sort out addresses smaller than HeapBaseMinAddress. This assumes - // the array is sorted. - uint i = 0; - while (addresses[i] != 0 && - (addresses[i] < OopEncodingHeapMax || addresses[i] < HeapBaseMinAddress)) { - i++; - } - uint start = i; - - // Avoid more steps than requested. - i = 0; - while (addresses[start+i] != 0) { - if (i == HeapSearchSteps) { - addresses[start+i] = 0; - break; - } - i++; - } - - return (char**) &addresses[start]; -} - -void ReservedHeapSpace::initialize_compressed_heap(const size_t size, size_t alignment, bool large) { - guarantee(size + noaccess_prefix_size(alignment) <= OopEncodingHeapMax, - "can not allocate compressed oop heap for this size"); - guarantee(alignment == MAX2(alignment, (size_t)os::vm_page_size()), "alignment too small"); - assert(HeapBaseMinAddress > 0, "sanity"); - - const size_t granularity = os::vm_allocation_granularity(); - assert((size & (granularity - 1)) == 0, - "size not aligned to os::vm_allocation_granularity()"); - assert((alignment & (granularity - 1)) == 0, - "alignment not aligned to os::vm_allocation_granularity()"); - assert(alignment == 0 || is_power_of_2((intptr_t)alignment), - "not a power of 2"); - - // The necessary attach point alignment for generated wish addresses. - // This is needed to increase the chance of attaching for mmap and shmat. - const size_t os_attach_point_alignment = - AIX_ONLY(SIZE_256M) // Known shm boundary alignment. - NOT_AIX(os::vm_allocation_granularity()); - const size_t attach_point_alignment = lcm(alignment, os_attach_point_alignment); - - char *aligned_heap_base_min_address = (char *)align_ptr_up((void *)HeapBaseMinAddress, alignment); - size_t noaccess_prefix = ((aligned_heap_base_min_address + size) > (char*)OopEncodingHeapMax) ? - noaccess_prefix_size(alignment) : 0; - - // Attempt to alloc at user-given address. - if (!FLAG_IS_DEFAULT(HeapBaseMinAddress)) { - try_reserve_heap(size + noaccess_prefix, alignment, large, aligned_heap_base_min_address); - if (_base != aligned_heap_base_min_address) { // Enforce this exact address. - release(); - } - } - - // Keep heap at HeapBaseMinAddress. - if (_base == NULL) { - - // Try to allocate the heap at addresses that allow efficient oop compression. - // Different schemes are tried, in order of decreasing optimization potential. - // - // For this, try_reserve_heap() is called with the desired heap base addresses. - // A call into the os layer to allocate at a given address can return memory - // at a different address than requested. Still, this might be memory at a useful - // address. try_reserve_heap() always returns this allocated memory, as only here - // the criteria for a good heap are checked. - - // Attempt to allocate so that we can run without base and scale (32-Bit unscaled compressed oops). - // Give it several tries from top of range to bottom. - if (aligned_heap_base_min_address + size <= (char *)UnscaledOopHeapMax) { - - // Calc address range within we try to attach (range of possible start addresses). - char* const highest_start = (char *)align_ptr_down((char *)UnscaledOopHeapMax - size, attach_point_alignment); - char* const lowest_start = (char *)align_ptr_up ( aligned_heap_base_min_address , attach_point_alignment); - try_reserve_range(highest_start, lowest_start, attach_point_alignment, - aligned_heap_base_min_address, (char *)UnscaledOopHeapMax, size, alignment, large); - } - - // zerobased: Attempt to allocate in the lower 32G. - // But leave room for the compressed class pointers, which is allocated above - // the heap. - char *zerobased_max = (char *)OopEncodingHeapMax; - const size_t class_space = align_size_up(CompressedClassSpaceSize, alignment); - // For small heaps, save some space for compressed class pointer - // space so it can be decoded with no base. - if (UseCompressedClassPointers && !UseSharedSpaces && - OopEncodingHeapMax <= KlassEncodingMetaspaceMax && - (uint64_t)(aligned_heap_base_min_address + size + class_space) <= KlassEncodingMetaspaceMax) { - zerobased_max = (char *)OopEncodingHeapMax - class_space; - } - - // Give it several tries from top of range to bottom. - if (aligned_heap_base_min_address + size <= zerobased_max && // Zerobased theoretical possible. - ((_base == NULL) || // No previous try succeeded. - (_base + size > zerobased_max))) { // Unscaled delivered an arbitrary address. - - // Calc address range within we try to attach (range of possible start addresses). - char *const highest_start = (char *)align_ptr_down(zerobased_max - size, attach_point_alignment); - // Need to be careful about size being guaranteed to be less - // than UnscaledOopHeapMax due to type constraints. - char *lowest_start = aligned_heap_base_min_address; - uint64_t unscaled_end = UnscaledOopHeapMax - size; - if (unscaled_end < UnscaledOopHeapMax) { // unscaled_end wrapped if size is large - lowest_start = MAX2(lowest_start, (char*)unscaled_end); - } - lowest_start = (char *)align_ptr_up(lowest_start, attach_point_alignment); - try_reserve_range(highest_start, lowest_start, attach_point_alignment, - aligned_heap_base_min_address, zerobased_max, size, alignment, large); - } - - // Now we go for heaps with base != 0. We need a noaccess prefix to efficiently - // implement null checks. - noaccess_prefix = noaccess_prefix_size(alignment); - - // Try to attach at addresses that are aligned to OopEncodingHeapMax. Disjointbase mode. - char** addresses = get_attach_addresses_for_disjoint_mode(); - int i = 0; - while (addresses[i] && // End of array not yet reached. - ((_base == NULL) || // No previous try succeeded. - (_base + size > (char *)OopEncodingHeapMax && // Not zerobased or unscaled address. - !Universe::is_disjoint_heap_base_address((address)_base)))) { // Not disjoint address. - char* const attach_point = addresses[i]; - assert(attach_point >= aligned_heap_base_min_address, "Flag support broken"); - try_reserve_heap(size + noaccess_prefix, alignment, large, attach_point); - i++; - } - - // Last, desperate try without any placement. - if (_base == NULL) { - if (PrintCompressedOopsMode && Verbose) { - tty->print("Trying to allocate at address NULL heap of size " PTR_FORMAT ".\n", (address)size + noaccess_prefix); - } - initialize(size + noaccess_prefix, alignment, large, NULL, false); - } - } -} - -ReservedHeapSpace::ReservedHeapSpace(size_t size, size_t alignment, bool large) : ReservedSpace() { - - if (size == 0) { - return; - } - - // Heap size should be aligned to alignment, too. - guarantee(is_size_aligned(size, alignment), "set by caller"); - - if (UseCompressedOops) { - initialize_compressed_heap(size, alignment, large); - if (_size > size) { - // We allocated heap with noaccess prefix. - // It can happen we get a zerobased/unscaled heap with noaccess prefix, - // if we had to try at arbitrary address. - establish_noaccess_prefix(); - } - } else { - initialize(size, alignment, large, NULL, false); - } - - assert(markOopDesc::encode_pointer_as_mark(_base)->decode_pointer() == _base, - "area must be distinguishable from marks for mark-sweep"); - assert(markOopDesc::encode_pointer_as_mark(&_base[size])->decode_pointer() == &_base[size], - "area must be distinguishable from marks for mark-sweep"); - - if (base() > 0) { - MemTracker::record_virtual_memory_type((address)base(), mtJavaHeap); - } -} - -// Reserve space for code segment. Same as Java heap only we mark this as -// executable. -ReservedCodeSpace::ReservedCodeSpace(size_t r_size, - size_t rs_align, - bool large) : - ReservedSpace(r_size, rs_align, large, /*executable*/ true) { - MemTracker::record_virtual_memory_type((address)base(), mtCode); -} - -// VirtualSpace - -VirtualSpace::VirtualSpace() { - _low_boundary = NULL; - _high_boundary = NULL; - _low = NULL; - _high = NULL; - _lower_high = NULL; - _middle_high = NULL; - _upper_high = NULL; - _lower_high_boundary = NULL; - _middle_high_boundary = NULL; - _upper_high_boundary = NULL; - _lower_alignment = 0; - _middle_alignment = 0; - _upper_alignment = 0; - _special = false; - _executable = false; -} - - -bool VirtualSpace::initialize(ReservedSpace rs, size_t committed_size) { - const size_t max_commit_granularity = os::page_size_for_region_unaligned(rs.size(), 1); - return initialize_with_granularity(rs, committed_size, max_commit_granularity); -} - -bool VirtualSpace::initialize_with_granularity(ReservedSpace rs, size_t committed_size, size_t max_commit_granularity) { - if(!rs.is_reserved()) return false; // allocation failed. - assert(_low_boundary == NULL, "VirtualSpace already initialized"); - assert(max_commit_granularity > 0, "Granularity must be non-zero."); - - _low_boundary = rs.base(); - _high_boundary = low_boundary() + rs.size(); - - _low = low_boundary(); - _high = low(); - - _special = rs.special(); - _executable = rs.executable(); - - // When a VirtualSpace begins life at a large size, make all future expansion - // and shrinking occur aligned to a granularity of large pages. This avoids - // fragmentation of physical addresses that inhibits the use of large pages - // by the OS virtual memory system. Empirically, we see that with a 4MB - // page size, the only spaces that get handled this way are codecache and - // the heap itself, both of which provide a substantial performance - // boost in many benchmarks when covered by large pages. - // - // No attempt is made to force large page alignment at the very top and - // bottom of the space if they are not aligned so already. - _lower_alignment = os::vm_page_size(); - _middle_alignment = max_commit_granularity; - _upper_alignment = os::vm_page_size(); - - // End of each region - _lower_high_boundary = (char*) round_to((intptr_t) low_boundary(), middle_alignment()); - _middle_high_boundary = (char*) round_down((intptr_t) high_boundary(), middle_alignment()); - _upper_high_boundary = high_boundary(); - - // High address of each region - _lower_high = low_boundary(); - _middle_high = lower_high_boundary(); - _upper_high = middle_high_boundary(); - - // commit to initial size - if (committed_size > 0) { - if (!expand_by(committed_size)) { - return false; - } - } - return true; -} - - -VirtualSpace::~VirtualSpace() { - release(); -} - - -void VirtualSpace::release() { - // This does not release memory it never reserved. - // Caller must release via rs.release(); - _low_boundary = NULL; - _high_boundary = NULL; - _low = NULL; - _high = NULL; - _lower_high = NULL; - _middle_high = NULL; - _upper_high = NULL; - _lower_high_boundary = NULL; - _middle_high_boundary = NULL; - _upper_high_boundary = NULL; - _lower_alignment = 0; - _middle_alignment = 0; - _upper_alignment = 0; - _special = false; - _executable = false; -} - - -size_t VirtualSpace::committed_size() const { - return pointer_delta(high(), low(), sizeof(char)); -} - - -size_t VirtualSpace::reserved_size() const { - return pointer_delta(high_boundary(), low_boundary(), sizeof(char)); -} - - -size_t VirtualSpace::uncommitted_size() const { - return reserved_size() - committed_size(); -} - -size_t VirtualSpace::actual_committed_size() const { - // Special VirtualSpaces commit all reserved space up front. - if (special()) { - return reserved_size(); - } - - size_t committed_low = pointer_delta(_lower_high, _low_boundary, sizeof(char)); - size_t committed_middle = pointer_delta(_middle_high, _lower_high_boundary, sizeof(char)); - size_t committed_high = pointer_delta(_upper_high, _middle_high_boundary, sizeof(char)); - -#ifdef ASSERT - size_t lower = pointer_delta(_lower_high_boundary, _low_boundary, sizeof(char)); - size_t middle = pointer_delta(_middle_high_boundary, _lower_high_boundary, sizeof(char)); - size_t upper = pointer_delta(_upper_high_boundary, _middle_high_boundary, sizeof(char)); - - if (committed_high > 0) { - assert(committed_low == lower, "Must be"); - assert(committed_middle == middle, "Must be"); - } - - if (committed_middle > 0) { - assert(committed_low == lower, "Must be"); - } - if (committed_middle < middle) { - assert(committed_high == 0, "Must be"); - } - - if (committed_low < lower) { - assert(committed_high == 0, "Must be"); - assert(committed_middle == 0, "Must be"); - } -#endif - - return committed_low + committed_middle + committed_high; -} - - -bool VirtualSpace::contains(const void* p) const { - return low() <= (const char*) p && (const char*) p < high(); -} - -/* - First we need to determine if a particular virtual space is using large - pages. This is done at the initialize function and only virtual spaces - that are larger than LargePageSizeInBytes use large pages. Once we - have determined this, all expand_by and shrink_by calls must grow and - shrink by large page size chunks. If a particular request - is within the current large page, the call to commit and uncommit memory - can be ignored. In the case that the low and high boundaries of this - space is not large page aligned, the pages leading to the first large - page address and the pages after the last large page address must be - allocated with default pages. -*/ -bool VirtualSpace::expand_by(size_t bytes, bool pre_touch) { - if (uncommitted_size() < bytes) return false; - - if (special()) { - // don't commit memory if the entire space is pinned in memory - _high += bytes; - return true; - } - - char* previous_high = high(); - char* unaligned_new_high = high() + bytes; - assert(unaligned_new_high <= high_boundary(), - "cannot expand by more than upper boundary"); - - // Calculate where the new high for each of the regions should be. If - // the low_boundary() and high_boundary() are LargePageSizeInBytes aligned - // then the unaligned lower and upper new highs would be the - // lower_high() and upper_high() respectively. - char* unaligned_lower_new_high = - MIN2(unaligned_new_high, lower_high_boundary()); - char* unaligned_middle_new_high = - MIN2(unaligned_new_high, middle_high_boundary()); - char* unaligned_upper_new_high = - MIN2(unaligned_new_high, upper_high_boundary()); - - // Align the new highs based on the regions alignment. lower and upper - // alignment will always be default page size. middle alignment will be - // LargePageSizeInBytes if the actual size of the virtual space is in - // fact larger than LargePageSizeInBytes. - char* aligned_lower_new_high = - (char*) round_to((intptr_t) unaligned_lower_new_high, lower_alignment()); - char* aligned_middle_new_high = - (char*) round_to((intptr_t) unaligned_middle_new_high, middle_alignment()); - char* aligned_upper_new_high = - (char*) round_to((intptr_t) unaligned_upper_new_high, upper_alignment()); - - // Determine which regions need to grow in this expand_by call. - // If you are growing in the lower region, high() must be in that - // region so calculate the size based on high(). For the middle and - // upper regions, determine the starting point of growth based on the - // location of high(). By getting the MAX of the region's low address - // (or the previous region's high address) and high(), we can tell if it - // is an intra or inter region growth. - size_t lower_needs = 0; - if (aligned_lower_new_high > lower_high()) { - lower_needs = - pointer_delta(aligned_lower_new_high, lower_high(), sizeof(char)); - } - size_t middle_needs = 0; - if (aligned_middle_new_high > middle_high()) { - middle_needs = - pointer_delta(aligned_middle_new_high, middle_high(), sizeof(char)); - } - size_t upper_needs = 0; - if (aligned_upper_new_high > upper_high()) { - upper_needs = - pointer_delta(aligned_upper_new_high, upper_high(), sizeof(char)); - } - - // Check contiguity. - assert(low_boundary() <= lower_high() && - lower_high() <= lower_high_boundary(), - "high address must be contained within the region"); - assert(lower_high_boundary() <= middle_high() && - middle_high() <= middle_high_boundary(), - "high address must be contained within the region"); - assert(middle_high_boundary() <= upper_high() && - upper_high() <= upper_high_boundary(), - "high address must be contained within the region"); - - // Commit regions - if (lower_needs > 0) { - assert(low_boundary() <= lower_high() && - lower_high() + lower_needs <= lower_high_boundary(), - "must not expand beyond region"); - if (!os::commit_memory(lower_high(), lower_needs, _executable)) { - debug_only(warning("INFO: os::commit_memory(" PTR_FORMAT - ", lower_needs=" SIZE_FORMAT ", %d) failed", - lower_high(), lower_needs, _executable);) - return false; - } else { - _lower_high += lower_needs; - } - } - if (middle_needs > 0) { - assert(lower_high_boundary() <= middle_high() && - middle_high() + middle_needs <= middle_high_boundary(), - "must not expand beyond region"); - if (!os::commit_memory(middle_high(), middle_needs, middle_alignment(), - _executable)) { - debug_only(warning("INFO: os::commit_memory(" PTR_FORMAT - ", middle_needs=" SIZE_FORMAT ", " SIZE_FORMAT - ", %d) failed", middle_high(), middle_needs, - middle_alignment(), _executable);) - return false; - } - _middle_high += middle_needs; - } - if (upper_needs > 0) { - assert(middle_high_boundary() <= upper_high() && - upper_high() + upper_needs <= upper_high_boundary(), - "must not expand beyond region"); - if (!os::commit_memory(upper_high(), upper_needs, _executable)) { - debug_only(warning("INFO: os::commit_memory(" PTR_FORMAT - ", upper_needs=" SIZE_FORMAT ", %d) failed", - upper_high(), upper_needs, _executable);) - return false; - } else { - _upper_high += upper_needs; - } - } - - if (pre_touch || AlwaysPreTouch) { - os::pretouch_memory(previous_high, unaligned_new_high); - } - - _high += bytes; - return true; -} - -// A page is uncommitted if the contents of the entire page is deemed unusable. -// Continue to decrement the high() pointer until it reaches a page boundary -// in which case that particular page can now be uncommitted. -void VirtualSpace::shrink_by(size_t size) { - if (committed_size() < size) - fatal("Cannot shrink virtual space to negative size"); - - if (special()) { - // don't uncommit if the entire space is pinned in memory - _high -= size; - return; - } - - char* unaligned_new_high = high() - size; - assert(unaligned_new_high >= low_boundary(), "cannot shrink past lower boundary"); - - // Calculate new unaligned address - char* unaligned_upper_new_high = - MAX2(unaligned_new_high, middle_high_boundary()); - char* unaligned_middle_new_high = - MAX2(unaligned_new_high, lower_high_boundary()); - char* unaligned_lower_new_high = - MAX2(unaligned_new_high, low_boundary()); - - // Align address to region's alignment - char* aligned_upper_new_high = - (char*) round_to((intptr_t) unaligned_upper_new_high, upper_alignment()); - char* aligned_middle_new_high = - (char*) round_to((intptr_t) unaligned_middle_new_high, middle_alignment()); - char* aligned_lower_new_high = - (char*) round_to((intptr_t) unaligned_lower_new_high, lower_alignment()); - - // Determine which regions need to shrink - size_t upper_needs = 0; - if (aligned_upper_new_high < upper_high()) { - upper_needs = - pointer_delta(upper_high(), aligned_upper_new_high, sizeof(char)); - } - size_t middle_needs = 0; - if (aligned_middle_new_high < middle_high()) { - middle_needs = - pointer_delta(middle_high(), aligned_middle_new_high, sizeof(char)); - } - size_t lower_needs = 0; - if (aligned_lower_new_high < lower_high()) { - lower_needs = - pointer_delta(lower_high(), aligned_lower_new_high, sizeof(char)); - } - - // Check contiguity. - assert(middle_high_boundary() <= upper_high() && - upper_high() <= upper_high_boundary(), - "high address must be contained within the region"); - assert(lower_high_boundary() <= middle_high() && - middle_high() <= middle_high_boundary(), - "high address must be contained within the region"); - assert(low_boundary() <= lower_high() && - lower_high() <= lower_high_boundary(), - "high address must be contained within the region"); - - // Uncommit - if (upper_needs > 0) { - assert(middle_high_boundary() <= aligned_upper_new_high && - aligned_upper_new_high + upper_needs <= upper_high_boundary(), - "must not shrink beyond region"); - if (!os::uncommit_memory(aligned_upper_new_high, upper_needs)) { - debug_only(warning("os::uncommit_memory failed")); - return; - } else { - _upper_high -= upper_needs; - } - } - if (middle_needs > 0) { - assert(lower_high_boundary() <= aligned_middle_new_high && - aligned_middle_new_high + middle_needs <= middle_high_boundary(), - "must not shrink beyond region"); - if (!os::uncommit_memory(aligned_middle_new_high, middle_needs)) { - debug_only(warning("os::uncommit_memory failed")); - return; - } else { - _middle_high -= middle_needs; - } - } - if (lower_needs > 0) { - assert(low_boundary() <= aligned_lower_new_high && - aligned_lower_new_high + lower_needs <= lower_high_boundary(), - "must not shrink beyond region"); - if (!os::uncommit_memory(aligned_lower_new_high, lower_needs)) { - debug_only(warning("os::uncommit_memory failed")); - return; - } else { - _lower_high -= lower_needs; - } - } - - _high -= size; -} - -#ifndef PRODUCT -void VirtualSpace::check_for_contiguity() { - // Check contiguity. - assert(low_boundary() <= lower_high() && - lower_high() <= lower_high_boundary(), - "high address must be contained within the region"); - assert(lower_high_boundary() <= middle_high() && - middle_high() <= middle_high_boundary(), - "high address must be contained within the region"); - assert(middle_high_boundary() <= upper_high() && - upper_high() <= upper_high_boundary(), - "high address must be contained within the region"); - assert(low() >= low_boundary(), "low"); - assert(low_boundary() <= lower_high_boundary(), "lower high boundary"); - assert(upper_high_boundary() <= high_boundary(), "upper high boundary"); - assert(high() <= upper_high(), "upper high"); -} - -void VirtualSpace::print_on(outputStream* out) { - out->print ("Virtual space:"); - if (special()) out->print(" (pinned in memory)"); - out->cr(); - out->print_cr(" - committed: " SIZE_FORMAT, committed_size()); - out->print_cr(" - reserved: " SIZE_FORMAT, reserved_size()); - out->print_cr(" - [low, high]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]", low(), high()); - out->print_cr(" - [low_b, high_b]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]", low_boundary(), high_boundary()); -} - -void VirtualSpace::print() { - print_on(tty); -} - -/////////////// Unit tests /////////////// - -#ifndef PRODUCT - -#define test_log(...) \ - do {\ - if (VerboseInternalVMTests) { \ - tty->print_cr(__VA_ARGS__); \ - tty->flush(); \ - }\ - } while (false) - -class TestReservedSpace : AllStatic { - public: - static void small_page_write(void* addr, size_t size) { - size_t page_size = os::vm_page_size(); - - char* end = (char*)addr + size; - for (char* p = (char*)addr; p < end; p += page_size) { - *p = 1; - } - } - - static void release_memory_for_test(ReservedSpace rs) { - if (rs.special()) { - guarantee(os::release_memory_special(rs.base(), rs.size()), "Shouldn't fail"); - } else { - guarantee(os::release_memory(rs.base(), rs.size()), "Shouldn't fail"); - } - } - - static void test_reserved_space1(size_t size, size_t alignment) { - test_log("test_reserved_space1(%p)", (void*) (uintptr_t) size); - - assert(is_size_aligned(size, alignment), "Incorrect input parameters"); - - ReservedSpace rs(size, // size - alignment, // alignment - UseLargePages, // large - (char *)NULL); // requested_address - - test_log(" rs.special() == %d", rs.special()); - - assert(rs.base() != NULL, "Must be"); - assert(rs.size() == size, "Must be"); - - assert(is_ptr_aligned(rs.base(), alignment), "aligned sizes should always give aligned addresses"); - assert(is_size_aligned(rs.size(), alignment), "aligned sizes should always give aligned addresses"); - - if (rs.special()) { - small_page_write(rs.base(), size); - } - - release_memory_for_test(rs); - } - - static void test_reserved_space2(size_t size) { - test_log("test_reserved_space2(%p)", (void*)(uintptr_t)size); - - assert(is_size_aligned(size, os::vm_allocation_granularity()), "Must be at least AG aligned"); - - ReservedSpace rs(size); - - test_log(" rs.special() == %d", rs.special()); - - assert(rs.base() != NULL, "Must be"); - assert(rs.size() == size, "Must be"); - - if (rs.special()) { - small_page_write(rs.base(), size); - } - - release_memory_for_test(rs); - } - - static void test_reserved_space3(size_t size, size_t alignment, bool maybe_large) { - test_log("test_reserved_space3(%p, %p, %d)", - (void*)(uintptr_t)size, (void*)(uintptr_t)alignment, maybe_large); - - assert(is_size_aligned(size, os::vm_allocation_granularity()), "Must be at least AG aligned"); - assert(is_size_aligned(size, alignment), "Must be at least aligned against alignment"); - - bool large = maybe_large && UseLargePages && size >= os::large_page_size(); - - ReservedSpace rs(size, alignment, large, false); - - test_log(" rs.special() == %d", rs.special()); - - assert(rs.base() != NULL, "Must be"); - assert(rs.size() == size, "Must be"); - - if (rs.special()) { - small_page_write(rs.base(), size); - } - - release_memory_for_test(rs); - } - - - static void test_reserved_space1() { - size_t size = 2 * 1024 * 1024; - size_t ag = os::vm_allocation_granularity(); - - test_reserved_space1(size, ag); - test_reserved_space1(size * 2, ag); - test_reserved_space1(size * 10, ag); - } - - static void test_reserved_space2() { - size_t size = 2 * 1024 * 1024; - size_t ag = os::vm_allocation_granularity(); - - test_reserved_space2(size * 1); - test_reserved_space2(size * 2); - test_reserved_space2(size * 10); - test_reserved_space2(ag); - test_reserved_space2(size - ag); - test_reserved_space2(size); - test_reserved_space2(size + ag); - test_reserved_space2(size * 2); - test_reserved_space2(size * 2 - ag); - test_reserved_space2(size * 2 + ag); - test_reserved_space2(size * 3); - test_reserved_space2(size * 3 - ag); - test_reserved_space2(size * 3 + ag); - test_reserved_space2(size * 10); - test_reserved_space2(size * 10 + size / 2); - } - - static void test_reserved_space3() { - size_t ag = os::vm_allocation_granularity(); - - test_reserved_space3(ag, ag , false); - test_reserved_space3(ag * 2, ag , false); - test_reserved_space3(ag * 3, ag , false); - test_reserved_space3(ag * 2, ag * 2, false); - test_reserved_space3(ag * 4, ag * 2, false); - test_reserved_space3(ag * 8, ag * 2, false); - test_reserved_space3(ag * 4, ag * 4, false); - test_reserved_space3(ag * 8, ag * 4, false); - test_reserved_space3(ag * 16, ag * 4, false); - - if (UseLargePages) { - size_t lp = os::large_page_size(); - - // Without large pages - test_reserved_space3(lp, ag * 4, false); - test_reserved_space3(lp * 2, ag * 4, false); - test_reserved_space3(lp * 4, ag * 4, false); - test_reserved_space3(lp, lp , false); - test_reserved_space3(lp * 2, lp , false); - test_reserved_space3(lp * 3, lp , false); - test_reserved_space3(lp * 2, lp * 2, false); - test_reserved_space3(lp * 4, lp * 2, false); - test_reserved_space3(lp * 8, lp * 2, false); - - // With large pages - test_reserved_space3(lp, ag * 4 , true); - test_reserved_space3(lp * 2, ag * 4, true); - test_reserved_space3(lp * 4, ag * 4, true); - test_reserved_space3(lp, lp , true); - test_reserved_space3(lp * 2, lp , true); - test_reserved_space3(lp * 3, lp , true); - test_reserved_space3(lp * 2, lp * 2, true); - test_reserved_space3(lp * 4, lp * 2, true); - test_reserved_space3(lp * 8, lp * 2, true); - } - } - - static void test_reserved_space() { - test_reserved_space1(); - test_reserved_space2(); - test_reserved_space3(); - } -}; - -void TestReservedSpace_test() { - TestReservedSpace::test_reserved_space(); -} - -#define assert_equals(actual, expected) \ - assert(actual == expected, \ - err_msg("Got " SIZE_FORMAT " expected " \ - SIZE_FORMAT, actual, expected)); - -#define assert_ge(value1, value2) \ - assert(value1 >= value2, \ - err_msg("'" #value1 "': " SIZE_FORMAT " '" \ - #value2 "': " SIZE_FORMAT, value1, value2)); - -#define assert_lt(value1, value2) \ - assert(value1 < value2, \ - err_msg("'" #value1 "': " SIZE_FORMAT " '" \ - #value2 "': " SIZE_FORMAT, value1, value2)); - - -class TestVirtualSpace : AllStatic { - enum TestLargePages { - Default, - Disable, - Reserve, - Commit - }; - - static ReservedSpace reserve_memory(size_t reserve_size_aligned, TestLargePages mode) { - switch(mode) { - default: - case Default: - case Reserve: - return ReservedSpace(reserve_size_aligned); - case Disable: - case Commit: - return ReservedSpace(reserve_size_aligned, - os::vm_allocation_granularity(), - /* large */ false, /* exec */ false); - } - } - - static bool initialize_virtual_space(VirtualSpace& vs, ReservedSpace rs, TestLargePages mode) { - switch(mode) { - default: - case Default: - case Reserve: - return vs.initialize(rs, 0); - case Disable: - return vs.initialize_with_granularity(rs, 0, os::vm_page_size()); - case Commit: - return vs.initialize_with_granularity(rs, 0, os::page_size_for_region_unaligned(rs.size(), 1)); - } - } - - public: - static void test_virtual_space_actual_committed_space(size_t reserve_size, size_t commit_size, - TestLargePages mode = Default) { - size_t granularity = os::vm_allocation_granularity(); - size_t reserve_size_aligned = align_size_up(reserve_size, granularity); - - ReservedSpace reserved = reserve_memory(reserve_size_aligned, mode); - - assert(reserved.is_reserved(), "Must be"); - - VirtualSpace vs; - bool initialized = initialize_virtual_space(vs, reserved, mode); - assert(initialized, "Failed to initialize VirtualSpace"); - - vs.expand_by(commit_size, false); - - if (vs.special()) { - assert_equals(vs.actual_committed_size(), reserve_size_aligned); - } else { - assert_ge(vs.actual_committed_size(), commit_size); - // Approximate the commit granularity. - // Make sure that we don't commit using large pages - // if large pages has been disabled for this VirtualSpace. - size_t commit_granularity = (mode == Disable || !UseLargePages) ? - os::vm_page_size() : os::large_page_size(); - assert_lt(vs.actual_committed_size(), commit_size + commit_granularity); - } - - reserved.release(); - } - - static void test_virtual_space_actual_committed_space_one_large_page() { - if (!UseLargePages) { - return; - } - - size_t large_page_size = os::large_page_size(); - - ReservedSpace reserved(large_page_size, large_page_size, true, false); - - assert(reserved.is_reserved(), "Must be"); - - VirtualSpace vs; - bool initialized = vs.initialize(reserved, 0); - assert(initialized, "Failed to initialize VirtualSpace"); - - vs.expand_by(large_page_size, false); - - assert_equals(vs.actual_committed_size(), large_page_size); - - reserved.release(); - } - - static void test_virtual_space_actual_committed_space() { - test_virtual_space_actual_committed_space(4 * K, 0); - test_virtual_space_actual_committed_space(4 * K, 4 * K); - test_virtual_space_actual_committed_space(8 * K, 0); - test_virtual_space_actual_committed_space(8 * K, 4 * K); - test_virtual_space_actual_committed_space(8 * K, 8 * K); - test_virtual_space_actual_committed_space(12 * K, 0); - test_virtual_space_actual_committed_space(12 * K, 4 * K); - test_virtual_space_actual_committed_space(12 * K, 8 * K); - test_virtual_space_actual_committed_space(12 * K, 12 * K); - test_virtual_space_actual_committed_space(64 * K, 0); - test_virtual_space_actual_committed_space(64 * K, 32 * K); - test_virtual_space_actual_committed_space(64 * K, 64 * K); - test_virtual_space_actual_committed_space(2 * M, 0); - test_virtual_space_actual_committed_space(2 * M, 4 * K); - test_virtual_space_actual_committed_space(2 * M, 64 * K); - test_virtual_space_actual_committed_space(2 * M, 1 * M); - test_virtual_space_actual_committed_space(2 * M, 2 * M); - test_virtual_space_actual_committed_space(10 * M, 0); - test_virtual_space_actual_committed_space(10 * M, 4 * K); - test_virtual_space_actual_committed_space(10 * M, 8 * K); - test_virtual_space_actual_committed_space(10 * M, 1 * M); - test_virtual_space_actual_committed_space(10 * M, 2 * M); - test_virtual_space_actual_committed_space(10 * M, 5 * M); - test_virtual_space_actual_committed_space(10 * M, 10 * M); - } - - static void test_virtual_space_disable_large_pages() { - if (!UseLargePages) { - return; - } - // These test cases verify that if we force VirtualSpace to disable large pages - test_virtual_space_actual_committed_space(10 * M, 0, Disable); - test_virtual_space_actual_committed_space(10 * M, 4 * K, Disable); - test_virtual_space_actual_committed_space(10 * M, 8 * K, Disable); - test_virtual_space_actual_committed_space(10 * M, 1 * M, Disable); - test_virtual_space_actual_committed_space(10 * M, 2 * M, Disable); - test_virtual_space_actual_committed_space(10 * M, 5 * M, Disable); - test_virtual_space_actual_committed_space(10 * M, 10 * M, Disable); - - test_virtual_space_actual_committed_space(10 * M, 0, Reserve); - test_virtual_space_actual_committed_space(10 * M, 4 * K, Reserve); - test_virtual_space_actual_committed_space(10 * M, 8 * K, Reserve); - test_virtual_space_actual_committed_space(10 * M, 1 * M, Reserve); - test_virtual_space_actual_committed_space(10 * M, 2 * M, Reserve); - test_virtual_space_actual_committed_space(10 * M, 5 * M, Reserve); - test_virtual_space_actual_committed_space(10 * M, 10 * M, Reserve); - - test_virtual_space_actual_committed_space(10 * M, 0, Commit); - test_virtual_space_actual_committed_space(10 * M, 4 * K, Commit); - test_virtual_space_actual_committed_space(10 * M, 8 * K, Commit); - test_virtual_space_actual_committed_space(10 * M, 1 * M, Commit); - test_virtual_space_actual_committed_space(10 * M, 2 * M, Commit); - test_virtual_space_actual_committed_space(10 * M, 5 * M, Commit); - test_virtual_space_actual_committed_space(10 * M, 10 * M, Commit); - } - - static void test_virtual_space() { - test_virtual_space_actual_committed_space(); - test_virtual_space_actual_committed_space_one_large_page(); - test_virtual_space_disable_large_pages(); - } -}; - -void TestVirtualSpace_test() { - TestVirtualSpace::test_virtual_space(); -} - -#endif // PRODUCT - -#endif diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/virtualspace.hpp --- a/hotspot/src/share/vm/runtime/virtualspace.hpp Thu May 07 10:19:31 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,218 +0,0 @@ -/* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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_RUNTIME_VIRTUALSPACE_HPP -#define SHARE_VM_RUNTIME_VIRTUALSPACE_HPP - -#include "memory/allocation.hpp" - -// ReservedSpace is a data structure for reserving a contiguous address range. - -class ReservedSpace VALUE_OBJ_CLASS_SPEC { - friend class VMStructs; - protected: - char* _base; - size_t _size; - size_t _noaccess_prefix; - size_t _alignment; - bool _special; - private: - bool _executable; - - // ReservedSpace - ReservedSpace(char* base, size_t size, size_t alignment, bool special, - bool executable); - protected: - void initialize(size_t size, size_t alignment, bool large, - char* requested_address, - bool executable); - - public: - // Constructor - ReservedSpace(); - ReservedSpace(size_t size); - ReservedSpace(size_t size, size_t alignment, bool large, - char* requested_address = NULL); - ReservedSpace(size_t size, size_t alignment, bool large, bool executable); - - // Accessors - char* base() const { return _base; } - size_t size() const { return _size; } - size_t alignment() const { return _alignment; } - bool special() const { return _special; } - bool executable() const { return _executable; } - size_t noaccess_prefix() const { return _noaccess_prefix; } - bool is_reserved() const { return _base != NULL; } - void release(); - - // Splitting - ReservedSpace first_part(size_t partition_size, size_t alignment, - bool split = false, bool realloc = true); - ReservedSpace last_part (size_t partition_size, size_t alignment); - - // These simply call the above using the default alignment. - inline ReservedSpace first_part(size_t partition_size, - bool split = false, bool realloc = true); - inline ReservedSpace last_part (size_t partition_size); - - // Alignment - static size_t page_align_size_up(size_t size); - static size_t page_align_size_down(size_t size); - static size_t allocation_align_size_up(size_t size); - static size_t allocation_align_size_down(size_t size); -}; - -ReservedSpace -ReservedSpace::first_part(size_t partition_size, bool split, bool realloc) -{ - return first_part(partition_size, alignment(), split, realloc); -} - -ReservedSpace ReservedSpace::last_part(size_t partition_size) -{ - return last_part(partition_size, alignment()); -} - -// Class encapsulating behavior specific of memory space reserved for Java heap. -class ReservedHeapSpace : public ReservedSpace { - private: - void try_reserve_heap(size_t size, size_t alignment, bool large, - char *requested_address); - void try_reserve_range(char *highest_start, char *lowest_start, - size_t attach_point_alignment, char *aligned_HBMA, - char *upper_bound, size_t size, size_t alignment, bool large); - void initialize_compressed_heap(const size_t size, size_t alignment, bool large); - // Create protection page at the beginning of the space. - void establish_noaccess_prefix(); - public: - // Constructor. Tries to find a heap that is good for compressed oops. - ReservedHeapSpace(size_t size, size_t forced_base_alignment, bool large); - // Returns the base to be used for compression, i.e. so that null can be - // encoded safely and implicit null checks can work. - char *compressed_oop_base() { return _base - _noaccess_prefix; } -}; - -// Class encapsulating behavior specific memory space for Code -class ReservedCodeSpace : public ReservedSpace { - public: - // Constructor - ReservedCodeSpace(size_t r_size, size_t rs_align, bool large); -}; - -// VirtualSpace is data structure for committing a previously reserved address range in smaller chunks. - -class VirtualSpace VALUE_OBJ_CLASS_SPEC { - friend class VMStructs; - private: - // Reserved area - char* _low_boundary; - char* _high_boundary; - - // Committed area - char* _low; - char* _high; - - // The entire space has been committed and pinned in memory, no - // os::commit_memory() or os::uncommit_memory(). - bool _special; - - // Need to know if commit should be executable. - bool _executable; - - // MPSS Support - // Each virtualspace region has a lower, middle, and upper region. - // Each region has an end boundary and a high pointer which is the - // high water mark for the last allocated byte. - // The lower and upper unaligned to LargePageSizeInBytes uses default page. - // size. The middle region uses large page size. - char* _lower_high; - char* _middle_high; - char* _upper_high; - - char* _lower_high_boundary; - char* _middle_high_boundary; - char* _upper_high_boundary; - - size_t _lower_alignment; - size_t _middle_alignment; - size_t _upper_alignment; - - // MPSS Accessors - char* lower_high() const { return _lower_high; } - char* middle_high() const { return _middle_high; } - char* upper_high() const { return _upper_high; } - - char* lower_high_boundary() const { return _lower_high_boundary; } - char* middle_high_boundary() const { return _middle_high_boundary; } - char* upper_high_boundary() const { return _upper_high_boundary; } - - size_t lower_alignment() const { return _lower_alignment; } - size_t middle_alignment() const { return _middle_alignment; } - size_t upper_alignment() const { return _upper_alignment; } - - public: - // Committed area - char* low() const { return _low; } - char* high() const { return _high; } - - // Reserved area - char* low_boundary() const { return _low_boundary; } - char* high_boundary() const { return _high_boundary; } - - bool special() const { return _special; } - - public: - // Initialization - VirtualSpace(); - bool initialize_with_granularity(ReservedSpace rs, size_t committed_byte_size, size_t max_commit_ganularity); - bool initialize(ReservedSpace rs, size_t committed_byte_size); - - // Destruction - ~VirtualSpace(); - - // Reserved memory - size_t reserved_size() const; - // Actually committed OS memory - size_t actual_committed_size() const; - // Memory used/expanded in this virtual space - size_t committed_size() const; - // Memory left to use/expand in this virtual space - size_t uncommitted_size() const; - - bool contains(const void* p) const; - - // Operations - // returns true on success, false otherwise - bool expand_by(size_t bytes, bool pre_touch = false); - void shrink_by(size_t bytes); - void release(); - - void check_for_contiguity() PRODUCT_RETURN; - - // Debugging - void print_on(outputStream* out) PRODUCT_RETURN; - void print(); -}; - -#endif // SHARE_VM_RUNTIME_VIRTUALSPACE_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/runtime/vmStructs.cpp --- a/hotspot/src/share/vm/runtime/vmStructs.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Thu May 07 20:51:12 2015 -0700 @@ -65,6 +65,7 @@ #include "memory/space.hpp" #include "memory/tenuredGeneration.hpp" #include "memory/universe.hpp" +#include "memory/virtualspace.hpp" #include "memory/watermark.hpp" #include "oops/arrayKlass.hpp" #include "oops/arrayOop.hpp" @@ -100,7 +101,6 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/thread.inline.hpp" -#include "runtime/virtualspace.hpp" #include "runtime/vmStructs.hpp" #include "utilities/array.hpp" #include "utilities/globalDefinitions.hpp" @@ -555,10 +555,8 @@ nonstatic_field(GenerationSpec, _init_size, size_t) \ nonstatic_field(GenerationSpec, _max_size, size_t) \ \ - static_field(GenCollectedHeap, _gch, GenCollectedHeap*) \ nonstatic_field(GenCollectedHeap, _young_gen, Generation*) \ nonstatic_field(GenCollectedHeap, _old_gen, Generation*) \ - nonstatic_field(GenCollectedHeap, _n_gens, int) \ \ nonstatic_field(GenCollectorPolicy, _young_gen_spec, GenerationSpec*) \ nonstatic_field(GenCollectorPolicy, _old_gen_spec, GenerationSpec*) \ @@ -1501,8 +1499,7 @@ /******************************************/ \ \ declare_toplevel_type(CollectedHeap) \ - declare_type(SharedHeap, CollectedHeap) \ - declare_type(GenCollectedHeap, SharedHeap) \ + declare_type(GenCollectedHeap, CollectedHeap) \ declare_toplevel_type(Generation) \ declare_type(DefNewGeneration, Generation) \ declare_type(CardGeneration, Generation) \ @@ -1985,13 +1982,18 @@ declare_c2_type(PowDNode, Node) \ declare_c2_type(ReverseBytesINode, Node) \ declare_c2_type(ReverseBytesLNode, Node) \ + declare_c2_type(ReductionNode, Node) \ declare_c2_type(VectorNode, Node) \ declare_c2_type(AddVBNode, VectorNode) \ declare_c2_type(AddVSNode, VectorNode) \ declare_c2_type(AddVINode, VectorNode) \ + declare_c2_type(AddReductionVINode, ReductionNode) \ declare_c2_type(AddVLNode, VectorNode) \ + declare_c2_type(AddReductionVLNode, ReductionNode) \ declare_c2_type(AddVFNode, VectorNode) \ + declare_c2_type(AddReductionVFNode, ReductionNode) \ declare_c2_type(AddVDNode, VectorNode) \ + declare_c2_type(AddReductionVDNode, ReductionNode) \ declare_c2_type(SubVBNode, VectorNode) \ declare_c2_type(SubVSNode, VectorNode) \ declare_c2_type(SubVINode, VectorNode) \ @@ -2000,8 +2002,11 @@ declare_c2_type(SubVDNode, VectorNode) \ declare_c2_type(MulVSNode, VectorNode) \ declare_c2_type(MulVINode, VectorNode) \ + declare_c2_type(MulReductionVINode, ReductionNode) \ declare_c2_type(MulVFNode, VectorNode) \ + declare_c2_type(MulReductionVFNode, ReductionNode) \ declare_c2_type(MulVDNode, VectorNode) \ + declare_c2_type(MulReductionVDNode, ReductionNode) \ declare_c2_type(DivVFNode, VectorNode) \ declare_c2_type(DivVDNode, VectorNode) \ declare_c2_type(LShiftVBNode, VectorNode) \ @@ -2257,8 +2262,6 @@ declare_constant(CollectedHeap::ParallelScavengeHeap) \ declare_constant(CollectedHeap::G1CollectedHeap) \ \ - declare_constant(GenCollectedHeap::max_gens) \ - \ /* constants from Generation::Name enum */ \ \ declare_constant(Generation::DefNew) \ @@ -2516,6 +2519,7 @@ declare_constant(Deoptimization::Reason_speculate_null_check) \ declare_constant(Deoptimization::Reason_rtm_state_change) \ declare_constant(Deoptimization::Reason_unstable_if) \ + declare_constant(Deoptimization::Reason_unstable_fused_if) \ declare_constant(Deoptimization::Reason_tenured) \ declare_constant(Deoptimization::Reason_LIMIT) \ declare_constant(Deoptimization::Reason_RECORDED_LIMIT) \ diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/services/diagnosticCommand.cpp --- a/hotspot/src/share/vm/services/diagnosticCommand.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp Thu May 07 20:51:12 2015 -0700 @@ -32,6 +32,7 @@ #include "services/diagnosticArgument.hpp" #include "services/diagnosticCommand.hpp" #include "services/diagnosticFramework.hpp" +#include "services/writeableFlags.hpp" #include "services/heapDumper.hpp" #include "services/management.hpp" #include "utilities/macros.hpp" @@ -50,6 +51,7 @@ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); @@ -62,6 +64,9 @@ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); #endif // INCLUDE_SERVICES +#if INCLUDE_JVMTI + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); +#endif // INCLUDE_JVMTI DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); @@ -76,6 +81,7 @@ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(jmx_agent_export_flags, true,false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(jmx_agent_export_flags, true,false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(jmx_agent_export_flags, true,false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(jmx_agent_export_flags, true,false)); } @@ -197,6 +203,46 @@ } } +SetVMFlagDCmd::SetVMFlagDCmd(outputStream* output, bool heap) : + DCmdWithParser(output, heap), + _flag("flag name", "The name of the flag we want to set", + "STRING", true), + _value("string value", "The value we want to set", "STRING", false) { + _dcmdparser.add_dcmd_argument(&_flag); + _dcmdparser.add_dcmd_argument(&_value); +} + +void SetVMFlagDCmd::execute(DCmdSource source, TRAPS) { + const char* val = NULL; + if (_value.value() != NULL) { + val = _value.value(); + } + + FormatBuffer<80> err_msg("%s", ""); + int ret = WriteableFlags::set_flag(_flag.value(), val, Flag::MANAGEMENT, err_msg); + + if (ret != WriteableFlags::SUCCESS) { + output()->print_cr("%s", err_msg.buffer()); + } +} + +int SetVMFlagDCmd::num_arguments() { + ResourceMark rm; + SetVMFlagDCmd* dcmd = new SetVMFlagDCmd(NULL, false); + if (dcmd != NULL) { + DCmdMark mark(dcmd); + return dcmd->_dcmdparser.num_arguments(); + } else { + return 0; + } +} + +void JVMTIDataDumpDCmd::execute(DCmdSource source, TRAPS) { + if (JvmtiExport::should_post_data_dump()) { + JvmtiExport::post_data_dump(); + } +} + void PrintSystemPropertiesDCmd::execute(DCmdSource source, TRAPS) { // load sun.misc.VMSupport Symbol* klass = vmSymbols::sun_misc_VMSupport(); @@ -663,6 +709,38 @@ JavaCalls::call_static(&result, ik, vmSymbols::stopRemoteAgent_name(), vmSymbols::void_method_signature(), CHECK); } +JMXStatusDCmd::JMXStatusDCmd(outputStream *output, bool heap_allocated) : + DCmd(output, heap_allocated) { + // do nothing +} + +void JMXStatusDCmd::execute(DCmdSource source, TRAPS) { + ResourceMark rm(THREAD); + HandleMark hm(THREAD); + + // Load and initialize the sun.management.Agent class + // invoke getManagementAgentStatus() method to generate the status info + // throw java.lang.NoSuchMethodError if method doesn't exist + + Handle loader = Handle(THREAD, SystemDictionary::java_system_loader()); + Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::sun_management_Agent(), loader, Handle(), true, CHECK); + instanceKlassHandle ik (THREAD, k); + + JavaValue result(T_OBJECT); + JavaCalls::call_static(&result, ik, vmSymbols::getAgentStatus_name(), vmSymbols::void_string_signature(), CHECK); + + jvalue* jv = (jvalue*) result.get_value_addr(); + oop str = (oop) jv->l; + if (str != NULL) { + char* out = java_lang_String::as_utf8_string(str); + if (out) { + output()->print_cr("%s", out); + return; + } + } + output()->print_cr("Error obtaining management agent status"); +} + VMDynamicLibrariesDCmd::VMDynamicLibrariesDCmd(outputStream *output, bool heap_allocated) : DCmd(output, heap_allocated) { // do nothing diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/services/diagnosticCommand.hpp --- a/hotspot/src/share/vm/services/diagnosticCommand.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp Thu May 07 20:51:12 2015 -0700 @@ -131,6 +131,48 @@ virtual void execute(DCmdSource source, TRAPS); }; +class SetVMFlagDCmd : public DCmdWithParser { +protected: + DCmdArgument _flag; + DCmdArgument _value; + +public: + SetVMFlagDCmd(outputStream* output, bool heap); + static const char* name() { return "VM.set_flag"; } + static const char* description() { + return "Sets VM flag option using the provided value."; + } + static const char* impact() { + return "Low"; + } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "control", NULL}; + return p; + } + static int num_arguments(); + virtual void execute(DCmdSource source, TRAPS); +}; + +class JVMTIDataDumpDCmd : public DCmd { +public: + JVMTIDataDumpDCmd(outputStream* output, bool heap) : DCmd(output, heap) { } + static const char* name() { return "JVMTI.data_dump"; } + static const char* description() { + return "Signal the JVM to do a data-dump request for JVMTI."; + } + static const char* impact() { + return "High"; + } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } + static int num_arguments() { return 0; } + virtual void execute(DCmdSource source, TRAPS); +}; + class VMDynamicLibrariesDCmd : public DCmd { public: VMDynamicLibrariesDCmd(outputStream* output, bool heap); @@ -410,6 +452,29 @@ virtual void execute(DCmdSource source, TRAPS); }; +// Print the JMX system status +class JMXStatusDCmd : public DCmd { +public: + JMXStatusDCmd(outputStream *output, bool heap_allocated); + + static const char *name() { + return "ManagementAgent.status"; + } + + static const char *description() { + return "Print the management agent status."; + } + + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } + + virtual void execute(DCmdSource source, TRAPS); + +}; + class RotateGCLogDCmd : public DCmd { public: RotateGCLogDCmd(outputStream* output, bool heap) : DCmd(output, heap) {} diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/services/diagnosticFramework.cpp --- a/hotspot/src/share/vm/services/diagnosticFramework.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/services/diagnosticFramework.cpp Thu May 07 20:51:12 2015 -0700 @@ -455,12 +455,12 @@ } if (notif) { - Klass* k = Management::sun_management_ManagementFactoryHelper_klass(CHECK); - instanceKlassHandle mgmt_factory_helper_klass(THREAD, k); + Klass* k = Management::com_sun_management_internal_DiagnosticCommandImpl_klass(CHECK); + instanceKlassHandle dcmd_mbean_klass(THREAD, k); JavaValue result(T_OBJECT); JavaCalls::call_static(&result, - mgmt_factory_helper_klass, + dcmd_mbean_klass, vmSymbols::getDiagnosticCommandMBean_name(), vmSymbols::getDiagnosticCommandMBean_signature(), CHECK); @@ -468,12 +468,9 @@ instanceOop m = (instanceOop) result.get_jobject(); instanceHandle dcmd_mbean_h(THREAD, m); - Klass* k2 = Management::sun_management_DiagnosticCommandImpl_klass(CHECK); - instanceKlassHandle dcmd_mbean_klass(THREAD, k2); - - if (!dcmd_mbean_h->is_a(k2)) { + if (!dcmd_mbean_h->is_a(k)) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - "ManagementFactory.getDiagnosticCommandMBean didn't return a DiagnosticCommandMBean instance"); + "DiagnosticCommandImpl.getDiagnosticCommandMBean didn't return a DiagnosticCommandMBean instance"); } JavaValue result2(T_VOID); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/services/gcNotifier.cpp --- a/hotspot/src/share/vm/services/gcNotifier.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/services/gcNotifier.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -77,7 +77,7 @@ static Handle getGcInfoBuilder(GCMemoryManager *gcManager,TRAPS) { - Klass* k = Management::sun_management_GarbageCollectorImpl_klass(CHECK_NH); + Klass* k = Management::com_sun_management_internal_GarbageCollectorExtImpl_klass(CHECK_NH); instanceKlassHandle gcMBeanKlass (THREAD, k); instanceOop i = gcManager->get_memory_manager_instance(THREAD); @@ -214,8 +214,8 @@ Handle objName = java_lang_String::create_from_str(request->gcManager->name(), CHECK); Handle objAction = java_lang_String::create_from_str(request->gcAction, CHECK); Handle objCause = java_lang_String::create_from_str(request->gcCause, CHECK); + Klass* k = Management::com_sun_management_internal_GarbageCollectorExtImpl_klass(CHECK); - Klass* k = Management::sun_management_GarbageCollectorImpl_klass(CHECK); instanceKlassHandle gc_mbean_klass(THREAD, k); instanceOop gc_mbean = request->gcManager->get_memory_manager_instance(THREAD); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/services/management.cpp --- a/hotspot/src/share/vm/services/management.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/services/management.cpp Thu May 07 20:51:12 2015 -0700 @@ -64,18 +64,16 @@ PerfVariable* Management::_end_vm_creation_time = NULL; PerfVariable* Management::_vm_init_done_time = NULL; +Klass* Management::_diagnosticCommandImpl_klass = NULL; +Klass* Management::_garbageCollectorExtImpl_klass = NULL; +Klass* Management::_garbageCollectorMXBean_klass = NULL; +Klass* Management::_gcInfo_klass = NULL; +Klass* Management::_managementFactoryHelper_klass = NULL; +Klass* Management::_memoryManagerMXBean_klass = NULL; +Klass* Management::_memoryPoolMXBean_klass = NULL; +Klass* Management::_memoryUsage_klass = NULL; Klass* Management::_sensor_klass = NULL; Klass* Management::_threadInfo_klass = NULL; -Klass* Management::_memoryUsage_klass = NULL; -Klass* Management::_memoryPoolMXBean_klass = NULL; -Klass* Management::_memoryManagerMXBean_klass = NULL; -Klass* Management::_garbageCollectorMXBean_klass = NULL; -Klass* Management::_managementFactory_klass = NULL; -Klass* Management::_garbageCollectorImpl_klass = NULL; -Klass* Management::_gcInfo_klass = NULL; -Klass* Management::_diagnosticCommandImpl_klass = NULL; -Klass* Management::_managementFactoryHelper_klass = NULL; - jmmOptionalSupport Management::_optional_support = {0}; TimeStamp Management::_stamp; @@ -255,18 +253,18 @@ return _sensor_klass; } -Klass* Management::sun_management_ManagementFactory_klass(TRAPS) { - if (_managementFactory_klass == NULL) { - _managementFactory_klass = load_and_initialize_klass(vmSymbols::sun_management_ManagementFactory(), CHECK_NULL); +Klass* Management::sun_management_ManagementFactoryHelper_klass(TRAPS) { + if (_managementFactoryHelper_klass == NULL) { + _managementFactoryHelper_klass = load_and_initialize_klass(vmSymbols::sun_management_ManagementFactoryHelper(), CHECK_NULL); } - return _managementFactory_klass; + return _managementFactoryHelper_klass; } -Klass* Management::sun_management_GarbageCollectorImpl_klass(TRAPS) { - if (_garbageCollectorImpl_klass == NULL) { - _garbageCollectorImpl_klass = load_and_initialize_klass(vmSymbols::sun_management_GarbageCollectorImpl(), CHECK_NULL); +Klass* Management::com_sun_management_internal_GarbageCollectorExtImpl_klass(TRAPS) { + if (_garbageCollectorExtImpl_klass == NULL) { + _garbageCollectorExtImpl_klass = load_and_initialize_klass(vmSymbols::com_sun_management_internal_GarbageCollectorExtImpl(), CHECK_NULL); } - return _garbageCollectorImpl_klass; + return _garbageCollectorExtImpl_klass; } Klass* Management::com_sun_management_GcInfo_klass(TRAPS) { @@ -276,20 +274,13 @@ return _gcInfo_klass; } -Klass* Management::sun_management_DiagnosticCommandImpl_klass(TRAPS) { +Klass* Management::com_sun_management_internal_DiagnosticCommandImpl_klass(TRAPS) { if (_diagnosticCommandImpl_klass == NULL) { - _diagnosticCommandImpl_klass = load_and_initialize_klass(vmSymbols::sun_management_DiagnosticCommandImpl(), CHECK_NULL); + _diagnosticCommandImpl_klass = load_and_initialize_klass(vmSymbols::com_sun_management_internal_DiagnosticCommandImpl(), CHECK_NULL); } return _diagnosticCommandImpl_klass; } -Klass* Management::sun_management_ManagementFactoryHelper_klass(TRAPS) { - if (_managementFactoryHelper_klass == NULL) { - _managementFactoryHelper_klass = load_and_initialize_klass(vmSymbols::sun_management_ManagementFactoryHelper(), CHECK_NULL); - } - return _managementFactoryHelper_klass; -} - static void initialize_ThreadInfo_constructor_arguments(JavaCallArguments* args, ThreadSnapshot* snapshot, TRAPS) { Handle snapshot_thread(THREAD, snapshot->threadObj()); @@ -1109,6 +1100,8 @@ bool with_locked_monitors, bool with_locked_synchronizers, TRAPS) { + // no need to actually perform thread dump if no TIDs are specified + if (num_threads == 0) return; // First get an array of threadObj handles. // A JavaThread may terminate before we get the stack trace. diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/services/management.hpp --- a/hotspot/src/share/vm/services/management.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/services/management.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,18 +42,16 @@ static TimeStamp _stamp; // Timestamp since vm init done time // Management klasses + static Klass* _diagnosticCommandImpl_klass; + static Klass* _garbageCollectorExtImpl_klass; + static Klass* _garbageCollectorMXBean_klass; + static Klass* _gcInfo_klass; + static Klass* _managementFactoryHelper_klass; + static Klass* _memoryManagerMXBean_klass; + static Klass* _memoryPoolMXBean_klass; + static Klass* _memoryUsage_klass; static Klass* _sensor_klass; static Klass* _threadInfo_klass; - static Klass* _memoryUsage_klass; - static Klass* _memoryPoolMXBean_klass; - static Klass* _memoryManagerMXBean_klass; - static Klass* _garbageCollectorMXBean_klass; - static Klass* _managementFactory_klass; - static Klass* _garbageCollectorImpl_klass; - static Klass* _diagnosticCommandImpl_klass; - static Klass* _managementFactoryHelper_klass; - static Klass* _gcInfo_klass; - static Klass* load_and_initialize_klass(Symbol* sh, TRAPS); public: @@ -93,17 +91,15 @@ static Klass* java_lang_management_MemoryPoolMXBean_klass(TRAPS); static Klass* java_lang_management_MemoryManagerMXBean_klass(TRAPS); static Klass* java_lang_management_GarbageCollectorMXBean_klass(TRAPS); + static Klass* sun_management_ManagementFactoryHelper_klass(TRAPS) + NOT_MANAGEMENT_RETURN_(NULL); static Klass* sun_management_Sensor_klass(TRAPS) NOT_MANAGEMENT_RETURN_(NULL); - static Klass* sun_management_ManagementFactory_klass(TRAPS) - NOT_MANAGEMENT_RETURN_(NULL); - static Klass* sun_management_GarbageCollectorImpl_klass(TRAPS) + static Klass* com_sun_management_internal_GarbageCollectorExtImpl_klass(TRAPS) NOT_MANAGEMENT_RETURN_(NULL); static Klass* com_sun_management_GcInfo_klass(TRAPS) NOT_MANAGEMENT_RETURN_(NULL); - static Klass* sun_management_DiagnosticCommandImpl_klass(TRAPS) - NOT_MANAGEMENT_RETURN_(NULL); - static Klass* sun_management_ManagementFactoryHelper_klass(TRAPS) + static Klass* com_sun_management_internal_DiagnosticCommandImpl_klass(TRAPS) NOT_MANAGEMENT_RETURN_(NULL); static instanceOop create_thread_info_instance(ThreadSnapshot* snapshot, TRAPS); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/services/memTracker.cpp --- a/hotspot/src/share/vm/services/memTracker.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/services/memTracker.cpp Thu May 07 20:51:12 2015 -0700 @@ -47,9 +47,9 @@ NMT_TrackingLevel MemTracker::init_tracking_level() { NMT_TrackingLevel level = NMT_off; char buf[64]; - char nmt_option[64]; jio_snprintf(buf, sizeof(buf), "NMT_LEVEL_%d", os::current_process_id()); - if (os::getenv(buf, nmt_option, sizeof(nmt_option))) { + const char *nmt_option = ::getenv(buf); + if (nmt_option != NULL) { if (strcmp(nmt_option, "summary") == 0) { level = NMT_summary; } else if (strcmp(nmt_option, "detail") == 0) { @@ -311,4 +311,3 @@ out->print_cr(" "); walker.report_statistics(out); } - diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/services/memoryManager.cpp --- a/hotspot/src/share/vm/services/memoryManager.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/services/memoryManager.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -98,8 +98,7 @@ if (mgr_obj == NULL) { // It's ok for more than one thread to execute the code up to the locked region. // Extra manager instances will just be gc'ed. - Klass* k = Management::sun_management_ManagementFactory_klass(CHECK_0); - instanceKlassHandle ik(THREAD, k); + Klass* k = Management::sun_management_ManagementFactoryHelper_klass(CHECK_0); Handle mgr_name = java_lang_String::create_from_str(name(), CHECK_0); @@ -110,7 +109,14 @@ Symbol* method_name = NULL; Symbol* signature = NULL; if (is_gc_memory_manager()) { + Klass* extKlass = Management::com_sun_management_internal_GarbageCollectorExtImpl_klass(CHECK_0); + // com.sun.management.GarbageCollectorMXBean is in jdk.management module which may not be present. + if (extKlass != NULL) { + k = extKlass; + } + method_name = vmSymbols::createGarbageCollector_name(); + signature = vmSymbols::createGarbageCollector_signature(); args.push_oop(Handle()); // Argument 2 (for future extension) } else { @@ -118,6 +124,8 @@ signature = vmSymbols::createMemoryManager_signature(); } + instanceKlassHandle ik(THREAD, k); + JavaCalls::call_static(&result, ik, method_name, diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/services/memoryManager.hpp --- a/hotspot/src/share/vm/services/memoryManager.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/services/memoryManager.hpp Thu May 07 20:51:12 2015 -0700 @@ -53,20 +53,6 @@ volatile instanceOop _memory_mgr_obj; public: - enum Name { - Abstract, - CodeCache, - Metaspace, - Copy, - MarkSweepCompact, - ParNew, - ConcurrentMarkSweep, - PSScavenge, - PSMarkSweep, - G1YoungGen, - G1OldGen - }; - MemoryManager(); int num_memory_pools() const { return _num_pools; } @@ -80,7 +66,6 @@ bool is_manager(instanceHandle mh) { return mh() == _memory_mgr_obj; } virtual instanceOop get_memory_manager_instance(TRAPS); - virtual MemoryManager::Name kind() { return MemoryManager::Abstract; } virtual bool is_gc_memory_manager() { return false; } virtual const char* name() = 0; @@ -98,7 +83,6 @@ static GCMemoryManager* get_psMarkSweep_memory_manager(); static GCMemoryManager* get_g1YoungGen_memory_manager(); static GCMemoryManager* get_g1OldGen_memory_manager(); - }; class CodeCacheMemoryManager : public MemoryManager { @@ -106,16 +90,14 @@ public: CodeCacheMemoryManager() : MemoryManager() {} - MemoryManager::Name kind() { return MemoryManager::CodeCache; } - const char* name() { return "CodeCacheManager"; } + const char* name() { return "CodeCacheManager"; } }; class MetaspaceMemoryManager : public MemoryManager { public: MetaspaceMemoryManager() : MemoryManager() {} - MemoryManager::Name kind() { return MemoryManager::Metaspace; } - const char *name() { return "Metaspace Manager"; } + const char* name() { return "Metaspace Manager"; } }; class GCStatInfo : public ResourceObj { @@ -202,7 +184,6 @@ void set_notification_enabled(bool enabled) { _notification_enabled = enabled; } bool is_notification_enabled() { return _notification_enabled; } - virtual MemoryManager::Name kind() = 0; }; // These subclasses of GCMemoryManager are defined to include @@ -213,8 +194,7 @@ public: CopyMemoryManager() : GCMemoryManager() {} - MemoryManager::Name kind() { return MemoryManager::Copy; } - const char* name() { return "Copy"; } + const char* name() { return "Copy"; } }; class MSCMemoryManager : public GCMemoryManager { @@ -222,9 +202,7 @@ public: MSCMemoryManager() : GCMemoryManager() {} - MemoryManager::Name kind() { return MemoryManager::MarkSweepCompact; } - const char* name() { return "MarkSweepCompact"; } - + const char* name() { return "MarkSweepCompact"; } }; class ParNewMemoryManager : public GCMemoryManager { @@ -232,9 +210,7 @@ public: ParNewMemoryManager() : GCMemoryManager() {} - MemoryManager::Name kind() { return MemoryManager::ParNew; } - const char* name() { return "ParNew"; } - + const char* name() { return "ParNew"; } }; class CMSMemoryManager : public GCMemoryManager { @@ -242,9 +218,7 @@ public: CMSMemoryManager() : GCMemoryManager() {} - MemoryManager::Name kind() { return MemoryManager::ConcurrentMarkSweep; } - const char* name() { return "ConcurrentMarkSweep";} - + const char* name() { return "ConcurrentMarkSweep";} }; class PSScavengeMemoryManager : public GCMemoryManager { @@ -252,9 +226,7 @@ public: PSScavengeMemoryManager() : GCMemoryManager() {} - MemoryManager::Name kind() { return MemoryManager::PSScavenge; } - const char* name() { return "PS Scavenge"; } - + const char* name() { return "PS Scavenge"; } }; class PSMarkSweepMemoryManager : public GCMemoryManager { @@ -262,8 +234,7 @@ public: PSMarkSweepMemoryManager() : GCMemoryManager() {} - MemoryManager::Name kind() { return MemoryManager::PSMarkSweep; } - const char* name() { return "PS MarkSweep"; } + const char* name() { return "PS MarkSweep"; } }; class G1YoungGenMemoryManager : public GCMemoryManager { @@ -271,8 +242,7 @@ public: G1YoungGenMemoryManager() : GCMemoryManager() {} - MemoryManager::Name kind() { return MemoryManager::G1YoungGen; } - const char* name() { return "G1 Young Generation"; } + const char* name() { return "G1 Young Generation"; } }; class G1OldGenMemoryManager : public GCMemoryManager { @@ -280,8 +250,7 @@ public: G1OldGenMemoryManager() : GCMemoryManager() {} - MemoryManager::Name kind() { return MemoryManager::G1OldGen; } - const char* name() { return "G1 Old Generation"; } + const char* name() { return "G1 Old Generation"; } }; #endif // SHARE_VM_SERVICES_MEMORYMANAGER_HPP diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/services/memoryPool.cpp --- a/hotspot/src/share/vm/services/memoryPool.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/services/memoryPool.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,7 +86,7 @@ if (pool_obj == NULL) { // It's ok for more than one thread to execute the code up to the locked region. // Extra pool instances will just be gc'ed. - Klass* k = Management::sun_management_ManagementFactory_klass(CHECK_NULL); + Klass* k = Management::sun_management_ManagementFactoryHelper_klass(CHECK_NULL); instanceKlassHandle ik(THREAD, k); Handle pool_name = java_lang_String::create_from_str(_name, CHECK_NULL); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/services/memoryService.cpp --- a/hotspot/src/share/vm/services/memoryService.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/services/memoryService.cpp Thu May 07 20:51:12 2015 -0700 @@ -126,9 +126,8 @@ CollectorPolicy* policy = heap->collector_policy(); assert(policy->is_generation_policy(), "Only support two generations"); - guarantee(heap->n_gens() == 2, "Only support two-generation heap"); - GenCollectorPolicy* gen_policy = policy->as_generation_policy(); + guarantee(gen_policy->number_of_generations() == 2, "Only support two-generation heap"); if (gen_policy != NULL) { Generation::Name kind = gen_policy->young_gen_spec()->name(); switch (kind) { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/utilities/globalDefinitions.hpp --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp Thu May 07 20:51:12 2015 -0700 @@ -407,14 +407,6 @@ // Machine dependent stuff -#if defined(X86) && defined(COMPILER2) && !defined(JAVASE_EMBEDDED) -// Include Restricted Transactional Memory lock eliding optimization -#define INCLUDE_RTM_OPT 1 -#define RTM_OPT_ONLY(code) code -#else -#define INCLUDE_RTM_OPT 0 -#define RTM_OPT_ONLY(code) -#endif // States of Restricted Transactional Memory usage. enum RTMState { NoRTM = 0x2, // Don't use RTM @@ -446,6 +438,15 @@ # include "globalDefinitions_aarch64.hpp" #endif +#ifndef INCLUDE_RTM_OPT +#define INCLUDE_RTM_OPT 0 +#endif +#if INCLUDE_RTM_OPT +#define RTM_OPT_ONLY(code) code +#else +#define RTM_OPT_ONLY(code) +#endif + // To assure the IRIW property on processors that are not multiple copy // atomic, sync instructions must be issued between volatile reads to // assure their ordering, instead of after volatile stores. @@ -1345,6 +1346,13 @@ return (intptr_t) p; } +// swap a & b +template static void swap(T& a, T& b) { + T tmp = a; + a = b; + b = tmp; +} + // Printf-style formatters for fixed- and variable-width types as pointers and // integers. These are derived from the definitions in inttypes.h. If the platform // doesn't provide appropriate definitions, they should be provided in diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/utilities/growableArray.hpp --- a/hotspot/src/share/vm/utilities/growableArray.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/utilities/growableArray.hpp Thu May 07 20:51:12 2015 -0700 @@ -168,6 +168,8 @@ GrowableArray(int initial_size, bool C_heap = false, MEMFLAGS F = mtInternal) : GenericGrowableArray(initial_size, 0, C_heap, F) { _data = (E*)raw_allocate(sizeof(E)); +// Needed for Visual Studio 2012 and older +#pragma warning(suppress: 4345) for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E(); } @@ -385,6 +387,8 @@ E* newData = (E*)raw_allocate(sizeof(E)); int i = 0; for ( ; i < _len; i++) ::new ((void*)&newData[i]) E(_data[i]); +// Needed for Visual Studio 2012 and older +#pragma warning(suppress: 4345) for ( ; i < _max; i++) ::new ((void*)&newData[i]) E(); for (i = 0; i < old_max; i++) _data[i].~E(); if (on_C_heap() && _data != NULL) { diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/utilities/ostream.cpp --- a/hotspot/src/share/vm/utilities/ostream.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/utilities/ostream.cpp Thu May 07 20:51:12 2015 -0700 @@ -109,7 +109,7 @@ } if (add_cr) { if (result != buffer) { - strncpy(buffer, result, buflen); + memcpy(buffer, result, result_len); result = buffer; } buffer[result_len++] = '\n'; @@ -334,15 +334,19 @@ assert(rm == NULL || Thread::current()->current_resource_mark() == rm, "stringStream is re-allocated with a different ResourceMark"); buffer = NEW_RESOURCE_ARRAY(char, end); - strncpy(buffer, oldbuf, buffer_pos); + if (buffer_pos > 0) { + memcpy(buffer, oldbuf, buffer_pos); + } buffer_length = end; } } // invariant: buffer is always null-terminated guarantee(buffer_pos + write_len + 1 <= buffer_length, "stringStream oob"); - buffer[buffer_pos + write_len] = 0; - strncpy(buffer + buffer_pos, s, write_len); - buffer_pos += write_len; + if (write_len > 0) { + buffer[buffer_pos + write_len] = 0; + memcpy(buffer + buffer_pos, s, write_len); + buffer_pos += write_len; + } // Note that the following does not depend on write_len. // This means that position and count get updated @@ -978,8 +982,13 @@ xs->head("properties"); // Print it as a java-style property list. // System properties don't generally contain newlines, so don't bother with unparsing. + outputStream *text = xs->text(); for (SystemProperty* p = Arguments::system_properties(); p != NULL; p = p->next()) { - xs->text()->print_cr("%s=%s", p->key(), p->value()); + // Print in two stages to avoid problems with long + // keys/values. + text->print_raw(p->key()); + text->put('='); + text->print_raw_cr(p->value()); } xs->tail("properties"); } diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/utilities/stack.hpp --- a/hotspot/src/share/vm/utilities/stack.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/utilities/stack.hpp Thu May 07 20:51:12 2015 -0700 @@ -96,11 +96,16 @@ public: friend class StackIterator; + // Number of elements that fit in 4K bytes minus the size of two pointers + // (link field and malloc header). + static const size_t _default_segment_size = (4096 - 2 * sizeof(E*)) / sizeof(E); + static size_t default_segment_size() { return _default_segment_size; } + // segment_size: number of items per segment // max_cache_size: maxmium number of *segments* to cache // max_size: maximum number of items allowed, rounded to a multiple of // the segment size (0 == unlimited) - inline Stack(size_t segment_size = default_segment_size(), + inline Stack(size_t segment_size = _default_segment_size, size_t max_cache_size = 4, size_t max_size = 0); inline ~Stack() { clear(true); } @@ -122,8 +127,6 @@ // clear_cache is true, also release any cached segments. void clear(bool clear_cache = false); - static inline size_t default_segment_size(); - protected: // Each segment includes space for _seg_size elements followed by a link // (pointer) to the previous segment; the space is allocated as a single block diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/utilities/stack.inline.hpp --- a/hotspot/src/share/vm/utilities/stack.inline.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/utilities/stack.inline.hpp Thu May 07 20:51:12 2015 -0700 @@ -86,14 +86,6 @@ } template -size_t Stack::default_segment_size() -{ - // Number of elements that fit in 4K bytes minus the size of two pointers - // (link field and malloc header). - return (4096 - 2 * sizeof(E*)) / sizeof(E); -} - -template size_t Stack::adjust_segment_size(size_t seg_size) { const size_t elem_sz = sizeof(E); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/utilities/vmError.cpp --- a/hotspot/src/share/vm/utilities/vmError.cpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/utilities/vmError.cpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -217,7 +217,7 @@ bool VMError::coredump_status; char VMError::coredump_message[O_BUFLEN]; -void VMError::report_coredump_status(const char* message, bool status) { +void VMError::record_coredump_status(const char* message, bool status) { coredump_status = status; strncpy(coredump_message, message, sizeof(coredump_message)); coredump_message[sizeof(coredump_message)-1] = 0; @@ -231,7 +231,7 @@ if (signame) { jio_snprintf(buf, buflen, - "%s (0x%x) at pc=" PTR_FORMAT ", pid=%d, tid=" UINTX_FORMAT, + "%s (0x%x) at pc=" PTR_FORMAT ", pid=%d, tid=" INTPTR_FORMAT, signame, _id, _pc, os::current_process_id(), os::current_thread_id()); } else if (_filename != NULL && _lineno > 0) { @@ -239,7 +239,7 @@ char separator = os::file_separator()[0]; const char *p = strrchr(_filename, separator); int n = jio_snprintf(buf, buflen, - "Internal Error at %s:%d, pid=%d, tid=" UINTX_FORMAT, + "Internal Error at %s:%d, pid=%d, tid=" INTPTR_FORMAT, p ? p + 1 : _filename, _lineno, os::current_process_id(), os::current_thread_id()); if (n >= 0 && n < buflen && _message) { @@ -253,7 +253,7 @@ } } else { jio_snprintf(buf, buflen, - "Internal Error (0x%x), pid=%d, tid=" UINTX_FORMAT, + "Internal Error (0x%x), pid=%d, tid=" INTPTR_FORMAT, _id, os::current_process_id(), os::current_thread_id()); } @@ -463,14 +463,7 @@ #else const char *file = _filename; #endif - size_t len = strlen(file); - size_t buflen = sizeof(buf); - - strncpy(buf, file, buflen); - if (len + 10 < buflen) { - sprintf(buf + len, ":%d", _lineno); - } - st->print(" (%s)", buf); + st->print(" (%s:%d)", file, _lineno); } else { st->print(" (0x%x)", _id); } @@ -480,7 +473,7 @@ // process id, thread id st->print(", pid=%d", os::current_process_id()); - st->print(", tid=" UINTX_FORMAT, os::current_thread_id()); + st->print(", tid=" INTPTR_FORMAT, os::current_thread_id()); st->cr(); STEP(40, "(printing error message)") @@ -525,10 +518,14 @@ } STEP(63, "(printing core file information)") st->print("# "); - if (coredump_status) { - st->print("Core dump written. Default location: %s", coredump_message); + if (CreateCoredumpOnCrash) { + if (coredump_status) { + st->print("Core dump will be written. %s", coredump_message); + } else { + st->print("No core dump will be written. %s", coredump_message); + } } else { - st->print("Failed to write core dump. %s", coredump_message); + st->print("CreateCoredumpOnCrash turned off, no core file dumped"); } st->cr(); st->print_cr("#"); @@ -768,7 +765,7 @@ STEP(220, "(printing environment variables)" ) if (_verbose) { - os::print_environment_variables(st, env_list, buf, sizeof(buf)); + os::print_environment_variables(st, env_list); st->cr(); } @@ -918,7 +915,7 @@ static bool transmit_report_done = false; // done error reporting if (SuppressFatalErrorMessage) { - os::abort(); + os::abort(CreateCoredumpOnCrash); } jlong mytid = os::current_thread_id(); if (first_error == NULL && @@ -936,8 +933,7 @@ ShowMessageBoxOnError = false; } - // Write a minidump on Windows, check core dump limits on Linux/Solaris - os::check_or_create_dump(_siginfo, _context, buffer, sizeof(buffer)); + os::check_dump_limit(buffer, sizeof(buffer)); // reset signal handlers or exception filter; make sure recursive crashes // are handled properly. @@ -1108,7 +1104,7 @@ if (!skip_os_abort) { skip_os_abort = true; bool dump_core = should_report_bug(first_error->_id); - os::abort(dump_core); + os::abort(dump_core && CreateCoredumpOnCrash, _siginfo, _context); } // if os::abort() doesn't abort, try os::die(); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/utilities/vmError.hpp --- a/hotspot/src/share/vm/utilities/vmError.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/utilities/vmError.hpp Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -117,8 +117,8 @@ // return a string to describe the error char *error_string(char* buf, int buflen); - // Report status of core/minidump - static void report_coredump_status(const char* message, bool status); + // Record status of core/minidump + static void record_coredump_status(const char* message, bool status); // main error reporting function void report_and_die(); diff -r a4b1c7d6317a -r febd2373771c hotspot/src/share/vm/utilities/workgroup.hpp --- a/hotspot/src/share/vm/utilities/workgroup.hpp Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/src/share/vm/utilities/workgroup.hpp Thu May 07 20:51:12 2015 -0700 @@ -340,18 +340,6 @@ } }; -// Work gangs in garbage collectors: 2009-06-10 -// -// SharedHeap - work gang for stop-the-world parallel collection. -// Used by -// ParNewGeneration -// CMSParRemarkTask -// CMSRefProcTaskExecutor -// G1CollectedHeap -// G1ParFinalCountTask -// ConcurrentMark -// CMSCollector - // A class that acts as a synchronisation barrier. Workers enter // the barrier and must wait until all other workers have entered // before any of them may leave. diff -r a4b1c7d6317a -r febd2373771c hotspot/test/Makefile --- a/hotspot/test/Makefile Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/Makefile Thu May 07 20:51:12 2015 -0700 @@ -279,6 +279,8 @@ # Default JTREG to run JTREG = $(JT_HOME)/bin/jtreg +# Use agent mode +JTREG_BASIC_OPTIONS += -agentvm # Only run automatic tests JTREG_BASIC_OPTIONS += -a # Report details on all failed or error tests, times too @@ -344,6 +346,34 @@ ################################################################ +# basicvmtest (make sure various basic java options work) + +# Set up the directory in which the jvm directories live (client/, server/, etc.) +ifeq ($(PLATFORM),windows) +JVMS_DIR := $(PRODUCT_HOME)/bin +else ifeq ($(PLATFORM),bsd) +JVMS_DIR := $(PRODUCT_HOME)/lib +else +# The jvms live in the architecture directory (amd64, sparcv9, +# etc.). By using a wildcard there's no need to figure out the exact +# name of that directory. +JVMS_DIR := $(PRODUCT_HOME)/lib/* +endif + +# Use the existance of a directory as a sign that jvm variant is available +CANDIDATE_JVM_VARIANTS := client minimal server +JVM_VARIANTS := $(strip $(foreach x,$(CANDIDATE_JVM_VARIANTS),$(if $(wildcard $(JVMS_DIR)/$(x)),$(x)))) + +hotspot_basicvmtest: + for variant in $(JVM_VARIANTS); \ + do \ + $(MAKE) JAVA_ARGS="$(JAVA_ARGS) -$$variant" hotspot_$${variant}test; \ + done + +PHONY_LIST += hotspot_basicvmtest + +################################################################ + # clienttest (make sure various basic java client options work) hotspot_clienttest clienttest: sanitytest diff -r a4b1c7d6317a -r febd2373771c hotspot/test/TEST.groups --- a/hotspot/test/TEST.groups Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/TEST.groups Thu May 07 20:51:12 2015 -0700 @@ -394,6 +394,7 @@ hotspot_gc = \ sanity/ExecuteInternalVMTests.java \ gc/ \ + -gc/g1/TestGreyReclaimedHumongousObjects.java \ -gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java hotspot_gc_closed = \ @@ -416,9 +417,7 @@ -runtime/SharedArchiveFile/CdsSameObjectAlignment.java \ -runtime/SharedArchiveFile/DefaultUseWithClient.java \ -runtime/Thread/CancellableThreadTest.java \ - -runtime/7158988/FieldMonitor.java - -hotspot_runtime_closed = \ + -runtime/7158988/FieldMonitor.java \ sanity/ExecuteInternalVMTests.java \ testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/arraycopy/TestArrayCopyBadReexec.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/arraycopy/TestArrayCopyBadReexec.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8073866 + * @summary Fix for 8064703 may also cause stores between the allocation and arraycopy to be rexecuted after a deoptimization + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestArrayCopyBadReexec + * + */ + +public class TestArrayCopyBadReexec { + + static int val; + + static int[] m1(int[] src, int l) { + if (src == null) { + return null; + } + int[] dest = new int[10]; + val++; + try { + System.arraycopy(src, 0, dest, 0, l); + } catch (IndexOutOfBoundsException npe) { + } + return dest; + } + + static public void main(String[] args) { + int[] src = new int[10]; + int[] res = null; + boolean success = true; + + for (int i = 0; i < 20000; i++) { + m1(src, 10); + } + + int val_before = val; + + m1(src, -1); + + if (val - val_before != 1) { + System.out.println("Bad increment: " + (val - val_before)); + throw new RuntimeException("Test failed"); + } + } +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/arraycopy/TestArrayCopyNoInit.java --- a/hotspot/test/compiler/arraycopy/TestArrayCopyNoInit.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/compiler/arraycopy/TestArrayCopyNoInit.java Thu May 07 20:51:12 2015 -0700 @@ -76,7 +76,7 @@ static TestArrayCopyNoInit[] m5(Object[] src) { Object tmp = src[0]; TestArrayCopyNoInit[] dest = new TestArrayCopyNoInit[10]; - System.arraycopy(src, 0, dest, 0, 0); + System.arraycopy(src, 0, dest, 0, 10); return dest; } @@ -110,7 +110,7 @@ static H[] m6(Object[] src) { Object tmp = src[0]; H[] dest = new H[10]; - System.arraycopy(src, 0, dest, 0, 0); + System.arraycopy(src, 0, dest, 0, 10); return dest; } diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/arraycopy/TestArrayCopyNoInitDeopt.java --- a/hotspot/test/compiler/arraycopy/TestArrayCopyNoInitDeopt.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/compiler/arraycopy/TestArrayCopyNoInitDeopt.java Thu May 07 20:51:12 2015 -0700 @@ -116,44 +116,46 @@ throw new RuntimeException("m1 deoptimized again"); } - // Same test as above but with speculative types + if (WHITE_BOX.getUintxVMFlag("TypeProfileLevel") == 20) { + // Same test as above but with speculative types - // Warm up & make sure we collect type profiling - for (int i = 0; i < 20000; i++) { - m2(src); - } + // Warm up & make sure we collect type profiling + for (int i = 0; i < 20000; i++) { + m2(src); + } - // And make sure m2 is compiled by C2 - WHITE_BOX.enqueueMethodForCompilation(method_m2, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION); + // And make sure m2 is compiled by C2 + WHITE_BOX.enqueueMethodForCompilation(method_m2, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION); - if (!WHITE_BOX.isMethodCompiled(method_m2)) { - throw new RuntimeException("m2 not compiled"); - } + if (!WHITE_BOX.isMethodCompiled(method_m2)) { + throw new RuntimeException("m2 not compiled"); + } - // should deoptimize for speculative type check - if (!deoptimize(method_m2, src_obj)) { - throw new RuntimeException("m2 not deoptimized"); - } + // should deoptimize for speculative type check + if (!deoptimize(method_m2, src_obj)) { + throw new RuntimeException("m2 not deoptimized"); + } - WHITE_BOX.enqueueMethodForCompilation(method_m2, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION); + WHITE_BOX.enqueueMethodForCompilation(method_m2, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION); - if (!WHITE_BOX.isMethodCompiled(method_m2)) { - throw new RuntimeException("m2 not recompiled"); - } + if (!WHITE_BOX.isMethodCompiled(method_m2)) { + throw new RuntimeException("m2 not recompiled"); + } - // should deoptimize for actual type check - if (!deoptimize(method_m2, src_obj)) { - throw new RuntimeException("m2 not deoptimized"); - } + // should deoptimize for actual type check + if (!deoptimize(method_m2, src_obj)) { + throw new RuntimeException("m2 not deoptimized"); + } - WHITE_BOX.enqueueMethodForCompilation(method_m2, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION); + WHITE_BOX.enqueueMethodForCompilation(method_m2, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION); - if (!WHITE_BOX.isMethodCompiled(method_m2)) { - throw new RuntimeException("m2 not recompiled"); - } + if (!WHITE_BOX.isMethodCompiled(method_m2)) { + throw new RuntimeException("m2 not recompiled"); + } - if (deoptimize(method_m2, src_obj)) { - throw new RuntimeException("m2 deoptimized again"); + if (deoptimize(method_m2, src_obj)) { + throw new RuntimeException("m2 deoptimized again"); + } } } } diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/arraycopy/TestArrayCopyOfStopped.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/arraycopy/TestArrayCopyOfStopped.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8074676 + * @summary after guards in Arrays.copyOf() intrinsic, control may become top + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestArrayCopyOfStopped + * + */ + +import java.util.Arrays; + +public class TestArrayCopyOfStopped { + static class A { + } + + static class B { + } + + static final B[] array_of_bs = new B[10]; + static final A[] array_of_as = new A[10]; + + static Object[] m1_helper(Object[] array, boolean flag) { + if (flag) { + return Arrays.copyOf(array, 10, A[].class); + } + return null; + } + + static Object[] m1(boolean flag) { + return m1_helper(array_of_bs, flag); + } + + public static void main(String[] args) { + for (int i = 0; i < 20000; i++) { + m1_helper(array_of_as, (i%2) == 0); + } + + for (int i = 0; i < 20000; i++) { + m1(false); + } + } +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/arraycopy/TestArrayCopyStoppedAfterGuards.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/arraycopy/TestArrayCopyStoppedAfterGuards.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8075921 + * @summary control becomes top after arraycopy guards and confuses tighly coupled allocation logic + * @run main/othervm -Xcomp -XX:CompileOnly=TestArrayCopyStoppedAfterGuards.test,System.arraycopy TestArrayCopyStoppedAfterGuards + * + */ + +public class TestArrayCopyStoppedAfterGuards { + + static void test() { + Object src = new Object(); + int[] dst = new int[10]; + System.arraycopy(src, 0, dst, 0, 10); + } + + static public void main(String[] args) { + // warmup + Object o = new Object(); + int[] src = new int[10]; + int[] dst = new int[10]; + System.arraycopy(src, 0, dst, 0, 10); + + try { + test(); + } catch(ArrayStoreException ase) {} + } +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java --- a/hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java Thu May 07 20:51:12 2015 -0700 @@ -37,7 +37,6 @@ /* * @test PoolsIndependenceTest - * @ignore 8068385 * @library /testlibrary /../../test/lib * @build PoolsIndependenceTest * @run main ClassFileInstaller sun.hotspot.WhiteBox diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/inlining/DefaultMethodsDependencies.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/inlining/DefaultMethodsDependencies.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8069263 + * @summary Deoptimization between array allocation and arraycopy may result in non initialized array + * @run main/othervm -XX:-BackgroundCompilation -XX:CompileOnly=DefaultMethodsDependencies::test -XX:CompileOnly=DefaultMethodsDependencies$I2::m1 DefaultMethodsDependencies + * + */ + +public class DefaultMethodsDependencies { + + interface I1 { + void m1(); + // triggers processing of default methods in C1 + default void m2() { + } + } + + interface I2 extends I1 { + // added to C2 as default method + default void m1() { + } + } + + static abstract class C1 implements I1 { + } + + static class C2 extends C1 implements I2 { + } + + static void test(C1 obj) { + obj.m1(); + } + + static public void main(String[] args) { + C2 obj = new C2(); + for (int i = 0; i < 20000; i++) { + test(obj); + } + } +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/intrinsics/multiplytolen/TestMultiplyToLen.java --- a/hotspot/test/compiler/intrinsics/multiplytolen/TestMultiplyToLen.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/compiler/intrinsics/multiplytolen/TestMultiplyToLen.java Thu May 07 20:51:12 2015 -0700 @@ -34,6 +34,7 @@ * -XX:CompileCommand=inline,java.math.BigInteger::multiply TestMultiplyToLen */ +import java.util.Arrays; import java.util.Random; import java.math.*; @@ -97,12 +98,36 @@ newsum = newsum.add(newres); if (!bytecompare(oldres,newres)) { + System.out.println(b1); + System.out.println(b2); + System.out.print("mismatch for:b1:" + stringify(b1) + " :b2:" + stringify(b2) + " :oldres:" + stringify(oldres) + " :newres:" + stringify(newres)); + throw new Exception("Failed"); + } + } + + // Test carry propagation. Multiple carries during bignum + // multiplication are rare (especially when using 64-bit + // arithmetic) so we have to provoke them deliberately. + for (int j = 4; j <= 396; j += 4) { + byte[] bytes = new byte[j]; + Arrays.fill(bytes, (byte)255); + b1 = new BigInteger(bytes); + b2 = new BigInteger(bytes); + + oldres = base_multiply(b1,b2); + newres = new_multiply(b1,b2); + + oldsum = oldsum.add(oldres); + newsum = newsum.add(newres); + + if (!bytecompare(oldres,newres)) { System.out.print("mismatch for:b1:" + stringify(b1) + " :b2:" + stringify(b2) + " :oldres:" + stringify(oldres) + " :newres:" + stringify(newres)); System.out.println(b1); System.out.println(b2); throw new Exception("Failed"); } } + if (!bytecompare(oldsum,newsum)) { System.out.println("Failure: oldsum:" + stringify(oldsum) + " newsum:" + stringify(newsum)); throw new Exception("Failed"); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/intrinsics/unsafe/HeapByteBufferTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/intrinsics/unsafe/HeapByteBufferTest.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,371 @@ +// +// Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2015, Red Hat Inc. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// +// + +import com.oracle.java.testlibrary.Utils; +import static java.lang.Math.abs; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import static java.nio.ByteOrder.BIG_ENDIAN; +import static java.nio.ByteOrder.LITTLE_ENDIAN; +import java.util.Random; +import java.util.Arrays; + +/** + * @test + * @bug 8026049 + * @library /testlibrary + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-UseUnalignedAccesses HeapByteBufferTest + * @run main/othervm HeapByteBufferTest + * @summary Verify that byte buffers are correctly accessed. + */ + +// A wrapper for a ByteBuffer which maintains a backing array and a +// position. Whenever this wrapper is written the backing array and +// the wrapped byte buffer are updated together, and whenever it is +// read we check that the ByteBuffer and the backing array are identical. + +class MyByteBuffer { + final ByteBuffer buf; + final byte[] bytes; + int pos; + ByteOrder byteOrder = BIG_ENDIAN; + + MyByteBuffer(ByteBuffer buf, byte[] bytes) { + this.buf = buf; + this.bytes = Arrays.copyOf(bytes, bytes.length); + pos = 0; + } + + public final MyByteBuffer order(ByteOrder bo) { + byteOrder = bo; + buf.order(bo); + return this; + } + + static MyByteBuffer wrap(byte[] bytes) { + return new MyByteBuffer(ByteBuffer.wrap(bytes), bytes); + } + + int capacity() { return bytes.length; } + int position() { + if (buf.position() != pos) + throw new RuntimeException(); + return buf.position(); + } + + byte[] array() { return buf.array(); } + byte[] backingArray() { return bytes; } + + private static byte long7(long x) { return (byte)(x >> 56); } + private static byte long6(long x) { return (byte)(x >> 48); } + private static byte long5(long x) { return (byte)(x >> 40); } + private static byte long4(long x) { return (byte)(x >> 32); } + private static byte long3(long x) { return (byte)(x >> 24); } + private static byte long2(long x) { return (byte)(x >> 16); } + private static byte long1(long x) { return (byte)(x >> 8); } + private static byte long0(long x) { return (byte)(x ); } + + private static byte int3(int x) { return (byte)(x >> 24); } + private static byte int2(int x) { return (byte)(x >> 16); } + private static byte int1(int x) { return (byte)(x >> 8); } + private static byte int0(int x) { return (byte)(x ); } + + private static byte short1(short x) { return (byte)(x >> 8); } + private static byte short0(short x) { return (byte)(x ); } + + byte _get(long i) { return bytes[(int)i]; } + void _put(long i, byte x) { bytes[(int)i] = x; } + + private void putLongX(long a, long x) { + if (byteOrder == BIG_ENDIAN) { + x = Long.reverseBytes(x); + } + _put(a + 7, long7(x)); + _put(a + 6, long6(x)); + _put(a + 5, long5(x)); + _put(a + 4, long4(x)); + _put(a + 3, long3(x)); + _put(a + 2, long2(x)); + _put(a + 1, long1(x)); + _put(a , long0(x)); + } + + private void putIntX(long a, int x) { + if (byteOrder == BIG_ENDIAN) { + x = Integer.reverseBytes(x); + } + _put(a + 3, int3(x)); + _put(a + 2, int2(x)); + _put(a + 1, int1(x)); + _put(a , int0(x)); + } + + private void putShortX(int bi, short x) { + if (byteOrder == BIG_ENDIAN) { + x = Short.reverseBytes(x); + } + _put(bi , short0(x)); + _put(bi + 1, short1(x)); + } + + static private int makeInt(byte b3, byte b2, byte b1, byte b0) { + return (((b3 ) << 24) | + ((b2 & 0xff) << 16) | + ((b1 & 0xff) << 8) | + ((b0 & 0xff) )); + } + int getIntX(long a) { + int x = makeInt(_get(a + 3), + _get(a + 2), + _get(a + 1), + _get(a)); + if (byteOrder == BIG_ENDIAN) { + x = Integer.reverseBytes(x); + } + return x; + } + + static private long makeLong(byte b7, byte b6, byte b5, byte b4, + byte b3, byte b2, byte b1, byte b0) + { + return ((((long)b7 ) << 56) | + (((long)b6 & 0xff) << 48) | + (((long)b5 & 0xff) << 40) | + (((long)b4 & 0xff) << 32) | + (((long)b3 & 0xff) << 24) | + (((long)b2 & 0xff) << 16) | + (((long)b1 & 0xff) << 8) | + (((long)b0 & 0xff) )); + } + + long getLongX(long a) { + long x = makeLong(_get(a + 7), + _get(a + 6), + _get(a + 5), + _get(a + 4), + _get(a + 3), + _get(a + 2), + _get(a + 1), + _get(a)); + if (byteOrder == BIG_ENDIAN) { + x = Long.reverseBytes(x); + } + return x; + } + + static private short makeShort(byte b1, byte b0) { + return (short)((b1 << 8) | (b0 & 0xff)); + } + + short getShortX(long a) { + short x = makeShort(_get(a + 1), + _get(a )); + if (byteOrder == BIG_ENDIAN) { + x = Short.reverseBytes(x); + } + return x; + } + + double getDoubleX(long a) { + long x = getLongX(a); + return Double.longBitsToDouble(x); + } + + double getFloatX(long a) { + int x = getIntX(a); + return Float.intBitsToFloat(x); + } + + void ck(long x, long y) { + if (x != y) { + throw new RuntimeException(" x = " + Long.toHexString(x) + ", y = " + Long.toHexString(y)); + } + } + + void ck(double x, double y) { + if (x == x && y == y && x != y) { + ck(x, y); + } + } + + long getLong(int i) { ck(buf.getLong(i), getLongX(i)); return buf.getLong(i); } + int getInt(int i) { ck(buf.getInt(i), getIntX(i)); return buf.getInt(i); } + short getShort(int i) { ck(buf.getShort(i), getShortX(i)); return buf.getShort(i); } + char getChar(int i) { ck(buf.getChar(i), (char)getShortX(i)); return buf.getChar(i); } + double getDouble(int i) { ck(buf.getDouble(i), getDoubleX(i)); return buf.getDouble(i); } + float getFloat(int i) { ck(buf.getFloat(i), getFloatX(i)); return buf.getFloat(i); } + + void putLong(int i, long x) { buf.putLong(i, x); putLongX(i, x); } + void putInt(int i, int x) { buf.putInt(i, x); putIntX(i, x); } + void putShort(int i, short x) { buf.putShort(i, x); putShortX(i, x); } + void putChar(int i, char x) { buf.putChar(i, x); putShortX(i, (short)x); } + void putDouble(int i, double x) { buf.putDouble(i, x); putLongX(i, Double.doubleToRawLongBits(x)); } + void putFloat(int i, float x) { buf.putFloat(i, x); putIntX(i, Float.floatToRawIntBits(x)); } + + long getLong() { ck(buf.getLong(buf.position()), getLongX(pos)); long x = buf.getLong(); pos += 8; return x; } + int getInt() { ck(buf.getInt(buf.position()), getIntX(pos)); int x = buf.getInt(); pos += 4; return x; } + short getShort() { ck(buf.getShort(buf.position()), getShortX(pos)); short x = buf.getShort(); pos += 2; return x; } + char getChar() { ck(buf.getChar(buf.position()), (char)getShortX(pos)); char x = buf.getChar(); pos += 2; return x; } + double getDouble() { ck(buf.getDouble(buf.position()), getDoubleX(pos)); double x = buf.getDouble(); pos += 8; return x; } + float getFloat() { ck(buf.getFloat(buf.position()), getFloatX(pos)); float x = buf.getFloat(); pos += 4; return x; } + + void putLong(long x) { putLongX(pos, x); pos += 8; buf.putLong(x); } + void putInt(int x) { putIntX(pos, x); pos += 4; buf.putInt(x); } + void putShort(short x) { putShortX(pos, x); pos += 2; buf.putShort(x); } + void putChar(char x) { putShortX(pos, (short)x); pos += 2; buf.putChar(x); } + void putDouble(double x) { putLongX(pos, Double.doubleToRawLongBits(x)); pos += 8; buf.putDouble(x); } + void putFloat(float x) { putIntX(pos, Float.floatToRawIntBits(x)); pos += 4; buf.putFloat(x); } + + void rewind() { pos = 0; buf.rewind(); } +} + +public class HeapByteBufferTest implements Runnable { + + Random random = Utils.getRandomInstance(); + MyByteBuffer data = MyByteBuffer.wrap(new byte[1024]); + + int randomOffset(Random r, MyByteBuffer buf, int size) { + return r.nextInt(buf.capacity() - size); + } + + long iterations; + + HeapByteBufferTest(long iterations) { + this.iterations = iterations; + } + + // The core of the test. Walk over the buffer reading and writing + // random data, XORing it as we go. We can detect writes in the + // wrong place, writes which are too long or too short, and reads + // or writes of the wrong data, + void step(Random r) { + data.order((r.nextInt() & 1) != 0 ? BIG_ENDIAN : LITTLE_ENDIAN); + + data.rewind(); + while (data.position() < data.capacity()) + data.putLong(data.getLong() ^ random.nextLong()); + + data.rewind(); + while (data.position() < data.capacity()) + data.putInt(data.getInt() ^ random.nextInt()); + + data.rewind(); + while (data.position() < data.capacity()) + data.putShort((short)(data.getShort() ^ random.nextInt())); + + data.rewind(); + while (data.position() < data.capacity()) + data.putChar((char)(data.getChar() ^ random.nextInt())); + + data.rewind(); + while (data.position() < data.capacity()) { + data.putDouble(combine(data.getDouble(), random.nextLong())); + } + + data.rewind(); + while (data.position() < data.capacity()) + data.putFloat(combine(data.getFloat(), random.nextInt())); + + for (int i = 0; i < 100; i++) { + int offset = randomOffset(r, data, 8); + data.putLong(offset, data.getLong(offset) ^ random.nextLong()); + } + for (int i = 0; i < 100; i++) { + int offset = randomOffset(r, data, 4); + data.putInt(offset, data.getInt(offset) ^ random.nextInt()); + } + for (int i = 0; i < 100; i++) { + int offset = randomOffset(r, data, 2); + data.putShort(offset, (short)(data.getShort(offset) ^ random.nextInt())); + } + for (int i = 0; i < 100; i++) { + int offset = randomOffset(r, data, 2); + data.putChar(offset, (char)(data.getChar(offset) ^ random.nextInt())); + } + for (int i = 0; i < 100; i++) { + int offset = randomOffset(r, data, 8); + data.putDouble(offset, combine(data.getDouble(offset), random.nextLong())); + } + for (int i = 0; i < 100; i++) { + int offset = randomOffset(r, data, 4); + data.putFloat(offset, combine(data.getFloat(offset), random.nextInt())); + } + } + + // XOR the bit pattern of a double and a long, returning the + // result as a double. + // + // We convert signalling NaNs to quiet NaNs. We need to do this + // because some platforms (in particular legacy 80x87) do not + // provide transparent conversions between integer and + // floating-point types even when using raw conversions but + // quietly convert sNaN to qNaN. This causes spurious test + // failures when the template interpreter uses 80x87 and the JITs + // use XMM registers. + // + public double combine(double prev, long bits) { + bits ^= Double.doubleToRawLongBits(prev); + double result = Double.longBitsToDouble(bits); + if (Double.isNaN(result)) { + result = Double.longBitsToDouble(bits | 0x8000000000000l); + } + return result; + } + + // XOR the bit pattern of a float and an int, returning the result + // as a float. Convert sNaNs to qNaNs. + public Float combine(float prev, int bits) { + bits ^= Float.floatToRawIntBits(prev); + Float result = Float.intBitsToFloat(bits); + if (Float.isNaN(result)) { + result = Float.intBitsToFloat(bits | 0x400000); + } + return result; + } + + public void run() { + for (int i = 0; i < data.capacity(); i += 8) { + data.putLong(i, random.nextLong()); + } + + for (int i = 0; i < iterations; i++) { + step(random); + } + + if (!Arrays.equals(data.array(), data.backingArray())) { + throw new RuntimeException(); + } + } + + public static void main(String[] args) { + // The number of iterations is high to ensure that tiered + // compilation kicks in all the way up to C2. + long iterations = 100000; + if (args.length > 0) + iterations = Long.parseLong(args[0]); + + new HeapByteBufferTest(iterations).run(); + } +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/jsr292/CallSiteDepContextTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jsr292/CallSiteDepContextTest.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8057967 + * @ignore 8079205 + * @run main/bootclasspath -Xbatch java.lang.invoke.CallSiteDepContextTest + */ +package java.lang.invoke; + +import java.lang.ref.*; +import jdk.internal.org.objectweb.asm.*; +import sun.misc.Unsafe; + +import static jdk.internal.org.objectweb.asm.Opcodes.*; + +public class CallSiteDepContextTest { + static final Unsafe UNSAFE = Unsafe.getUnsafe(); + static final MethodHandles.Lookup LOOKUP = MethodHandles.Lookup.IMPL_LOOKUP; + static final String CLASS_NAME = "java/lang/invoke/Test"; + static final String METHOD_NAME = "m"; + static final MethodType TYPE = MethodType.methodType(int.class); + + static MutableCallSite mcs; + static MethodHandle bsmMH; + + static { + try { + bsmMH = LOOKUP.findStatic( + CallSiteDepContextTest.class, "bootstrap", + MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class)); + } catch(Throwable e) { + throw new InternalError(e); + } + } + + public static CallSite bootstrap(MethodHandles.Lookup caller, + String invokedName, + MethodType invokedType) { + return mcs; + } + + static class T { + static int f1() { return 1; } + static int f2() { return 2; } + } + + static byte[] getClassFile(String suffix) { + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + MethodVisitor mv; + cw.visit(52, ACC_PUBLIC | ACC_SUPER, CLASS_NAME + suffix, null, "java/lang/Object", null); + { + mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, METHOD_NAME, TYPE.toMethodDescriptorString(), null, null); + mv.visitCode(); + Handle bsm = new Handle(H_INVOKESTATIC, + "java/lang/invoke/CallSiteDepContextTest", "bootstrap", + bsmMH.type().toMethodDescriptorString()); + mv.visitInvokeDynamicInsn("methodName", TYPE.toMethodDescriptorString(), bsm); + mv.visitInsn(IRETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + cw.visitEnd(); + return cw.toByteArray(); + } + + private static void execute(int expected, MethodHandle... mhs) throws Throwable { + for (int i = 0; i < 20_000; i++) { + for (MethodHandle mh : mhs) { + int r = (int) mh.invokeExact(); + if (r != expected) { + throw new Error(r + " != " + expected); + } + } + } + } + + public static void testSharedCallSite() throws Throwable { + Class cls1 = UNSAFE.defineAnonymousClass(Object.class, getClassFile("CS_1"), null); + Class cls2 = UNSAFE.defineAnonymousClass(Object.class, getClassFile("CS_2"), null); + + MethodHandle[] mhs = new MethodHandle[] { + LOOKUP.findStatic(cls1, METHOD_NAME, TYPE), + LOOKUP.findStatic(cls2, METHOD_NAME, TYPE) + }; + + mcs = new MutableCallSite(LOOKUP.findStatic(T.class, "f1", TYPE)); + execute(1, mhs); + mcs.setTarget(LOOKUP.findStatic(T.class, "f2", TYPE)); + execute(2, mhs); + } + + public static void testNonBoundCallSite() throws Throwable { + mcs = new MutableCallSite(LOOKUP.findStatic(T.class, "f1", TYPE)); + + // mcs.context == null + MethodHandle mh = mcs.dynamicInvoker(); + execute(1, mh); + + // mcs.context == cls1 + Class cls1 = UNSAFE.defineAnonymousClass(Object.class, getClassFile("NonBound_1"), null); + MethodHandle mh1 = LOOKUP.findStatic(cls1, METHOD_NAME, TYPE); + + execute(1, mh1); + + mcs.setTarget(LOOKUP.findStatic(T.class, "f2", TYPE)); + + execute(2, mh, mh1); + } + + static ReferenceQueue rq = new ReferenceQueue(); + static PhantomReference ref; + + public static void testGC() throws Throwable { + mcs = new MutableCallSite(LOOKUP.findStatic(T.class, "f1", TYPE)); + + Class[] cls = new Class[] { + UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_1"), null), + UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_2"), null), + }; + + MethodHandle[] mhs = new MethodHandle[] { + LOOKUP.findStatic(cls[0], METHOD_NAME, TYPE), + LOOKUP.findStatic(cls[1], METHOD_NAME, TYPE), + }; + + // mcs.context == cls[0] + int r = (int) mhs[0].invokeExact(); + + execute(1, mhs); + + ref = new PhantomReference<>(cls[0], rq); + cls[0] = UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_3"), null); + mhs[0] = LOOKUP.findStatic(cls[0], METHOD_NAME, TYPE); + + do { + System.gc(); + try { + Reference ref1 = rq.remove(1000); + if (ref1 == ref) { + ref1.clear(); + System.gc(); // Ensure that the stale context is cleared + break; + } + } catch(InterruptedException e) { /* ignore */ } + } while (true); + + execute(1, mhs); + mcs.setTarget(LOOKUP.findStatic(T.class, "f2", TYPE)); + execute(2, mhs); + } + + public static void main(String[] args) throws Throwable { + testSharedCallSite(); + testNonBoundCallSite(); + testGC(); + System.out.println("TEST PASSED"); + } +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/jsr292/MHInlineTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jsr292/MHInlineTest.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +/** + * @test + * @bug 8062280 + * @summary C2: inlining failure due to access checks being too strict + * @library /testlibrary + * @run main/othervm MHInlineTest + */ +import java.lang.invoke.*; +import com.oracle.java.testlibrary.*; +import static com.oracle.java.testlibrary.Asserts.*; + +public class MHInlineTest { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", "-showversion", + "-server", "-XX:-TieredCompilation", "-Xbatch", + "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining", + "-XX:CompileCommand=dontinline,MHInlineTest::test*", + "MHInlineTest$Launcher"); + + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + + analyzer.shouldHaveExitValue(0); + + // The test is applicable only to C2 (present in Server VM). + if (analyzer.getStderr().contains("Server VM")) { + analyzer.shouldContain("MHInlineTest$B::public_x (3 bytes) inline (hot)"); + analyzer.shouldContain("MHInlineTest$B::protected_x (3 bytes) inline (hot)"); + analyzer.shouldContain("MHInlineTest$B::package_x (3 bytes) inline (hot)"); + analyzer.shouldContain("MHInlineTest$A::package_final_x (3 bytes) inline (hot)"); + analyzer.shouldContain("MHInlineTest$B::private_x (3 bytes) inline (hot)"); + analyzer.shouldContain("MHInlineTest$B::private_static_x (3 bytes) inline (hot)"); + analyzer.shouldContain("MHInlineTest$A::package_static_x (3 bytes) inline (hot)"); + } + } + + static class A { + public static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); + + public Class public_x() { return A.class; } + protected Class protected_x() { return A.class; } + Class package_x() { return A.class; } + final Class package_final_x() { return A.class; } + + static Class package_static_x() { return A.class; } + } + + static class B extends A { + public static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); + + @Override public Class public_x() { return B.class; } + @Override protected Class protected_x() { return B.class; } + @Override Class package_x() { return B.class; } + + private Class private_x() { return B.class; } + static Class private_static_x() { return B.class; } + } + + static final MethodHandle A_PUBLIC_X; + static final MethodHandle A_PROTECTED_X; + static final MethodHandle A_PACKAGE_X; + static final MethodHandle A_PACKAGE_STATIC_X; + static final MethodHandle A_PACKAGE_FINAL_X; + + static final MethodHandle B_PRIVATE_X; + static final MethodHandle B_PRIVATE_STATIC_X; + + static { + try { + MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); + + A_PUBLIC_X = LOOKUP.findVirtual( + A.class, "public_x", MethodType.methodType(Class.class)); + A_PROTECTED_X = LOOKUP.findVirtual( + A.class, "protected_x", MethodType.methodType(Class.class)); + A_PACKAGE_X = LOOKUP.findVirtual( + A.class, "package_x", MethodType.methodType(Class.class)); + A_PACKAGE_FINAL_X = LOOKUP.findVirtual( + A.class, "package_final_x", MethodType.methodType(Class.class)); + A_PACKAGE_STATIC_X = LOOKUP.findStatic( + A.class, "package_static_x", MethodType.methodType(Class.class)); + + B_PRIVATE_X = B.LOOKUP.findVirtual( + B.class, "private_x", MethodType.methodType(Class.class)); + B_PRIVATE_STATIC_X = B.LOOKUP.findStatic( + B.class, "private_static_x", MethodType.methodType(Class.class)); + } catch (Exception e) { + throw new Error(e); + } + } + + static final A a = new B(); + + private static void testPublicMH() { + try { + Class r = (Class)A_PUBLIC_X.invokeExact(a); + assertEquals(r, B.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testProtectedMH() { + try { + Class r = (Class)A_PROTECTED_X.invokeExact(a); + assertEquals(r, B.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testPackageMH() { + try { + Class r = (Class)A_PACKAGE_X.invokeExact(a); + assertEquals(r, B.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testPackageFinalMH() { + try { + Class r = (Class)A_PACKAGE_FINAL_X.invokeExact(a); + assertEquals(r, A.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testPackageStaticMH() { + try { + Class r = (Class)A_PACKAGE_STATIC_X.invokeExact(); + assertEquals(r, A.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testPrivateMH() { + try { + Class r = (Class)B_PRIVATE_X.invokeExact((B)a); + assertEquals(r, B.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + private static void testPrivateStaticMH() { + try { + Class r = (Class)B_PRIVATE_STATIC_X.invokeExact(); + assertEquals(r, B.class); + } catch (Throwable throwable) { + throw new Error(throwable); + } + } + + static class Launcher { + public static void main(String[] args) throws Exception { + for (int i = 0; i < 20_000; i++) { + testPublicMH(); + } + for (int i = 0; i < 20_000; i++) { + testProtectedMH(); + } + for (int i = 0; i < 20_000; i++) { + testPackageMH(); + } + for (int i = 0; i < 20_000; i++) { + testPackageFinalMH(); + } + for (int i = 0; i < 20_000; i++) { + testPackageStaticMH(); + } + for (int i = 0; i < 20_000; i++) { + testPrivateMH(); + } + for (int i = 0; i < 20_000; i++) { + testPrivateStaticMH(); + } + } + } +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/jsr292/RedefineMethodUsedByMultipleMethodHandles.java --- a/hotspot/test/compiler/jsr292/RedefineMethodUsedByMultipleMethodHandles.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/compiler/jsr292/RedefineMethodUsedByMultipleMethodHandles.java Thu May 07 20:51:12 2015 -0700 @@ -30,7 +30,7 @@ * java.instrument * java.management * @compile -XDignore.symbol.file RedefineMethodUsedByMultipleMethodHandles.java - * @run main RedefineMethodUsedByMultipleMethodHandles + * @run main/othervm RedefineMethodUsedByMultipleMethodHandles */ import java.io.*; diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/loopopts/TestPredicateLostDependency.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/loopopts/TestPredicateLostDependency.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8069191 + * @summary predicate moved out of loops and CastPP removal causes dependency to be lost + * @run main/othervm -Xcomp -XX:CompileOnly=TestPredicateLostDependency.m1 -XX:+IgnoreUnrecognizedVMOptions -XX:+StressGCM TestPredicateLostDependency + * + */ + +public class TestPredicateLostDependency { + static class A { + int i; + } + + static class B extends A { + } + + static boolean crash = false; + + static boolean m2() { + return crash; + } + + static int m3(float[] arr) { + return 0; + } + + static float m1(A aa) { + float res = 0; + float[] arr = new float[10]; + for (int i = 0; i < 10; i++) { + if (m2()) { + arr = null; + } + m3(arr); + int j = arr.length; + int k = 0; + for (k = 9; k < j; k++) { + } + if (k == 10) { + if (aa instanceof B) { + } + } + res += arr[0]; + res += arr[1]; + } + return res; + } + + static public void main(String args[]) { + A a = new A(); + B b = new B(); + for (int i = 0; i < 20000; i++) { + m1(a); + } + crash = true; + try { + m1(a); + } catch (NullPointerException npe) {} + } +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/loopopts/TestSplitIfUnswitchedLoopsEliminated.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/loopopts/TestSplitIfUnswitchedLoopsEliminated.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8078426 + * @summary split if finds predicates on several incoming paths when unswitched's loops are optimized out + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:-UseCompressedOops TestSplitIfUnswitchedLoopsEliminated + * + */ + + +public class TestSplitIfUnswitchedLoopsEliminated { + + static class A { + int f; + } + + static A aa = new A(); + static A aaa = new A(); + + static int test_helper(int stop, boolean unswitch) { + A a = null; + for (int i = 3; i < 10; i++) { + if (unswitch) { + a = null; + } else { + a = aa; + int v = a.f; + } + } + if (stop != 4) { + a = aaa; + } + if (a != null) { + return a.f; + } + return 0; + } + + static int test(boolean unswitch) { + int stop = 1; + for (; stop < 3; stop *= 4) { + } + return test_helper(stop, unswitch); + } + + public static void main(String[] args) { + for (int i = 0; i < 20000; i++) { + test_helper(10, i%2 == 0); + test(i%2 == 0); + } + } +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/loopopts/superword/ProdRed_Double.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/loopopts/superword/ProdRed_Double.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8074981 + * @summary Add C2 x86 Superword support for scalar product reduction optimizations : float test + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 ProdRed_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 ProdRed_Double + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 ProdRed_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 ProdRed_Double + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 ProdRed_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 ProdRed_Double + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 ProdRed_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 ProdRed_Double + */ + +public class ProdRed_Double +{ + public static void main(String[] args) throws Exception { + double[] a = new double[256*1024]; + double[] b = new double[256*1024]; + prodReductionInit(a,b); + double valid = 2000; + double total = 0; + for(int j = 0; j < 2000; j++) { + total = j + 1; + total = prodReductionImplement(a,b, total); + } + if(total == valid) { + System.out.println("Success"); + } else { + System.out.println("Invalid sum of elements variable in total: " + total); + System.out.println("Expected value = " + valid); + throw new Exception("Failed"); + } + } + + public static void prodReductionInit(double[] a, double[] b) + { + for(int i = 0; i < a.length; i++) + { + a[i] = i + 2; + b[i] = i + 1; + } + } + + public static double prodReductionImplement(double[] a, double[] b, double total) + { + for(int i = 0; i < a.length; i++) + { + total *= a[i] - b[i]; + } + return total; + } + +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/loopopts/superword/ProdRed_Float.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/loopopts/superword/ProdRed_Float.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8074981 + * @summary Add C2 x86 Superword support for scalar product reduction optimizations : float test + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 ProdRed_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 ProdRed_Float + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 ProdRed_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 ProdRed_Float + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 ProdRed_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 ProdRed_Float + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 ProdRed_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 ProdRed_Float + */ + +public class ProdRed_Float +{ + public static void main(String[] args) throws Exception { + float[] a = new float[256*1024]; + float[] b = new float[256*1024]; + prodReductionInit(a,b); + float valid = 2000; + float total = 0; + for(int j = 0; j < 2000; j++) { + total = j + 1; + total = prodReductionImplement(a,b, total); + } + if(total == valid) { + System.out.println("Success"); + } else { + System.out.println("Invalid sum of elements variable in total: " + total); + System.out.println("Expected value = " + valid); + throw new Exception("Failed"); + } + } + + public static void prodReductionInit(float[] a, float[] b) + { + for(int i = 0; i < a.length; i++) + { + a[i] = i + 2; + b[i] = i + 1; + } + } + + public static float prodReductionImplement(float[] a, float[] b, float total) + { + for(int i = 0; i < a.length; i++) + { + total *= a[i] - b[i]; + } + return total; + } + +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/loopopts/superword/ProdRed_Int.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/loopopts/superword/ProdRed_Int.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8074981 + * @summary Add C2 x86 Superword support for scalar product reduction optimizations : int test + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 ProdRed_Int + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 ProdRed_Int + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 ProdRed_Int + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 ProdRed_Int + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 ProdRed_Int + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 ProdRed_Int + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 ProdRed_Int + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 ProdRed_Int + */ + +public class ProdRed_Int +{ + public static void main(String[] args) throws Exception { + int[] a = new int[256*1024]; + int[] b = new int[256*1024]; + prodReductionInit(a,b); + int valid = 419430401; + int total = 1; + for(int j = 0; j < 2000; j++) { + total = prodReductionImplement(a,b,total); + } + if(total == valid) { + System.out.println("Success"); + } else { + System.out.println("Invalid sum of elements variable in total: " + total); + System.out.println("Expected value = " + valid); + throw new Exception("Failed"); + } + } + + public static void prodReductionInit(int[] a, int[] b) + { + for(int i = 0; i < a.length; i++) + { + a[i] = i + 2; + b[i] = i + 1; + } + } + + public static int prodReductionImplement(int[] a, int[] b, int total) + { + for(int i = 0; i < a.length; i++) + { + total *= a[i] + b[i]; + } + return total; + } + +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/loopopts/superword/SumRed_Double.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/loopopts/superword/SumRed_Double.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8074981 + * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : double test + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRed_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRed_Double + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 SumRed_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 SumRed_Double + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 SumRed_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 SumRed_Double + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 SumRed_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 SumRed_Double + */ + +public class SumRed_Double +{ + public static void main(String[] args) throws Exception { + double[] a = new double[256*1024]; + double[] b = new double[256*1024]; + double[] c = new double[256*1024]; + double[] d = new double[256*1024]; + sumReductionInit(a,b,c); + double total = 0; + double valid = 3.6028590866691944E19; + for(int j = 0; j < 2000; j++) { + total = sumReductionImplement(a,b,c,d,total); + } + if(total == valid) { + System.out.println("Success"); + } else { + System.out.println("Invalid sum of elements variable in total: " + total); + System.out.println("Expected value = " + valid); + throw new Exception("Failed"); + } + } + + public static void sumReductionInit( + double[] a, + double[] b, + double[] c) + { + for(int j = 0; j < 1; j++) + { + for(int i = 0; i < a.length; i++) + { + a[i] = i * 1 + j; + b[i] = i * 1 - j; + c[i] = i + j; + } + } + } + + public static double sumReductionImplement( + double[] a, + double[] b, + double[] c, + double[] d, + double total) + { + for(int i = 0; i < a.length; i++) + { + d[i]= (a[i] * b[i]) + (a[i] * c[i]) + (b[i] * c[i]); + total += d[i]; + } + return total; + } + +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/loopopts/superword/SumRed_Float.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/loopopts/superword/SumRed_Float.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8074981 + * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : float test + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRed_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRed_Float + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 SumRed_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 SumRed_Float + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 SumRed_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 SumRed_Float + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 SumRed_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 SumRed_Float + */ + +public class SumRed_Float +{ + public static void main(String[] args) throws Exception { + float[] a = new float[256*1024]; + float[] b = new float[256*1024]; + float[] c = new float[256*1024]; + float[] d = new float[256*1024]; + sumReductionInit(a,b,c); + float total = 0; + float valid = (float)4.611686E18; + for(int j = 0; j < 2000; j++) { + total = sumReductionImplement(a,b,c,d,total); + } + if(total == valid) { + System.out.println("Success"); + } else { + System.out.println("Invalid sum of elements variable in total: " + total); + System.out.println("Expected value = " + valid); + throw new Exception("Failed"); + } + } + + public static void sumReductionInit( + float[] a, + float[] b, + float[] c) + { + for(int j = 0; j < 1; j++) + { + for(int i = 0; i < a.length; i++) + { + a[i] = i * 1 + j; + b[i] = i * 1 - j; + c[i] = i + j; + } + } + } + + public static float sumReductionImplement( + float[] a, + float[] b, + float[] c, + float[] d, + float total) + { + for(int i = 0; i < a.length; i++) + { + d[i]= (a[i] * b[i]) + (a[i] * c[i]) + (b[i] * c[i]); + total += d[i]; + } + return total; + } + +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/loopopts/superword/SumRed_Int.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/loopopts/superword/SumRed_Int.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8074981 + * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : int test + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRed_Int + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRed_Int + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 SumRed_Int + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 SumRed_Int + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 SumRed_Int + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 SumRed_Int + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 SumRed_Int + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 SumRed_Int + */ + +public class SumRed_Int +{ + public static void main(String[] args) throws Exception { + int[] a = new int[256*1024]; + int[] b = new int[256*1024]; + int[] c = new int[256*1024]; + int[] d = new int[256*1024]; + sumReductionInit(a,b,c); + int total = 0; + int valid = 262144000; + for(int j = 0; j < 2000; j++) { + total = sumReductionImplement(a,b,c,d,total); + } + if(total == valid) { + System.out.println("Success"); + } else { + System.out.println("Invalid sum of elements variable in total: " + total); + System.out.println("Expected value = " + valid); + throw new Exception("Failed"); + } + } + + public static void sumReductionInit( + int[] a, + int[] b, + int[] c) + { + for(int j = 0; j < 1; j++) + { + for(int i = 0; i < a.length; i++) + { + a[i] = i * 1 + j; + b[i] = i * 1 - j; + c[i] = i + j; + } + } + } + + public static int sumReductionImplement( + int[] a, + int[] b, + int[] c, + int[] d, + int total) + { + for(int i = 0; i < a.length; i++) + { + d[i]= (a[i] * b[i]) + (a[i] * c[i]) + (b[i] * c[i]); + total += d[i]; + } + return total; + } + +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/rangechecks/TestExplicitRangeChecks.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/rangechecks/TestExplicitRangeChecks.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,596 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8073480 + * @summary explicit range checks should be recognized by C2 + * @library /testlibrary /../../test/lib /compiler/whitebox + * @build TestExplicitRangeChecks + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main ClassFileInstaller com.oracle.java.testlibrary.Platform + * @run main/othervm -ea -Xmixed -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:CompileCommand=compileonly,TestExplicitRangeChecks.test* TestExplicitRangeChecks + * + */ + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.util.*; +import sun.hotspot.WhiteBox; +import sun.hotspot.code.NMethod; +import com.oracle.java.testlibrary.Platform; +import sun.misc.Unsafe; + +public class TestExplicitRangeChecks { + + static int[] array = new int[10]; + + @Retention(RetentionPolicy.RUNTIME) + @interface Args { + int[] compile(); + int[] good(); + int[] bad(); + boolean deoptimize() default true; + } + + // Should be compiled as a single unsigned comparison + // 0 <= index < array.length + @Args(compile = {5,}, good = {0, 9}, bad = {-1, 10}) + static boolean test1_1(int index, int[] array) { + if (index < 0 || index >= array.length) { + return false; + } + return true; + } + + // same test but so we can compile with same optimization after trap in test1_1 + static boolean test1_2(int index, int[] array) { + if (index < 0 || index >= array.length) { + return false; + } + return true; + } + + // Shouldn't matter whether first or second test is the one + // against a constants + // 0 <= index < array.length + @Args(compile = {5,}, good = {0, 9}, bad = {-1, 10}) + static boolean test2_1(int index, int[] array) { + if (index >= array.length || index < 0) { + return false; + } + return true; + } + + static boolean test2_2(int index, int[] array) { + if (index >= array.length || index < 0) { + return false; + } + return true; + } + + // 0 <= index <= array.length + @Args(compile = {5,}, good = {0, 10}, bad = {-1, 11}) + static boolean test3_1(int index, int[] array) { + if (index < 0 || index > array.length) { + return false; + } + return true; + } + + static boolean test3_2(int index, int[] array) { + if (index < 0 || index > array.length) { + return false; + } + return true; + } + + // 0 <= index <= array.length + @Args(compile = {5,}, good = {0, 10}, bad = {-1, 11}) + static boolean test4_1(int index, int[] array) { + if (index > array.length || index < 0 ) { + return false; + } + return true; + } + + static boolean test4_2(int index, int[] array) { + if (index > array.length || index < 0) { + return false; + } + return true; + } + + static int[] test5_helper(int i) { + return (i < 100) ? new int[10] : new int[5]; + } + + // 0 < index < array.length + @Args(compile = {5,}, good = {1, 9}, bad = {0, 10}) + static boolean test5_1(int index, int[] array) { + array = test5_helper(index); // array.length must be not constant greater than 1 + if (index <= 0 || index >= array.length) { + return false; + } + return true; + } + + static boolean test5_2(int index, int[] array) { + array = test5_helper(index); // array.length must be not constant greater than 1 + if (index <= 0 || index >= array.length) { + return false; + } + return true; + } + + // 0 < index < array.length + @Args(compile = {5,}, good = {1, 9}, bad = {0, 10}) + static boolean test6_1(int index, int[] array) { + array = test5_helper(index); // array.length must be not constant greater than 1 + if (index >= array.length || index <= 0 ) { + return false; + } + return true; + } + + static boolean test6_2(int index, int[] array) { + array = test5_helper(index); // array.length must be not constant greater than 1 + if (index >= array.length || index <= 0) { + return false; + } + return true; + } + + // 0 < index <= array.length + @Args(compile = {5,}, good = {1, 10}, bad = {0, 11}) + static boolean test7_1(int index, int[] array) { + if (index <= 0 || index > array.length) { + return false; + } + return true; + } + + static boolean test7_2(int index, int[] array) { + if (index <= 0 || index > array.length) { + return false; + } + return true; + } + + // 0 < index <= array.length + @Args(compile = {5,}, good = {1, 10}, bad = {0, 11}) + static boolean test8_1(int index, int[] array) { + if (index > array.length || index <= 0 ) { + return false; + } + return true; + } + + static boolean test8_2(int index, int[] array) { + if (index > array.length || index <= 0) { + return false; + } + return true; + } + + static int[] test9_helper1(int i) { + return (i < 100) ? new int[1] : new int[2]; + } + + static int[] test9_helper2(int i) { + return (i < 100) ? new int[10] : new int[11]; + } + + // array1.length <= index < array2.length + @Args(compile = {5,}, good = {1, 9}, bad = {0, 10}) + static boolean test9_1(int index, int[] array) { + int[] array1 = test9_helper1(index); + int[] array2 = test9_helper2(index); + if (index < array1.length || index >= array2.length) { + return false; + } + return true; + } + + static boolean test9_2(int index, int[] array) { + int[] array1 = test9_helper1(index); + int[] array2 = test9_helper2(index); + if (index < array1.length || index >= array2.length) { + return false; + } + return true; + } + + // Previously supported pattern + @Args(compile = {-5,5,15}, good = {0, 9}, bad = {-1, 10}, deoptimize=false) + static boolean test10_1(int index, int[] array) { + if (index < 0 || index >= 10) { + return false; + } + return true; + } + + static int[] array11 = new int[10]; + @Args(compile = {5,}, good = {0, 9}, bad = {-1,}) + static boolean test11_1(int index, int[] array) { + if (index < 0) { + return false; + } + int unused = array11[index]; + // If this one is folded with the first test then we allow + // array access above to proceed even for out of bound array + // index and the method throws an + // ArrayIndexOutOfBoundsException. + if (index >= array.length) { + return false; + } + return true; + } + + static int[] array12 = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10}; + @Args(compile = {5,}, good = {0, 9}, bad = {-1,}) + static boolean test12_1(int index, int[] array) { + // Cannot be folded otherwise would cause incorrect array + // access if the array12 range check is executed before the + // folded test. + if (index < 0 || index >= array12[index]) { + return false; + } + return true; + } + + // Same as test1_1 but pass null array when index < 0: shouldn't + // cause NPE. + @Args(compile = {5,}, good = {0, 9}, bad = {}) + static boolean test13_1(int index, int[] array) { + if (index < 0 || index >= array.length) { + return false; + } + return true; + } + + // Same as test10 but with uncommon traps + @Args(compile = {5}, good = {0, 9}, bad = {-1, 10}) + static boolean test14_1(int index, int[] array) { + if (index < 0 || index >= 10) { + return false; + } + return true; + } + + static boolean test14_2(int index, int[] array) { + if (index < 0 || index >= 10) { + return false; + } + return true; + } + + // Same as test13_1 but pass null array: null trap should be reported on first if + @Args(compile = {5,}, good = {0, 9}, bad = {}) + static boolean test15_1(int index, int[] array) { + if (index < 0 || index >= array.length) { + return false; + } + return true; + } + + // Same as test1 but with no null check between the integer comparisons + @Args(compile = {5,}, good = {0, 9}, bad = {-1, 10}) + static boolean test16_1(int index, int[] array) { + int l = array.length; + if (index < 0 || index >= l) { + return false; + } + return true; + } + + static boolean test16_2(int index, int[] array) { + int l = array.length; + if (index < 0 || index >= l) { + return false; + } + return true; + } + + // Same as test1 but bound check on array access should optimize + // out. + @Args(compile = {5,}, good = {0, 9}, bad = {-1, 10}) + static boolean test17_1(int index, int[] array) { + if (index < 0 || index >= array.length) { + return false; + } + array[index] = 0; + return true; + } + + static boolean test17_2(int index, int[] array) { + if (index < 0 || index >= array.length) { + return false; + } + array[index] = 0; + return true; + } + + // Same as test1 but range check smearing should optimize + // 3rd range check out. + @Args(compile = {5,}, good = {}, bad = {}) + static boolean test18_1(int index, int[] array) { + if (index < 0 || index >= array.length) { + return false; + } + array[index+2] = 0; + array[index+1] = 0; + return true; + } + + static boolean test19_helper1(int index) { + if (index < 12) { + return false; + } + return true; + } + + static boolean test19_helper2(int index) { + if (index > 8) { + return false; + } + return true; + } + + // Second test should be optimized out + static boolean test19(int index, int[] array) { + test19_helper1(index); + test19_helper2(index); + return true; + } + + static boolean success = true; + + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + final HashMap tests = new HashMap<>(); + { + for (Method m : this.getClass().getDeclaredMethods()) { + if (m.getName().matches("test[0-9]+(_[0-9])?")) { + assert(Modifier.isStatic(m.getModifiers())) : m; + tests.put(m.getName(), m); + } + } + } + + void doTest(String name) throws Exception { + Method m = tests.get(name + "_1"); + + Args anno = m.getAnnotation(Args.class); + int[] compile = anno.compile(); + int[] good = anno.good(); + int[] bad = anno.bad(); + boolean deoptimize = anno.deoptimize(); + + // Get compiled + for (int i = 0; i < 20000;) { + for (int j = 0; j < compile.length; j++) { + m.invoke(null, compile[j], array); + i++; + } + } + + if (!WHITE_BOX.isMethodCompiled(m)) { + System.out.println(name + "_1 not compiled"); + success = false; + } + + // check that good values don't trigger exception or + // deoptimization + for (int i = 0; i < good.length; i++) { + boolean res = (boolean)m.invoke(null, good[i], array); + + if (!res) { + System.out.println(name + " bad result for good input " + good[i]); + success = false; + } + if (!WHITE_BOX.isMethodCompiled(m)) { + System.out.println(name + " deoptimized on valid access"); + success = false; + } + } + + // check that bad values trigger exception and deoptimization + for (int i = 0; i < bad.length; i++) { + if (i > 0 && deoptimize) { + m = tests.get(name + "_" + (i+1)); + for (int k = 0; k < 20000;) { + for (int j = 0; j < compile.length; j++) { + m.invoke(null, compile[j], array); + k++; + } + } + if (!WHITE_BOX.isMethodCompiled(m)) { + System.out.println(name + ("_" + (i+1)) + " not compiled"); + success = false; + } + } + + boolean res = (boolean)m.invoke(null, bad[i], array); + + if (res) { + System.out.println(name + " bad result for bad input " + bad[i]); + success = false; + } + if (Platform.isServer()) { + if (deoptimize && WHITE_BOX.isMethodCompiled(m)) { + System.out.println(name + " not deoptimized on invalid access"); + success = false; + } else if (!deoptimize && !WHITE_BOX.isMethodCompiled(m)) { + System.out.println(name + " deoptimized on invalid access"); + success = false; + } + } + } + + } + + private static final Unsafe UNSAFE; + + static { + try { + Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); + unsafeField.setAccessible(true); + UNSAFE = (Unsafe) unsafeField.get(null); + } + catch (Exception e) { + throw new AssertionError(e); + } + } + + // On x64, int to long conversion should optimize away in address computation + static int test20(int[] a) { + int sum = 0; + for (int i = 0; i < a.length; i++) { + sum += test20_helper(a, i); + } + return sum; + } + + static int test20_helper(int[] a, int i) { + if (i < 0 || i >= a.length) + throw new ArrayIndexOutOfBoundsException(); + + long address = (((long) i) << 2) + UNSAFE.ARRAY_INT_BASE_OFFSET; + return UNSAFE.getInt(a, address); + } + + static int test21(int[] a) { + int sum = 0; + for (int i = 0; i < a.length; i++) { + sum += test20_helper(a, i); + } + return sum; + } + + static int test21_helper(int[] a, int i) { + if (i < 0 || i >= a.length) + throw new ArrayIndexOutOfBoundsException(); + + long address = (((long) i) << 2) + UNSAFE.ARRAY_INT_BASE_OFFSET; + return UNSAFE.getIntVolatile(a, address); + } + + static public void main(String[] args) throws Exception { + + if (WHITE_BOX.getBooleanVMFlag("BackgroundCompilation")) { + throw new AssertionError("Background compilation enabled"); + } + + TestExplicitRangeChecks test = new TestExplicitRangeChecks(); + + test.doTest("test1"); + test.doTest("test2"); + test.doTest("test3"); + test.doTest("test4"); + + // pollute branch profile + for (int i = 0; i < 10000; i++) { + test5_helper((i%2 == 0) ? 0 : 1000); + } + + test.doTest("test5"); + test.doTest("test6"); + test.doTest("test7"); + test.doTest("test8"); + + // pollute branch profile + for (int i = 0; i < 10000; i++) { + test9_helper1((i%2 == 0) ? 0 : 1000); + test9_helper2((i%2 == 0) ? 0 : 1000); + } + + test.doTest("test9"); + test.doTest("test10"); + test.doTest("test11"); + test.doTest("test12"); + + test.doTest("test13"); + { + Method m = test.tests.get("test13_1"); + for (int i = 0; i < 1; i++) { + test13_1(-1, null); + if (!WHITE_BOX.isMethodCompiled(m)) { + break; + } + } + } + test.doTest("test13"); + { + Method m = test.tests.get("test13_1"); + for (int i = 0; i < 10; i++) { + test13_1(-1, null); + if (!WHITE_BOX.isMethodCompiled(m)) { + break; + } + } + } + + test.doTest("test14"); + + test.doTest("test15"); + { + Method m = test.tests.get("test15_1"); + for (int i = 0; i < 10; i++) { + try { + test15_1(5, null); + } catch(NullPointerException npe) {} + if (!WHITE_BOX.isMethodCompiled(m)) { + break; + } + } + } + test.doTest("test15"); + test.doTest("test16"); + test.doTest("test17"); + test.doTest("test18"); + + for (int i = 0; i < 20000; i++) { + test19_helper1(20); + test19_helper2(5); + } + + { + Method m = test.tests.get("test19"); + WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION); + } + + for (int i = 0; i < 20000; i++) { + test20(array); + } + + for (int i = 0; i < 20000; i++) { + test21(array); + } + + if (!success) { + throw new RuntimeException("some tests failed"); + } + } +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/startup/NumCompilerThreadsCheck.java --- a/hotspot/test/compiler/startup/NumCompilerThreadsCheck.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/compiler/startup/NumCompilerThreadsCheck.java Thu May 07 20:51:12 2015 -0700 @@ -40,20 +40,10 @@ String expectedOutput = "CICompilerCount of -1 is invalid"; out.shouldContain(expectedOutput); - if (isZeroVm()) { + if (Platform.isZero()) { String expectedLowWaterMarkText = "must be at least 0"; out.shouldContain(expectedLowWaterMarkText); } } - private static boolean isZeroVm() { - String vmName = System.getProperty("java.vm.name"); - if (vmName == null) { - throw new RuntimeException("No VM name"); - } - if (vmName.toLowerCase().contains("zero")) { - return true; - } - return false; - } } diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/types/TestMeetExactConstantArrays.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/types/TestMeetExactConstantArrays.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8075587 + * @summary meet of 2 constant arrays result in bottom + * @run main/othervm TestMeetExactConstantArrays + * + */ + +public class TestMeetExactConstantArrays { + public abstract static class NumbersHolder { + public Number[] getNumbers() { + return null; + } + } + + public static class IntegersHolder extends NumbersHolder { + private final static Integer integers[] = { new Integer(1) }; + + public Number[] getNumbers() { + return integers; + } + } + + public static class LongsHolder extends NumbersHolder { + private final static Long longs[] = { new Long(1) }; + + public Number[] getNumbers() { + return longs; + } + } + + public static final void loopNumbers(NumbersHolder numbersHolder) { + Number[] numbers = numbersHolder.getNumbers(); + for (int i = 0; i < numbers.length; i++) { + numbers[i].longValue(); + } + } + + public static void main(String[] args) throws Exception { + for (int i = 0; i < 10000; i++) { + IntegersHolder integersHolder = new IntegersHolder(); + LongsHolder longsHolder = new LongsHolder(); + loopNumbers(integersHolder); + loopNumbers(longsHolder); + } + } +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/uncommontrap/TestUnstableIfTrap.java --- a/hotspot/test/compiler/uncommontrap/TestUnstableIfTrap.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/compiler/uncommontrap/TestUnstableIfTrap.java Thu May 07 20:51:12 2015 -0700 @@ -69,7 +69,7 @@ * -XX:CompileCommand=compileonly,UnstableIfExecutable.test * -XX:LogFile=never_taken_fired.xml * TestUnstableIfTrap NEVER_TAKEN true - * @run main uncommontrap.Verifier always_taken_not_fired.xml + * @run main/othervm uncommontrap.Verifier always_taken_not_fired.xml * always_taken_fired.xml * never_taken_not_fired.xml * never_taken_fired.xml diff -r a4b1c7d6317a -r febd2373771c hotspot/test/compiler/whitebox/DeoptimizeFramesTest.java --- a/hotspot/test/compiler/whitebox/DeoptimizeFramesTest.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/compiler/whitebox/DeoptimizeFramesTest.java Thu May 07 20:51:12 2015 -0700 @@ -32,12 +32,12 @@ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI -Xmixed * -XX:CompileCommand=compileonly,DeoptimizeFramesTest$TestCaseImpl::method - * -XX:+IgnoreUnexpectedVMOptions -XX:-DeoptimizeRandom -XX:-DeoptimizeALot + * -XX:+IgnoreUnrecognizedVMOptions -XX:-DeoptimizeRandom -XX:-DeoptimizeALot * DeoptimizeFramesTest true * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI -Xmixed * -XX:CompileCommand=compileonly,DeoptimizeFramesTest$TestCaseImpl::method - * -XX:+IgnoreUnexpectedVMOptions -XX:-DeoptimizeRandom -XX:-DeoptimizeALot + * -XX:+IgnoreUnrecognizedVMOptions -XX:-DeoptimizeRandom -XX:-DeoptimizeALot * DeoptimizeFramesTest false * @summary testing of WB::deoptimizeFrames() */ diff -r a4b1c7d6317a -r febd2373771c hotspot/test/gc/TestSmallHeap.java --- a/hotspot/test/gc/TestSmallHeap.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/gc/TestSmallHeap.java Thu May 07 20:51:12 2015 -0700 @@ -58,9 +58,11 @@ */ import com.oracle.java.testlibrary.*; +import com.sun.management.HotSpotDiagnosticMXBean; +import java.lang.management.ManagementFactory; import static com.oracle.java.testlibrary.Asserts.*; + import sun.hotspot.WhiteBox; -import sun.management.ManagementFactoryHelper; public class TestSmallHeap { @@ -69,7 +71,9 @@ int pageSize = wb.getVMPageSize(); int heapBytesPerCard = 512; long expectedMaxHeap = pageSize * heapBytesPerCard; - String maxHeap = ManagementFactoryHelper.getDiagnosticMXBean().getVMOption("MaxHeapSize").getValue(); + String maxHeap + = ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class) + .getVMOption("MaxHeapSize").getValue(); assertEQ(Long.parseLong(maxHeap), expectedMaxHeap); } } diff -r a4b1c7d6317a -r febd2373771c hotspot/test/gc/arguments/TestG1HeapRegionSize.java --- a/hotspot/test/gc/arguments/TestG1HeapRegionSize.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/gc/arguments/TestG1HeapRegionSize.java Thu May 07 20:51:12 2015 -0700 @@ -33,14 +33,15 @@ * @run main/othervm -XX:G1HeapRegionSize=64m -Xmx256m TestG1HeapRegionSize 33554432 */ -import sun.management.ManagementFactoryHelper; import com.sun.management.HotSpotDiagnosticMXBean; import com.sun.management.VMOption; +import java.lang.management.ManagementFactory; public class TestG1HeapRegionSize { public static void main(String[] args) { - HotSpotDiagnosticMXBean diagnostic = ManagementFactoryHelper.getDiagnosticMXBean(); + HotSpotDiagnosticMXBean diagnostic = + ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class); String expectedValue = getExpectedValue(args); VMOption option = diagnostic.getVMOption("UseG1GC"); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/gc/arguments/TestInitialTenuringThreshold.java --- a/hotspot/test/gc/arguments/TestInitialTenuringThreshold.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/gc/arguments/TestInitialTenuringThreshold.java Thu May 07 20:51:12 2015 -0700 @@ -70,6 +70,7 @@ runWithThresholds(10, 0, true); runWithThresholds(9, 8, true); runWithThresholds(-1, 8, true); + runWithThresholds(0, -1, true); runWithThresholds(8, -1, true); runWithThresholds(16, 8, true); runWithThresholds(8, 17, true); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/gc/arguments/TestSelectDefaultGC.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/gc/arguments/TestSelectDefaultGC.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test TestSelectDefaultGC + * @summary Test selection of GC when no GC option is specified + * @bug 8068582 + * @key gc + * @library /testlibrary + * @modules java.base/sun.misc + * java.management + * @run driver TestSelectDefaultGC + */ + +import com.oracle.java.testlibrary.*; +import java.util.regex.*; + +public class TestSelectDefaultGC { + public static boolean versionStringContains(OutputAnalyzer output, String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(output.getStderr()); + return matcher.find(); + } + + public static void assertVMOption(OutputAnalyzer output, String option, boolean value) { + output.shouldMatch(" " + option + " .*=.* " + value + " "); + } + + public static void main(String[] args) throws Exception { + // Start VM without specifying GC + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+PrintFlagsFinal", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + + boolean isServerVM = versionStringContains(output, "Server VM"); + + // Verify GC selection + assertVMOption(output, "UseParallelGC", isServerVM); + assertVMOption(output, "UseParallelOldGC", isServerVM); + assertVMOption(output, "UseSerialGC", !isServerVM); + assertVMOption(output, "UseConcMarkSweepGC", false); + assertVMOption(output, "UseG1GC", false); + assertVMOption(output, "UseParNewGC", false); + } +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/gc/arguments/TestUseCompressedOopsErgoTools.java --- a/hotspot/test/gc/arguments/TestUseCompressedOopsErgoTools.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/gc/arguments/TestUseCompressedOopsErgoTools.java Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 2013, 2015,Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,7 +21,6 @@ * questions. */ -import sun.management.ManagementFactoryHelper; import com.sun.management.HotSpotDiagnosticMXBean; import com.sun.management.VMOption; @@ -31,6 +30,7 @@ import java.util.Arrays; import com.oracle.java.testlibrary.*; +import java.lang.management.ManagementFactory; import sun.hotspot.WhiteBox; class DetermineMaxHeapForCompressedOops { @@ -43,7 +43,8 @@ class TestUseCompressedOopsErgoTools { private static long getCompressedClassSpaceSize() { - HotSpotDiagnosticMXBean diagnostic = ManagementFactoryHelper.getDiagnosticMXBean(); + HotSpotDiagnosticMXBean diagnostic = + ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class); VMOption option = diagnostic.getVMOption("CompressedClassSpaceSize"); return Long.parseLong(option.getValue()); @@ -174,4 +175,3 @@ return expect(flags, false, false, 0); } } - diff -r a4b1c7d6317a -r febd2373771c hotspot/test/gc/arguments/TestVerifyBeforeAndAfterGCFlags.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/gc/arguments/TestVerifyBeforeAndAfterGCFlags.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,119 @@ +/* +* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 only, as +* published by the Free Software Foundation. +* +* This code is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* version 2 for more details (a copy is included in the LICENSE file that +* accompanied this code). +* +* You should have received a copy of the GNU General Public License version +* 2 along with this work; if not, write to the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +* +* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +* or visit www.oracle.com if you need additional information or have any +* questions. +*/ + +/* + * @test TestVerifyBeforeAndAfterGCFlags + * @key gc + * @bug 8000831 + * @summary Runs an simple application (GarbageProducer) with various + combinations of -XX:{+|-}Verify{After|Before}GC flags and checks that + output contain or doesn't contain expected patterns + * @modules java.management + * @library /testlibrary + * @run driver TestVerifyBeforeAndAfterGCFlags + */ + +import java.util.ArrayList; +import java.util.Collections; + +import com.oracle.java.testlibrary.Utils; +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + +public class TestVerifyBeforeAndAfterGCFlags { + + // VerifyBeforeGC:[Verifying threads heap tenured eden syms strs zone dict metaspace chunks hand C-heap code cache ] + public static final String VERIFY_BEFORE_GC_PATTERN = "VerifyBeforeGC:\\[Verifying\\s+([^]\\s]+\\s+)+\\]"; + // VerifyBeforeGC: VerifyBeforeGC: VerifyBeforeGC: + public static final String VERIFY_BEFORE_GC_CORRUPTED_PATTERN = "VerifyBeforeGC:(?!\\[Verifying[^]]+\\])"; + + // VerifyAfterGC:[Verifying threads heap tenured eden syms strs zone dict metaspace chunks hand C-heap code cache ] + public static final String VERIFY_AFTER_GC_PATTERN = "VerifyAfterGC:\\[Verifying\\s+([^]\\s]+\\s+)+\\]"; + // VerifyAfterGC: VerifyAfterGC: VerifyAfterGC: + public static final String VERIFY_AFTER_GC_CORRUPTED_PATTERN = "VerifyAfterGC:(?!\\[Verifying[^]]+\\])"; + + public static void main(String args[]) throws Exception { + String[] filteredOpts = Utils.getFilteredTestJavaOpts( + new String[] { "-Xloggc:", + "-XX:+UseGCLogFileRotation", + "-XX:-DisplayVMOutput", + "VerifyBeforeGC", + "VerifyAfterGC" }); + testVerifyFlags(false, false, filteredOpts); + testVerifyFlags(true, true, filteredOpts); + testVerifyFlags(true, false, filteredOpts); + testVerifyFlags(false, true, filteredOpts); + } + + public static void testVerifyFlags(boolean verifyBeforeGC, + boolean verifyAfterGC, + String[] opts) throws Exception { + ArrayList vmOpts = new ArrayList<>(); + if (opts != null && (opts.length > 0)) { + Collections.addAll(vmOpts, opts); + } + + Collections.addAll(vmOpts, new String[] { + "-Xmx5m", + "-Xms5m", + "-Xmn3m", + "-XX:+UnlockDiagnosticVMOptions", + (verifyBeforeGC ? "-XX:+VerifyBeforeGC" + : "-XX:-VerifyBeforeGC"), + (verifyAfterGC ? "-XX:+VerifyAfterGC" + : "-XX:-VerifyAfterGC"), + GarbageProducer.class.getName() }); + ProcessBuilder procBuilder = + ProcessTools.createJavaProcessBuilder(vmOpts.toArray( + new String[vmOpts.size()])); + OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start()); + + analyzer.shouldHaveExitValue(0); + analyzer.shouldNotMatch(VERIFY_BEFORE_GC_CORRUPTED_PATTERN); + analyzer.shouldNotMatch(VERIFY_AFTER_GC_CORRUPTED_PATTERN); + + if (verifyBeforeGC) { + analyzer.shouldMatch(VERIFY_BEFORE_GC_PATTERN); + } else { + analyzer.shouldNotMatch(VERIFY_BEFORE_GC_PATTERN); + } + + if (verifyAfterGC) { + analyzer.shouldMatch(VERIFY_AFTER_GC_PATTERN); + } else { + analyzer.shouldNotMatch(VERIFY_AFTER_GC_PATTERN); + } + } + + public static class GarbageProducer { + static long[][] garbage = new long[10][]; + + public static void main(String args[]) { + int j = 0; + for(int i = 0; i<1000; i++) { + garbage[j] = new long[10000]; + j = (j+1)%garbage.length; + } + } + } +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/gc/g1/TestGCLogMessages.java --- a/hotspot/test/gc/g1/TestGCLogMessages.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/gc/g1/TestGCLogMessages.java Thu May 07 20:51:12 2015 -0700 @@ -66,7 +66,6 @@ new LogMessageWithLevel("SystemDictionary Roots", Level.FINEST), new LogMessageWithLevel("CLDG Roots", Level.FINEST), new LogMessageWithLevel("JVMTI Roots", Level.FINEST), - new LogMessageWithLevel("CodeCache Roots", Level.FINEST), new LogMessageWithLevel("SATB Filtering", Level.FINEST), new LogMessageWithLevel("CM RefProcessor Roots", Level.FINEST), new LogMessageWithLevel("Wait For Strong CLD", Level.FINEST), diff -r a4b1c7d6317a -r febd2373771c hotspot/test/gc/g1/TestGreyReclaimedHumongousObjects.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/gc/g1/TestGreyReclaimedHumongousObjects.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test TestGreyReclaimedHumongousObjects.java + * @bug 8069367 + * @requires vm.gc == "G1" | vm.gc == "null" + * @summary Test handling of marked but unscanned reclaimed humongous objects. + * @key gc + * @run main/othervm -XX:+UseG1GC -Xss32m -Xmx128m -XX:G1HeapRegionSize=1m + * -XX:+UnlockExperimentalVMOptions + * -XX:+G1EagerReclaimHumongousObjects + * -XX:+G1EagerReclaimHumongousObjectsWithStaleRefs + * TestGreyReclaimedHumongousObjects 1048576 90 + */ + +// This test spawns a bunch of threads, each of them rapidly +// allocating large objects and storing them into a circular buffer +// associated with the thread. The circular buffer results in these +// objects becoming dead in fairly short order. +// +// The situation we're trying to provoke is +// +// (1) A humongous object H is marked and added to the mark stack. +// +// (2) An evacuation pause determines H is no longer live, and +// reclaims it. This occurs before concurrent marking has gotten +// around to processing the mark stack entry for H. +// +// (3) Concurrent marking processes the mark stack entry for H. The +// bug is that it would attempt to scan the now dead object. +// +// Unfortunately, this test is *very* sensitive to configuration. +// Among the parameters that affect whether / how often we'll get into +// the desired situation within a reasonable amount of time are: +// +// - THREAD_COUNT: The number of allocating threads. +// +// - OLD_COUNT: The number of objects each thread keeps. +// +// - MAX_MEMORY: The maximum heap size. +// +// - G1HeapRegionSize +// +// - The size of the objects being allocated. +// +// The parameter values specified here: +// +// - THREAD_COUNT = 12 +// - OLD_COUNT == 4 +// - MAX_MEMORY == 128m +// - G1HeapRegionSize = 1m +// - Object size = 1048576 (2 regions after header overhead and roundup) +// +// seems to work well at provoking the desired state fairly quickly. +// Even relatively small perturbations may change that. The key +// factors seem to be keeping the heap mostly full of live objects but +// having them become dead fairly quickly. + +import java.util.Date; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import com.sun.management.HotSpotDiagnosticMXBean; +import java.lang.management.ManagementFactory; + +public class TestGreyReclaimedHumongousObjects { + + static class NamedThreadFactory implements ThreadFactory { + private int threadNum = 0; + + @Override + public Thread newThread(Runnable r) { + return new Thread(r, THREAD_NAME + (threadNum++)); + } + } + + static class Runner extends Thread { + private final Date startDate = new Date(); + private final int obj_size; + private final Object[] old_garbage; + private int old_index = 0; + + public Runner(int obj_size) { + this.obj_size = obj_size; + old_garbage = new Object[OLD_COUNT]; + } + + private void allocate_garbage() { + byte[] garbage = new byte[obj_size]; + old_garbage[Math.abs(++old_index % OLD_COUNT)] = garbage; + } + + @Override + public void run() { + try { + while (!isInterrupted()) { + allocate_garbage(); + Thread.sleep(0); // Yield, to ensure interruptable. + } + } catch (InterruptedException e) { + System.out.println("Aborted after " + + (new Date().getTime() - startDate.getTime()) + + " ms"); + interrupt(); + } + } + } + + public static void main(String[] args) throws Exception { + HotSpotDiagnosticMXBean diagnostic = + ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class); + + System.out.println("Max memory= " + MAX_MEMORY + " bytes"); + + int obj_size = 0; + long seconds_to_run = 0; + if (args.length != 2) { + throw new RuntimeException("Object size argument must be supplied"); + } else { + obj_size = Integer.parseInt(args[0]); + seconds_to_run = Integer.parseInt(args[1]); + } + System.out.println("Objects size= " + obj_size + " bytes"); + System.out.println("Seconds to run=" + seconds_to_run); + + int region_size = + Integer.parseInt(diagnostic.getVMOption("G1HeapRegionSize").getValue()); + if (obj_size < (region_size / 2)) { + throw new RuntimeException("Object size " + obj_size + + " is not humongous with region size " + region_size); + } + + ExecutorService executor = + Executors.newFixedThreadPool(THREAD_COUNT, new NamedThreadFactory()); + System.out.println("Starting " + THREAD_COUNT + " threads"); + + for (int i = 0; i < THREAD_COUNT; i++) { + executor.execute(new Runner(obj_size)); + } + + Thread.sleep(seconds_to_run * 1000); + executor.shutdownNow(); + + if (!executor.awaitTermination(10, TimeUnit.SECONDS)) { + System.err.println("Thread pool did not terminate after 10 seconds after shutdown"); + } + } + + private static final long MAX_MEMORY = Runtime.getRuntime().maxMemory(); + private static final int OLD_COUNT = 4; + private static final int THREAD_COUNT = 12; + private static final String THREAD_NAME = "TestGreyRH-"; +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/gc/g1/TestHumongousShrinkHeap.java --- a/hotspot/test/gc/g1/TestHumongousShrinkHeap.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/gc/g1/TestHumongousShrinkHeap.java Thu May 07 20:51:12 2015 -0700 @@ -34,11 +34,11 @@ * TestHumongousShrinkHeap */ +import com.sun.management.HotSpotDiagnosticMXBean; import java.lang.management.ManagementFactory; import java.lang.management.MemoryUsage; import java.util.ArrayList; import java.util.List; -import sun.management.ManagementFactoryHelper; import static com.oracle.java.testlibrary.Asserts.*; public class TestHumongousShrinkHeap { @@ -83,9 +83,11 @@ "committed free heap size is not less than committed full heap size, heap hasn't been shrunk?%n" + "%s = %s%n%s = %s", MIN_FREE_RATIO_FLAG_NAME, - ManagementFactoryHelper.getDiagnosticMXBean().getVMOption(MIN_FREE_RATIO_FLAG_NAME).getValue(), + ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class) + .getVMOption(MIN_FREE_RATIO_FLAG_NAME).getValue(), MAX_FREE_RATIO_FLAG_NAME, - ManagementFactoryHelper.getDiagnosticMXBean().getVMOption(MAX_FREE_RATIO_FLAG_NAME).getValue() + ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class) + .getVMOption(MAX_FREE_RATIO_FLAG_NAME).getValue() )); } diff -r a4b1c7d6317a -r febd2373771c hotspot/test/gc/g1/TestLargePageUseForAuxMemory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/gc/g1/TestLargePageUseForAuxMemory.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test TestLargePageUseForAuxMemory.java + * @bug 8058354 + * @ignore 8079208 + * @key gc + * @library /testlibrary /../../test/lib + * @requires (vm.gc=="G1" | vm.gc=="null") + * @build TestLargePageUseForAuxMemory + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @summary Test that auxiliary data structures are allocated using large pages if available. + * @run main/othervm -Xbootclasspath/a:. -XX:+UseG1GC -XX:+WhiteBoxAPI -XX:+IgnoreUnrecognizedVMOptions -XX:+UseLargePages TestLargePageUseForAuxMemory + */ + +import com.oracle.java.testlibrary.*; +import sun.hotspot.WhiteBox; + +public class TestLargePageUseForAuxMemory { + static final int HEAP_REGION_SIZE = 4 * 1024 * 1024; + static long largePageSize; + static long smallPageSize; + + static void checkSmallTables(OutputAnalyzer output, long expectedPageSize) throws Exception { + output.shouldContain("G1 'Block offset table': pg_sz=" + expectedPageSize); + output.shouldContain("G1 'Card counts table': pg_sz=" + expectedPageSize); + } + + static void checkBitmaps(OutputAnalyzer output, long expectedPageSize) throws Exception { + output.shouldContain("G1 'Prev Bitmap': pg_sz=" + expectedPageSize); + output.shouldContain("G1 'Next Bitmap': pg_sz=" + expectedPageSize); + } + + static void testVM(long heapsize, boolean cardsShouldUseLargePages, boolean bitmapShouldUseLargePages) throws Exception { + ProcessBuilder pb; + // Test with large page enabled. + pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-XX:G1HeapRegionSize=" + HEAP_REGION_SIZE, + "-Xms" + 10 * HEAP_REGION_SIZE, + "-Xmx" + heapsize, + "-XX:+TracePageSizes", + "-XX:+UseLargePages", + "-XX:+IgnoreUnrecognizedVMOptions", // there is on ObjectAlignmentInBytes in 32 bit builds + "-XX:ObjectAlignmentInBytes=8", + "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + checkSmallTables(output, (cardsShouldUseLargePages ? largePageSize : smallPageSize)); + checkBitmaps(output, (bitmapShouldUseLargePages ? largePageSize : smallPageSize)); + output.shouldHaveExitValue(0); + + // Test with large page disabled. + pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-XX:G1HeapRegionSize=" + HEAP_REGION_SIZE, + "-Xms" + 10 * HEAP_REGION_SIZE, + "-Xmx" + heapsize, + "-XX:+TracePageSizes", + "-XX:-UseLargePages", + "-XX:+IgnoreUnrecognizedVMOptions", // there is on ObjectAlignmentInBytes in 32 bit builds + "-XX:ObjectAlignmentInBytes=8", + "-version"); + + output = new OutputAnalyzer(pb.start()); + checkSmallTables(output, smallPageSize); + checkBitmaps(output, smallPageSize); + output.shouldHaveExitValue(0); + } + + public static void main(String[] args) throws Exception { + if (!Platform.isDebugBuild()) { + System.out.println("Skip tests on non-debug builds because the required option TracePageSizes is a debug-only option."); + return; + } + + WhiteBox wb = WhiteBox.getWhiteBox(); + smallPageSize = wb.getVMPageSize(); + largePageSize = wb.getVMLargePageSize(); + + if (largePageSize == 0) { + System.out.println("Skip tests because large page support does not seem to be available on this platform."); + return; + } + + // To get large pages for the card table etc. we need at least a 1G heap (with 4k page size). + // 32 bit systems will have problems reserving such an amount of contiguous space, so skip the + // test there. + if (!Platform.is32bit()) { + // Size that a single card covers. + final int cardSize = 512; + + final long heapSizeForCardTableUsingLargePages = largePageSize * cardSize; + + testVM(heapSizeForCardTableUsingLargePages, true, true); + testVM(heapSizeForCardTableUsingLargePages + HEAP_REGION_SIZE, true, true); + testVM(heapSizeForCardTableUsingLargePages - HEAP_REGION_SIZE, false, true); + } + + // Minimum heap requirement to get large pages for bitmaps is 128M heap. This seems okay to test + // everywhere. + final int bitmapTranslationFactor = 8 * 8; // ObjectAlignmentInBytes * BitsPerByte + final long heapSizeForBitmapUsingLargePages = largePageSize * bitmapTranslationFactor; + + testVM(heapSizeForBitmapUsingLargePages, false, true); + testVM(heapSizeForBitmapUsingLargePages + HEAP_REGION_SIZE, false, true); + testVM(heapSizeForBitmapUsingLargePages - HEAP_REGION_SIZE, false, false); + } +} + diff -r a4b1c7d6317a -r febd2373771c hotspot/test/gc/g1/TestShrinkDefragmentedHeap.java --- a/hotspot/test/gc/g1/TestShrinkDefragmentedHeap.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/gc/g1/TestShrinkDefragmentedHeap.java Thu May 07 20:51:12 2015 -0700 @@ -39,10 +39,10 @@ import java.lang.management.MemoryUsage; import java.util.ArrayList; import java.util.List; -import sun.management.ManagementFactoryHelper; import static com.oracle.java.testlibrary.Asserts.*; import com.oracle.java.testlibrary.ProcessTools; import com.oracle.java.testlibrary.OutputAnalyzer; +import com.sun.management.HotSpotDiagnosticMXBean; public class TestShrinkDefragmentedHeap { // Since we store all the small objects, they become old and old regions are also allocated at the bottom of the heap @@ -144,9 +144,11 @@ "committed free heap size is not less than committed full heap size, heap hasn't been shrunk?%n" + "%s = %s%n%s = %s", MIN_FREE_RATIO_FLAG_NAME, - ManagementFactoryHelper.getDiagnosticMXBean().getVMOption(MIN_FREE_RATIO_FLAG_NAME).getValue(), + ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class) + .getVMOption(MIN_FREE_RATIO_FLAG_NAME).getValue(), MAX_FREE_RATIO_FLAG_NAME, - ManagementFactoryHelper.getDiagnosticMXBean().getVMOption(MAX_FREE_RATIO_FLAG_NAME).getValue() + ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class) + .getVMOption(MAX_FREE_RATIO_FLAG_NAME).getValue() ); } diff -r a4b1c7d6317a -r febd2373771c hotspot/test/gc/g1/TestSummarizeRSetStatsTools.java --- a/hotspot/test/gc/g1/TestSummarizeRSetStatsTools.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/gc/g1/TestSummarizeRSetStatsTools.java Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,14 +25,11 @@ * Common helpers for TestSummarizeRSetStats* tests */ -import sun.management.ManagementFactoryHelper; import com.sun.management.HotSpotDiagnosticMXBean; import com.sun.management.VMOption; import com.oracle.java.testlibrary.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.lang.Thread; +import java.lang.management.ManagementFactory; import java.util.ArrayList; import java.util.Arrays; @@ -74,7 +71,8 @@ // the VM is currently run using G1GC, i.e. trying to test G1 functionality. public static boolean testingG1GC() { - HotSpotDiagnosticMXBean diagnostic = ManagementFactoryHelper.getDiagnosticMXBean(); + HotSpotDiagnosticMXBean diagnostic = + ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class); VMOption option = diagnostic.getVMOption("UseG1GC"); if (option.getValue().equals("false")) { @@ -150,4 +148,3 @@ } } } - diff -r a4b1c7d6317a -r febd2373771c hotspot/test/gc/parallelScavenge/TestDynShrinkHeap.java --- a/hotspot/test/gc/parallelScavenge/TestDynShrinkHeap.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/gc/parallelScavenge/TestDynShrinkHeap.java Thu May 07 20:51:12 2015 -0700 @@ -33,8 +33,8 @@ import java.lang.management.ManagementFactory; import java.lang.management.MemoryUsage; import java.util.ArrayList; -import sun.management.ManagementFactoryHelper; import static com.oracle.java.testlibrary.Asserts.assertLessThan; +import com.sun.management.HotSpotDiagnosticMXBean; public class TestDynShrinkHeap { @@ -63,9 +63,11 @@ "committed free heap size is not less than committed full heap size, heap hasn't been shrunk?%n" + "%s = %s%n%s = %s", MIN_FREE_RATIO_FLAG_NAME, - ManagementFactoryHelper.getDiagnosticMXBean().getVMOption(MIN_FREE_RATIO_FLAG_NAME).getValue(), + ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class) + .getVMOption(MIN_FREE_RATIO_FLAG_NAME).getValue(), MAX_FREE_RATIO_FLAG_NAME, - ManagementFactoryHelper.getDiagnosticMXBean().getVMOption(MAX_FREE_RATIO_FLAG_NAME).getValue() + ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class) + .getVMOption(MAX_FREE_RATIO_FLAG_NAME).getValue() )); } diff -r a4b1c7d6317a -r febd2373771c hotspot/test/gc/startup_warnings/TestParNewSerialOld.java --- a/hotspot/test/gc/startup_warnings/TestParNewSerialOld.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/gc/startup_warnings/TestParNewSerialOld.java Thu May 07 20:51:12 2015 -0700 @@ -40,7 +40,7 @@ public static void main(String args[]) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseParNewGC", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain("It is not possible to combine the ParNew young collector with the Serial old collector."); + output.shouldContain("It is not possible to combine the ParNew young collector with any collector other than CMS."); output.shouldContain("Error"); output.shouldHaveExitValue(1); } diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/CDSCompressedKPtrs/CDSCompressedKPtrs.java --- a/hotspot/test/runtime/CDSCompressedKPtrs/CDSCompressedKPtrs.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/CDSCompressedKPtrs/CDSCompressedKPtrs.java Thu May 07 20:51:12 2015 -0700 @@ -39,7 +39,7 @@ if (Platform.is64bit()) { pb = ProcessTools.createJavaProcessBuilder( "-XX:+UseCompressedClassPointers", "-XX:+UseCompressedOops", - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump"); + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./CDSCompressedKPtrs.jsa", "-Xshare:dump"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); try { output.shouldContain("Loading classes to share"); @@ -47,7 +47,7 @@ pb = ProcessTools.createJavaProcessBuilder( "-XX:+UseCompressedClassPointers", "-XX:+UseCompressedOops", - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:on", "-version"); + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./CDSCompressedKPtrs.jsa", "-Xshare:on", "-version"); output = new OutputAnalyzer(pb.start()); output.shouldContain("sharing"); output.shouldHaveExitValue(0); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/CDSCompressedKPtrs/CDSCompressedKPtrsError.java --- a/hotspot/test/runtime/CDSCompressedKPtrs/CDSCompressedKPtrsError.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/CDSCompressedKPtrs/CDSCompressedKPtrsError.java Thu May 07 20:51:12 2015 -0700 @@ -36,10 +36,12 @@ public class CDSCompressedKPtrsError { public static void main(String[] args) throws Exception { ProcessBuilder pb; + String filename = "./CDSCompressedKPtrsError.jsa"; + if (Platform.is64bit()) { pb = ProcessTools.createJavaProcessBuilder( "-XX:+UseCompressedOops", "-XX:+UseCompressedClassPointers", "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump"); + "-XX:SharedArchiveFile=" + filename, "-Xshare:dump"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); try { output.shouldContain("Loading classes to share"); @@ -47,21 +49,21 @@ pb = ProcessTools.createJavaProcessBuilder( "-XX:-UseCompressedClassPointers", "-XX:-UseCompressedOops", - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:on", "-version"); + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=" + filename, "-Xshare:on", "-version"); output = new OutputAnalyzer(pb.start()); output.shouldContain("Unable to use shared archive"); output.shouldHaveExitValue(0); pb = ProcessTools.createJavaProcessBuilder( "-XX:-UseCompressedClassPointers", "-XX:+UseCompressedOops", - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:on", "-version"); + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=" + filename, "-Xshare:on", "-version"); output = new OutputAnalyzer(pb.start()); output.shouldContain("Unable to use shared archive"); output.shouldHaveExitValue(0); pb = ProcessTools.createJavaProcessBuilder( "-XX:+UseCompressedClassPointers", "-XX:-UseCompressedOops", - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:on", "-version"); + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=" + filename, "-Xshare:on", "-version"); output = new OutputAnalyzer(pb.start()); output.shouldContain("Unable to use shared archive"); output.shouldHaveExitValue(0); @@ -74,19 +76,19 @@ // Test bad options with -Xshare:dump. pb = ProcessTools.createJavaProcessBuilder( "-XX:-UseCompressedOops", "-XX:+UseCompressedClassPointers", "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump"); + "-XX:SharedArchiveFile=./CDSCompressedKPtrsErrorBad1.jsa", "-Xshare:dump"); output = new OutputAnalyzer(pb.start()); output.shouldContain("Cannot dump shared archive"); pb = ProcessTools.createJavaProcessBuilder( "-XX:+UseCompressedOops", "-XX:-UseCompressedClassPointers", "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump"); + "-XX:SharedArchiveFile=./CDSCompressedKPtrsErrorBad2.jsa", "-Xshare:dump"); output = new OutputAnalyzer(pb.start()); output.shouldContain("Cannot dump shared archive"); pb = ProcessTools.createJavaProcessBuilder( "-XX:-UseCompressedOops", "-XX:-UseCompressedClassPointers", "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump"); + "-XX:SharedArchiveFile=./CDSCompressedKPtrsErrorBad3.jsa", "-Xshare:dump"); output = new OutputAnalyzer(pb.start()); output.shouldContain("Cannot dump shared archive"); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/CDSCompressedKPtrs/XShareAuto.java --- a/hotspot/test/runtime/CDSCompressedKPtrs/XShareAuto.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/CDSCompressedKPtrs/XShareAuto.java Thu May 07 20:51:12 2015 -0700 @@ -37,14 +37,14 @@ public static void main(String[] args) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-server", "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump"); + "-XX:SharedArchiveFile=./XShareAuto.jsa", "-Xshare:dump"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("Loading classes to share"); output.shouldHaveExitValue(0); pb = ProcessTools.createJavaProcessBuilder( "-server", "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=./sample.jsa", "-version"); + "-XX:SharedArchiveFile=./XShareAuto.jsa", "-version"); output = new OutputAnalyzer(pb.start()); // We asked for server but it could be aliased to something else if (output.getOutput().contains("Server VM")) { @@ -59,7 +59,7 @@ pb = ProcessTools.createJavaProcessBuilder( "-server", "-Xshare:auto", "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=./sample.jsa", "-XX:+PrintSharedSpaces", "-version"); + "-XX:SharedArchiveFile=./XShareAuto.jsa", "-XX:+PrintSharedSpaces", "-version"); output = new OutputAnalyzer(pb.start()); try { output.shouldContain("sharing"); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/CommandLine/ObsoleteFlagErrorMessage.java --- a/hotspot/test/runtime/CommandLine/ObsoleteFlagErrorMessage.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/CommandLine/ObsoleteFlagErrorMessage.java Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015 Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,24 +23,30 @@ /* * @test - * @bug 8060449 + * @bug 8060449 8073989 * @summary Newly obsolete command line options should still give useful error messages when used improperly. * @library /testlibrary - * @modules java.base/sun.misc - * java.management */ import com.oracle.java.testlibrary.*; public class ObsoleteFlagErrorMessage { public static void main(String[] args) throws Exception { + + // Case 1: Newly obsolete flags with extra junk appended should not be treated as newly obsolete (8060449) ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - "-XX:UseBoundThreadsPlusJunk", "-version"); + "-XX:UseOldInliningPlusJunk", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain("Unrecognized VM option 'UseBoundThreadsPlusJunk'"); // Must identify bad option. - output.shouldContain("UseBoundThreads"); // Should apply fuzzy matching to find correct option. - output.shouldContain("support").shouldContain("removed"); // Should warn user that the option they are trying to use is no longer supported. + output.shouldContain("Unrecognized VM option 'UseOldInliningPlusJunk'"); // Must identify bad option. output.shouldHaveExitValue(1); + + // Case 2: Newly obsolete integer-valued flags should be recognized as newly obsolete (8073989) + ProcessBuilder pb2 = ProcessTools.createJavaProcessBuilder( + "-XX:NmethodSweepFraction=10", "-version"); + + OutputAnalyzer output2 = new OutputAnalyzer(pb2.start()); + output2.shouldContain("ignoring option").shouldContain("support was removed"); + output2.shouldContain("NmethodSweepFraction"); } } diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/CommandLine/TestVMOptions.java --- a/hotspot/test/runtime/CommandLine/TestVMOptions.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/CommandLine/TestVMOptions.java Thu May 07 20:51:12 2015 -0700 @@ -46,7 +46,7 @@ pb = ProcessTools.createJavaProcessBuilder( "-XX:-PrintVMOptions", "-version"); output = new OutputAnalyzer(pb.start()); - output.shouldContain("java version"); + output.shouldMatch("(openjdk|java)\\sversion"); File dir = new File(System.getProperty("test.src", ".")); File file = new File(dir, "flagfile.txt"); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/CompressedOops/CompressedClassPointers.java --- a/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java Thu May 07 20:51:12 2015 -0700 @@ -97,7 +97,7 @@ // Test small heaps ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=./sample.jsa", + "-XX:SharedArchiveFile=./CompressedClassPointers.jsa", "-Xmx128m", "-XX:SharedBaseAddress=8g", "-XX:+PrintCompressedOopsMode", @@ -110,7 +110,7 @@ pb = ProcessTools.createJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=./sample.jsa", + "-XX:SharedArchiveFile=./CompressedClassPointers.jsa", "-Xmx128m", "-XX:SharedBaseAddress=8g", "-XX:+PrintCompressedOopsMode", diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/ErrorHandling/ProblematicFrameTest.java --- a/hotspot/test/runtime/ErrorHandling/ProblematicFrameTest.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/ErrorHandling/ProblematicFrameTest.java Thu May 07 20:51:12 2015 -0700 @@ -48,7 +48,7 @@ public static void main(String[] args) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - "-Xmx64m", "-XX:-TransmitErrorReport", "-XX:-CreateMinidumpOnCrash", Crasher.class.getName()); + "-Xmx64m", "-XX:-TransmitErrorReport", "-XX:-CreateCoredumpOnCrash", Crasher.class.getName()); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldNotMatch("error occurred during error reporting \\(printing problematic frame\\)"); } diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/ErrorHandling/SafeFetchInErrorHandlingTest.java --- a/hotspot/test/runtime/ErrorHandling/SafeFetchInErrorHandlingTest.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/ErrorHandling/SafeFetchInErrorHandlingTest.java Thu May 07 20:51:12 2015 -0700 @@ -1,3 +1,26 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -21,7 +44,7 @@ public static void main(String[] args) throws Exception { - if (!Platform.isDebugBuild()) { + if (!Platform.isDebugBuild() || Platform.isZero()) { return; } @@ -30,6 +53,7 @@ "-Xmx100M", "-XX:ErrorHandlerTest=14", "-XX:+TestSafeFetchInErrorHandler", + "-XX:-CreateCoredumpOnCrash", "-version"); OutputAnalyzer output_detail = new OutputAnalyzer(pb.start()); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/ErrorHandling/SecondaryErrorTest.java --- a/hotspot/test/runtime/ErrorHandling/SecondaryErrorTest.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/ErrorHandling/SecondaryErrorTest.java Thu May 07 20:51:12 2015 -0700 @@ -1,12 +1,26 @@ -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStreamReader; -import java.util.regex.Pattern; +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ -import com.oracle.java.testlibrary.OutputAnalyzer; -import com.oracle.java.testlibrary.Platform; -import com.oracle.java.testlibrary.ProcessTools; /* * @test @@ -18,6 +32,16 @@ * java.management */ +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.util.regex.Pattern; + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.Platform; +import com.oracle.java.testlibrary.ProcessTools; + public class SecondaryErrorTest { @@ -35,6 +59,7 @@ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", "-Xmx100M", + "-XX:-CreateCoredumpOnCrash", "-XX:ErrorHandlerTest=15", "-XX:TestCrashInErrorHandler=14", "-version"); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/NMT/JcmdDetailDiff.java --- a/hotspot/test/runtime/NMT/JcmdDetailDiff.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/NMT/JcmdDetailDiff.java Thu May 07 20:51:12 2015 -0700 @@ -28,7 +28,6 @@ * @library /testlibrary /../../test/lib * @modules java.base/sun.misc * java.management - * @ignore * @build JcmdDetailDiff * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail JcmdDetailDiff diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/NMT/NMTWithCDS.java --- a/hotspot/test/runtime/NMT/NMTWithCDS.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/NMT/NMTWithCDS.java Thu May 07 20:51:12 2015 -0700 @@ -37,14 +37,14 @@ public static void main(String[] args) throws Exception { ProcessBuilder pb; pb = ProcessTools.createJavaProcessBuilder( - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump"); + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./NMTWithCDS.jsa", "-Xshare:dump"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); try { output.shouldContain("Loading classes to share"); output.shouldHaveExitValue(0); pb = ProcessTools.createJavaProcessBuilder( - "-XX:+UnlockDiagnosticVMOptions", "-XX:NativeMemoryTracking=detail", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:on", "-version"); + "-XX:+UnlockDiagnosticVMOptions", "-XX:NativeMemoryTracking=detail", "-XX:SharedArchiveFile=./NMTWithCDS.jsa", "-Xshare:on", "-version"); output = new OutputAnalyzer(pb.start()); output.shouldContain("sharing"); output.shouldHaveExitValue(0); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/Safepoint/AssertSafepointCheckConsistency1.java --- a/hotspot/test/runtime/Safepoint/AssertSafepointCheckConsistency1.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/Safepoint/AssertSafepointCheckConsistency1.java Thu May 07 20:51:12 2015 -0700 @@ -49,7 +49,7 @@ "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", "-XX:-TransmitErrorReport", - "-XX:-CreateMinidumpOnCrash", + "-XX:-CreateCoredumpOnCrash", "-Xmx32m", "AssertSafepointCheckConsistency1", "test"); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/Safepoint/AssertSafepointCheckConsistency2.java --- a/hotspot/test/runtime/Safepoint/AssertSafepointCheckConsistency2.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/Safepoint/AssertSafepointCheckConsistency2.java Thu May 07 20:51:12 2015 -0700 @@ -49,7 +49,7 @@ "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", "-XX:-TransmitErrorReport", - "-XX:-CreateMinidumpOnCrash", + "-XX:-CreateCoredumpOnCrash", "-Xmx32m", "AssertSafepointCheckConsistency2", "test"); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/Safepoint/AssertSafepointCheckConsistency3.java --- a/hotspot/test/runtime/Safepoint/AssertSafepointCheckConsistency3.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/Safepoint/AssertSafepointCheckConsistency3.java Thu May 07 20:51:12 2015 -0700 @@ -49,7 +49,7 @@ "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", "-XX:-TransmitErrorReport", - "-XX:-CreateMinidumpOnCrash", + "-XX:-CreateCoredumpOnCrash", "-Xmx32m", "AssertSafepointCheckConsistency3", "test"); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/Safepoint/AssertSafepointCheckConsistency4.java --- a/hotspot/test/runtime/Safepoint/AssertSafepointCheckConsistency4.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/Safepoint/AssertSafepointCheckConsistency4.java Thu May 07 20:51:12 2015 -0700 @@ -49,7 +49,7 @@ "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", "-XX:-TransmitErrorReport", - "-XX:-CreateMinidumpOnCrash", + "-XX:-CreateCoredumpOnCrash", "-Xmx32m", "AssertSafepointCheckConsistency4", "test"); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/SharedArchiveFile/ArchiveDoesNotExist.java --- a/hotspot/test/runtime/SharedArchiveFile/ArchiveDoesNotExist.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/SharedArchiveFile/ArchiveDoesNotExist.java Thu May 07 20:51:12 2015 -0700 @@ -38,7 +38,7 @@ public class ArchiveDoesNotExist { public static void main(String[] args) throws Exception { - String fileName = "test.jsa"; + String fileName = "ArchiveDoesNotExist.jsa"; File cdsFile = new File(fileName); if (cdsFile.exists()) diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/SharedArchiveFile/CdsDifferentObjectAlignment.java --- a/hotspot/test/runtime/SharedArchiveFile/CdsDifferentObjectAlignment.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/SharedArchiveFile/CdsDifferentObjectAlignment.java Thu May 07 20:51:12 2015 -0700 @@ -59,10 +59,11 @@ createAlignment; String loadAlignmentArgument = "-XX:ObjectAlignmentInBytes=" + loadAlignment; + String filename = "./CdsDifferentObjectAlignment" + createAlignment + ".jsa"; ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=./sample.jsa", + "-XX:SharedArchiveFile=" + filename, "-Xshare:dump", createAlignmentArgument); @@ -72,7 +73,7 @@ pb = ProcessTools.createJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=./sample.jsa", + "-XX:SharedArchiveFile=" + filename, "-Xshare:on", loadAlignmentArgument, "-version"); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/SharedArchiveFile/CdsSameObjectAlignment.java --- a/hotspot/test/runtime/SharedArchiveFile/CdsSameObjectAlignment.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/SharedArchiveFile/CdsSameObjectAlignment.java Thu May 07 20:51:12 2015 -0700 @@ -55,10 +55,11 @@ System.out.println("dumpAndLoadSharedArchive(): objectAlignmentInBytes = " + objectAlignmentInBytes); + String filename = "./CdsSameObjectAlignment" + objectAlignmentInBytes + ".jsa"; // create shared archive ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=./sample.jsa", + "-XX:SharedArchiveFile=" + filename, "-Xshare:dump", objectAlignmentArg); @@ -70,7 +71,7 @@ // run using the shared archive pb = ProcessTools.createJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=./sample.jsa", + "-XX:SharedArchiveFile=" + filename, "-Xshare:on", objectAlignmentArg, "-version"); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/SharedArchiveFile/DefaultUseWithClient.java --- a/hotspot/test/runtime/SharedArchiveFile/DefaultUseWithClient.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/SharedArchiveFile/DefaultUseWithClient.java Thu May 07 20:51:12 2015 -0700 @@ -36,7 +36,7 @@ public class DefaultUseWithClient { public static void main(String[] args) throws Exception { - String fileName = "test.jsa"; + String fileName = "DefaultUseWithClient.jsa"; // On 32-bit windows CDS should be on by default in "-client" config // Skip this test on any other platform diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/SharedArchiveFile/LimitSharedSizes.java --- a/hotspot/test/runtime/SharedArchiveFile/LimitSharedSizes.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/SharedArchiveFile/LimitSharedSizes.java Thu May 07 20:51:12 2015 -0700 @@ -125,9 +125,11 @@ }; public static void main(String[] args) throws Exception { - String fileName = "test.jsa"; + int counter = 0; + for (SharedSizeTestData td : testTable) { + String fileName = "LimitSharedSizes" + counter + ".jsa"; + counter++; - for (SharedSizeTestData td : testTable) { String option = td.optionName + "=" + td.optionValue; System.out.println("testing option <" + option + ">"); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/SharedArchiveFile/PrintSharedArchiveAndExit.java --- a/hotspot/test/runtime/SharedArchiveFile/PrintSharedArchiveAndExit.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/SharedArchiveFile/PrintSharedArchiveAndExit.java Thu May 07 20:51:12 2015 -0700 @@ -34,8 +34,10 @@ public class PrintSharedArchiveAndExit { public static void main(String[] args) throws Exception { + String filename = "./PrintSharedArchiveAndExit.jsa"; + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump"); + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=" + filename, "-Xshare:dump"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); try { output.shouldContain("Loading classes to share"); @@ -43,7 +45,7 @@ // (1) With a valid archive pb = ProcessTools.createJavaProcessBuilder( - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=" + filename, "-XX:+PrintSharedArchiveAndExit", "-version"); output = new OutputAnalyzer(pb.start()); output.shouldContain("archive is valid"); @@ -51,7 +53,7 @@ output.shouldHaveExitValue(0); // Should report success in error code. pb = ProcessTools.createJavaProcessBuilder( - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=" + filename, "-XX:+PrintSharedArchiveAndExit"); output = new OutputAnalyzer(pb.start()); output.shouldContain("archive is valid"); @@ -61,7 +63,7 @@ // (2) With an invalid archive (boot class path has been prepended) pb = ProcessTools.createJavaProcessBuilder( "-Xbootclasspath/p:foo.jar", - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=" + filename, "-XX:+PrintSharedArchiveAndExit", "-version"); output = new OutputAnalyzer(pb.start()); output.shouldContain("archive is invalid"); @@ -70,7 +72,7 @@ pb = ProcessTools.createJavaProcessBuilder( "-Xbootclasspath/p:foo.jar", - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=" + filename, "-XX:+PrintSharedArchiveAndExit"); output = new OutputAnalyzer(pb.start()); output.shouldContain("archive is invalid"); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/SharedArchiveFile/SharedArchiveFile.java --- a/hotspot/test/runtime/SharedArchiveFile/SharedArchiveFile.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/SharedArchiveFile/SharedArchiveFile.java Thu May 07 20:51:12 2015 -0700 @@ -35,14 +35,14 @@ public class SharedArchiveFile { public static void main(String[] args) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump"); + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./SharedArchiveFile.jsa", "-Xshare:dump"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); try { output.shouldContain("Loading classes to share"); output.shouldHaveExitValue(0); pb = ProcessTools.createJavaProcessBuilder( - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:on", "-version"); + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./SharedArchiveFile.jsa", "-Xshare:on", "-version"); output = new OutputAnalyzer(pb.start()); output.shouldContain("sharing"); output.shouldHaveExitValue(0); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/SharedArchiveFile/SharedBaseAddress.java --- a/hotspot/test/runtime/SharedArchiveFile/SharedBaseAddress.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/SharedArchiveFile/SharedBaseAddress.java Thu May 07 20:51:12 2015 -0700 @@ -49,11 +49,12 @@ return; for (String testEntry : testTable) { + String filename = "SharedBaseAddress" + testEntry + ".jsa"; System.out.println("sharedBaseAddress = " + testEntry); ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=test.jsa", + "-XX:SharedArchiveFile=" + filename, "-XX:SharedBaseAddress=" + testEntry, "-Xshare:dump"); @@ -64,7 +65,7 @@ try { pb = ProcessTools.createJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=test.jsa", + "-XX:SharedArchiveFile=" + filename, "-Xshare:on", "-version"); output = new OutputAnalyzer(pb.start()); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/SharedArchiveFile/SharedSymbolTableBucketSize.java --- a/hotspot/test/runtime/SharedArchiveFile/SharedSymbolTableBucketSize.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/SharedArchiveFile/SharedSymbolTableBucketSize.java Thu May 07 20:51:12 2015 -0700 @@ -38,7 +38,7 @@ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-Xshare:dump", "-XX:+PrintSharedSpaces", "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=./sample.jsa", + "-XX:SharedArchiveFile=./SharedSymbolTableBucketSize.jsa", "-XX:SharedSymbolTableBucketSize=" + Integer.valueOf(bucket_size)); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("Loading classes to share"); @@ -60,7 +60,7 @@ pb = ProcessTools.createJavaProcessBuilder( "-Xshare:dump", "-XX:+PrintSharedSpaces", "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=./sample.jsa", + "-XX:SharedArchiveFile=./SharedSymbolTableBucketSize.jsa", input[i]); output = new OutputAnalyzer(pb.start()); output.shouldContain("Improperly specified VM option"); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/SharedArchiveFile/SpaceUtilizationCheck.java --- a/hotspot/test/runtime/SharedArchiveFile/SpaceUtilizationCheck.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/SharedArchiveFile/SpaceUtilizationCheck.java Thu May 07 20:51:12 2015 -0700 @@ -50,7 +50,7 @@ public static void main(String[] args) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=./test.jsa", + "-XX:SharedArchiveFile=./SpaceUtilizationCheck.jsa", "-Xshare:dump"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/StackGuardPages/invoke.c --- a/hotspot/test/runtime/StackGuardPages/invoke.c Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/StackGuardPages/invoke.c Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -221,7 +221,7 @@ printf("Test started with pid: %ld\n", (long) getpid()); options[0].optionString = "-Xint"; - options[1].optionString = "-Xss320k"; + options[1].optionString = "-Xss328k"; vm_args.version = JNI_VERSION_1_2; vm_args.ignoreUnrecognized = JNI_TRUE; diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/Unsafe/GetKlassPointerGetJavaMirror.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/Unsafe/GetKlassPointerGetJavaMirror.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8022853 + * @library /testlibrary + * @modules java.base/sun.misc + * @run main GetKlassPointerGetJavaMirror + */ + +import static com.oracle.java.testlibrary.Asserts.*; + +import com.oracle.java.testlibrary.*; +import sun.misc.Unsafe; + +public class GetKlassPointerGetJavaMirror { + + public static void main(String args[]) throws Exception { + Unsafe unsafe = Utils.getUnsafe(); + Object o = new GetKlassPointerGetJavaMirror(); + final long metaspaceKlass = unsafe.getKlassPointer(o); + Class c = unsafe.getJavaMirror(metaspaceKlass); + assertEquals(o.getClass(), c); + } + +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/Unsafe/GetUncompressedObject.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/Unsafe/GetUncompressedObject.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8022853 + * @library /testlibrary + * @modules java.base/sun.misc + * @run main GetUncompressedObject + */ + +import static com.oracle.java.testlibrary.Asserts.*; + +import com.oracle.java.testlibrary.*; +import sun.misc.Unsafe; + +public class GetUncompressedObject { + + public static void main(String args[]) throws Exception { + Unsafe unsafe = Utils.getUnsafe(); + + // Allocate some memory and fill it with non-zero values. + final int size = 32; + final long address = unsafe.allocateMemory(size); + unsafe.setMemory(address, size, (byte) 0x23); + + // The only thing we can do is check for null-ness. + // So, store a null somewhere. + unsafe.putAddress(address + 16, 0); + + Object nullObj = unsafe.getUncompressedObject(address + 16); + if (nullObj != null) { + throw new InternalError("should be null"); + } + } + +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/Unsafe/RangeCheck.java --- a/hotspot/test/runtime/Unsafe/RangeCheck.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/Unsafe/RangeCheck.java Thu May 07 20:51:12 2015 -0700 @@ -45,6 +45,7 @@ true, "-Xmx32m", "-XX:-TransmitErrorReport", + "-XX:-CreateCoredumpOnCrash", "-XX:-InlineUnsafeOps", // The compiler intrinsics doesn't have the assert DummyClassWithMainRangeCheck.class.getName()); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/handlerInTry/HandlerInTry.jasm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/handlerInTry/HandlerInTry.jasm Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * HandlerInTry contains a try block in a ctor whose handler is inside + * the same try block. The try block starts at line 74 (try t2;), ends at + * line 106 (endtry t2;), but its handler starts at line 101 (catch t2 #0;). + */ +super public class HandlerInTry + version 51:0 +{ + +public static final synthetic Field ___transactionFactory_2002349702336125:"Ljava/lang/Object;"; + +public Method "":"(Ljava/lang/Object;)V" + stack 5 locals 5 +{ + invokestatic Method ThreadLocalTransaction.getThreadLocalTransaction:"()Ljava/lang/Object;"; + checkcast class java/lang/Object; + astore_2; + aload_2; + invokestatic Method TransactionLogicDonor.isActiveTransaction:"(Ljava/lang/Object;)Z"; + ifeq L21; + aload_0; + aload_1; + aload_2; + invokespecial Method "":"(Ljava/lang/Object;Ljava/lang/Object;)V"; + return; + L21: stack_frame_type append; + locals_map class java/lang/Object; + aload_2; + getstatic Field ___transactionFactory_2002349702336125:"Ljava/lang/Object;"; + invokestatic Method TransactionLogicDonor.createTransaction:"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + astore_2; + aload_2; + iconst_1; + pop; + aload_2; + invokestatic Method ThreadLocalTransaction.setThreadLocalTransaction:"(Ljava/lang/Object;)V"; + try t0, t1; + aload_0; + aload_1; + aload_2; + invokespecial Method "":"(Ljava/lang/Object;Ljava/lang/Object;)V"; + aload_2; + pop; + aconst_null; + astore_2; + endtry t0, t1; + invokestatic Method ThreadLocalTransaction.clearThreadLocalTransaction:"()V"; + pop; + goto L107; + catch t0 java/lang/Throwable; + try t2; + stack_frame_type full; + locals_map bogus, class java/lang/Object, class java/lang/Object; + stack_map class java/lang/Throwable; + astore_3; + aload_2; + pop; + aload_3; + instanceof class ControlFlowError; + ifeq L82; + new class java/lang/NullPointerException; + dup; + invokespecial Method java/lang/NullPointerException."":"()V"; + athrow; + L82: stack_frame_type append; + locals_map class java/lang/Throwable; + aload_3; + instanceof class java/lang/Error; + ifeq L94; + aload_3; + checkcast class java/lang/Error; + athrow; + L94: stack_frame_type same; + aload_3; + checkcast class java/lang/Exception; + athrow; + catch t1 #0; + catch t2 #0; + stack_frame_type full; + locals_map bogus, class java/lang/Object, class java/lang/Object; + stack_map class java/lang/Throwable; + astore 4; + endtry t2; + invokestatic Method ThreadLocalTransaction.clearThreadLocalTransaction:"()V"; + aload 4; + athrow; + L107: stack_frame_type full; + locals_map class HandlerInTry, class java/lang/Object, null; + return; +} + +} // end Class HandlerInTry diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/handlerInTry/IsolatedHandlerInTry.jasm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/handlerInTry/IsolatedHandlerInTry.jasm Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * IsolatedHandlerInTry contains a try block in a ctor whose handler is inside + * the same try block but the handler can only be reached if an exception + * occurs. The handler does a return. So, a VerifyException should be thrown. + * The try block starts at line 77 (try t2;) and ends at line 113 (endtry t2;). + * Its handler starts at line 107 (catch t2 #0;). The handler can only be reached + * by exception because of the athrow at line 106. + */ +super public class IsolatedHandlerInTry + version 51:0 +{ + +public static final synthetic Field ___transactionFactory_2002349702336125:"Ljava/lang/Object;"; + +public Method "":"(Ljava/lang/Object;)V" + stack 5 locals 5 +{ + invokestatic Method ThreadLocalTransaction.getThreadLocalTransaction:"()Ljava/lang/Object;"; + checkcast class java/lang/Object; + astore_2; + aload_2; + invokestatic Method TransactionLogicDonor.isActiveTransaction:"(Ljava/lang/Object;)Z"; + ifeq L21; + aload_0; + aload_1; + aload_2; + invokespecial Method "":"(Ljava/lang/Object;Ljava/lang/Object;)V"; + return; + L21: stack_frame_type append; + locals_map class java/lang/Object; + aload_2; + getstatic Field ___transactionFactory_2002349702336125:"Ljava/lang/Object;"; + invokestatic Method TransactionLogicDonor.createTransaction:"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + astore_2; + aload_2; + iconst_1; + pop; + aload_2; + invokestatic Method ThreadLocalTransaction.setThreadLocalTransaction:"(Ljava/lang/Object;)V"; + try t0, t1; + aload_0; + aload_1; + aload_2; + invokespecial Method "":"(Ljava/lang/Object;Ljava/lang/Object;)V"; + aload_2; + pop; + aconst_null; + astore_2; + endtry t0, t1; + invokestatic Method ThreadLocalTransaction.clearThreadLocalTransaction:"()V"; + pop; + goto L107; + catch t0 java/lang/Throwable; + try t2; + stack_frame_type full; + locals_map bogus, class java/lang/Object, class java/lang/Object; + stack_map class java/lang/Throwable; + astore_3; + aload_2; + pop; + aload_3; + instanceof class ControlFlowError; + ifeq L82; + new class java/lang/NullPointerException; + dup; + invokespecial Method java/lang/NullPointerException."":"()V"; + athrow; + L82: stack_frame_type append; + locals_map class java/lang/Throwable; + aload_3; + instanceof class java/lang/Error; + ifeq L94; + aload_3; + checkcast class java/lang/Error; + athrow; + L94: stack_frame_type same; + aload_3; + checkcast class java/lang/Exception; + catch t1 #0; + stack_frame_type full; + locals_map bogus, class java/lang/Object, class java/lang/Object; + stack_map class java/lang/Throwable; + athrow; + catch t2 #0; + stack_frame_type full; + locals_map bogus, class java/lang/Object, class java/lang/Object; + stack_map class java/lang/Throwable; + astore 4; + return; + endtry t2; + stack_frame_type full; + locals_map bogus, class java/lang/Object, class java/lang/Object, class java/lang/Object; + stack_map class java/lang/Throwable; + invokestatic Method ThreadLocalTransaction.clearThreadLocalTransaction:"()V"; + athrow; + L107: stack_frame_type full; + locals_map class IsolatedHandlerInTry, class java/lang/Object, null; + return; +} + +} // end Class IsolatedHandlerInTry diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/handlerInTry/LoadHandlerInTry.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/handlerInTry/LoadHandlerInTry.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8075118 + * @summary Allow a ctor to call super() from a switch bytecode. + * @compile HandlerInTry.jasm + * @compile IsolatedHandlerInTry.jasm + * @run main/othervm -Xverify:all LoadHandlerInTry + */ + +/* + * This test has two cases: + * + * 1. class HandlerInTry: Class HandlerInTry contains a TRY block in a + * constructor whose handler is inside the same TRY block. The last + * few bytecodes and exception table look like this: + * + * ... + * 87: athrow + * 88: astore 4 + * 90: invokestatic #9 + * 93: aload 4 + * 95: athrow + * 96: return + * Exception table: + * from to target type + * 36 46 53 Class java/lang/Throwable + * 36 46 88 any + * 53 90 88 any + * + * Note that the target for the third handler in the Exception table is + * inside its TRY block. + * Without the fix for bug JDK-8075118, this test will time out. + * + * + * 2. class IsolatedHandlerInTry: Class IsolatedHandlerInTry also contains + * a TRY block in a constructoer whose handler is inside its TRY block. + * But the handler is only reachable if an exception is thrown. The + * handler's bytecodes will not get parsed as part of parsing the TRY + * block. They will only get parsed as a handler for the TRY block. + * Since the isolated handler does a 'return', a VerifyError exception + * should get thrown. + */ + +public class LoadHandlerInTry { + + public static void main(String[] args) throws Exception { + System.out.println("Regression test for bug 8075118"); + try { + Class newClass = Class.forName("HandlerInTry"); + } catch (Exception e) { + System.out.println("Failed: Exception was thrown: " + e.toString()); + throw e; + } + + try { + Class newClass = Class.forName("IsolatedHandlerInTry"); + throw new RuntimeException( + "Failed to throw VerifyError for IsolatedHandlerInTry"); + } catch (java.lang.VerifyError e) { + System.out.println("Passed: VerifyError exception was thrown"); + } + } +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/memory/ReadFromNoaccessArea.java --- a/hotspot/test/runtime/memory/ReadFromNoaccessArea.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/runtime/memory/ReadFromNoaccessArea.java Thu May 07 20:51:12 2015 -0700 @@ -50,6 +50,7 @@ "-XX:+WhiteBoxAPI", "-XX:+UseCompressedOops", "-XX:HeapBaseMinAddress=33G", + "-XX:-CreateCoredumpOnCrash", "-Xmx32m", DummyClassWithMainTryingToReadFromNoaccessArea.class.getName()); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/stackMapCheck/BadMap.jasm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/stackMapCheck/BadMap.jasm Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,152 @@ + /* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * This class should throw VerifyError because the StackMap for bytecode index + * 45 (astore_2, line 123) is incorrect. The stack maps for bytecode indexes 45 + * and 49 (astore, line 133) do not match because 45 does not supply enough + * locals to satisfy 49. + * + * The astore_2 bytecode at bytecode index 45 changes the type state, + * preventing the stackmap mismatch. But, if the incoming type state is used, + * as required by JVM Spec 8, then the verifier will detected the stackmap + * mismatch, and throw VerifyError. + */ + +super public class BadMap + version 51:0 +{ + + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + +public static Method main:"([Ljava/lang/String;)V" + throws java/lang/Throwable + stack 0 locals 1 +{ + return; +} + +public static Method foo:"()V" + stack 3 locals 5 +{ + iconst_0; + ifne L5; + nop; + try t7; + L5: stack_frame_type full; + aconst_null; + dup; + astore_0; + astore_1; + try t0; + aconst_null; + astore_0; + endtry t0; + goto L19; + catch t0 java/io/IOException; + stack_frame_type full; + locals_map class java/lang/Object, null; + stack_map class java/io/IOException; + astore_2; + aconst_null; + dup; + astore_1; + astore_0; + try t1; + L19: stack_frame_type full; + locals_map class java/lang/Object, class java/lang/Object; + aconst_null; + astore_2; + endtry t1; + aload_1; + ifnonnull L37; + nop; + goto L37; + catch t1 #0; + catch t2 #0; + try t2; + stack_frame_type full; + locals_map class java/lang/Object, class java/lang/Object; + stack_map class java/lang/Throwable; + astore_3; + endtry t2; + aload_1; + ifnonnull L35; + nop; + L35: stack_frame_type full; + locals_map class java/lang/Object, class java/lang/Object, bogus, class java/lang/Throwable; + aload_3; + athrow; + try t3, t4; + L37: stack_frame_type full; + locals_map class java/lang/Object, class java/lang/Object, class java/lang/Object; + aload_1; + ifnonnull L42; + nop; + endtry t3, t4; + L42: stack_frame_type full; + locals_map class java/lang/Object, class java/lang/Object, class java/lang/Object; + goto L54; + catch t3 java/lang/Exception; + try t5; + stack_frame_type full; + locals_map class java/lang/Object, class java/lang/Object; + stack_map class java/lang/Exception; + astore_2; // astore_2, at bci 45, that changes the type state. + endtry t5; + goto L54; + catch t4 #0; + catch t5 #0; + catch t6 #0; + try t6; + stack_frame_type full; + locals_map class java/lang/Object, class java/lang/Object, class java/lang/Object; + stack_map class java/lang/Throwable; + astore 4; + endtry t6; + aload 4; + athrow; + L54: stack_frame_type full; + locals_map class java/lang/Object, class java/lang/Object, class java/lang/Object; + goto L57; + L57: stack_frame_type full; + locals_map class java/lang/Object, class java/lang/Object, class java/lang/Object; + nop; + endtry t7; + return; + catch t7 #0; + stack_frame_type full; + stack_map class java/lang/Throwable; + nop; + athrow; +} + +} // end Class BadMap diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/stackMapCheck/BadMapDstore.jasm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/stackMapCheck/BadMapDstore.jasm Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,79 @@ + /* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * This class should throw VerifyError because the StackMap for bytecode index + * 9 (dstore_2, line 60) is incorrect. The stack maps for bytecode indexes 9 + * and 18 (astore_2, line 70) do not match because 9 does not supply enough + * locals to satisfy 18. + * + * The dstore_2 bytecode at bytecode index 9 changes the type state, + * preventing the stackmap mismatch. But, if the incoming type state is used, + * as required by JVM Spec 8, then the verifier will detected the stackmap + * mismatch, and throw VerifyError. + */ + +super public class BadMapDstore + version 51:0 +{ + +Field blah:I; + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + +public static Method main:"([Ljava/lang/String;)V" + stack 4 locals 4 +{ + new class BadMapDstore; + dup; + invokespecial Method "":"()V"; + astore_1; + dconst_1; + try t0; + dstore_2; + aload_1; + iconst_5; + putfield Field blah:"I"; + endtry t0; + goto L22; + catch t0 java/lang/Throwable; + stack_frame_type full; + locals_map class "[Ljava/lang/String;", class BadMapDstore, double; + stack_map class java/lang/Throwable; + astore_2; + aload_1; + dconst_0; + dstore_2; + pop; + L22: stack_frame_type same; + return; +} + +} // end Class BadMapDstore diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/stackMapCheck/BadMapIstore.jasm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/stackMapCheck/BadMapIstore.jasm Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,79 @@ + /* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * This class should throw VerifyError because the StackMap for bytecode index + * 9 (istore_2, line 60) is incorrect. The stack maps for bytecode indexes 9 + * and 18 (astore_2, line 70) do not match because 9 does not supply enough + * locals to satisfy 18. + * + * The istore_2 bytecode at bytecode index 9 changes the type state, + * preventing the stackmap mismatch. But, if the incoming type state is used, + * as required by JVM Spec 8, then the verifier will detected the stackmap + * mismatch, and throw VerifyError. + */ + +super public class BadMapIstore + version 51:0 +{ + +Field blah:I; + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + +public static Method main:"([Ljava/lang/String;)V" + stack 2 locals 3 +{ + new class BadMapIstore; + dup; + invokespecial Method "":"()V"; + astore_1; + iconst_2; + try t0; + istore_2; + aload_1; + iconst_5; + putfield Field blah:"I"; + endtry t0; + goto L22; + catch t0 java/lang/Throwable; + stack_frame_type full; + locals_map class "[Ljava/lang/String;", class BadMapIstore, int; + stack_map class java/lang/Throwable; + astore_2; + aload_1; + iconst_4; + istore_2; + pop; + L22: stack_frame_type same; + return; +} + +} // end Class BadMapIstore diff -r a4b1c7d6317a -r febd2373771c hotspot/test/runtime/stackMapCheck/StackMapCheck.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/stackMapCheck/StackMapCheck.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,63 @@ + /* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 7127066 + * @summary Class verifier accepts an invalid class file + * @compile BadMap.jasm + * @compile BadMapDstore.jasm + * @compile BadMapIstore.jasm + * @run main/othervm -Xverify:all StackMapCheck + */ + +public class StackMapCheck { + public static void main(String args[]) throws Throwable { + + System.out.println("Regression test for bug 7127066"); + try { + Class newClass = Class.forName("BadMap"); + throw new RuntimeException( + "StackMapCheck failed, BadMap did not throw VerifyError"); + } catch (java.lang.VerifyError e) { + System.out.println("BadMap passed, VerifyError was thrown"); + } + + try { + Class newClass = Class.forName("BadMapDstore"); + throw new RuntimeException( + "StackMapCheck failed, BadMapDstore did not throw VerifyError"); + } catch (java.lang.VerifyError e) { + System.out.println("BadMapDstore passed, VerifyError was thrown"); + } + + try { + Class newClass = Class.forName("BadMapIstore"); + throw new RuntimeException( + "StackMapCheck failed, BadMapIstore did not throw VerifyError"); + } catch (java.lang.VerifyError e) { + System.out.println("BadMapIstore passed, VerifyError was thrown"); + } + } +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/sanity/MismatchedWhiteBox/WhiteBox.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/sanity/MismatchedWhiteBox/WhiteBox.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test WhiteBox + * @bug 8011675 + * @summary verify that whitebox can be used even if not all functions are declared in java-part + * @author igor.ignatyev@oracle.com + * @library /testlibrary + * @compile WhiteBox.java + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI sun.hotspot.WhiteBox + */ + +package sun.hotspot; + +public class WhiteBox { + private static native void registerNatives(); + static { registerNatives(); } + public native int notExistedMethod(); + public native int getHeapOopSize(); + public static void main(String[] args) { + WhiteBox wb = new WhiteBox(); + if (wb.getHeapOopSize() < 0) { + throw new Error("wb.getHeapOopSize() < 0"); + } + boolean catched = false; + try { + wb.notExistedMethod(); + } catch (UnsatisfiedLinkError e) { + catched = true; + } + if (!catched) { + throw new Error("wb.notExistedMethod() was invoked"); + } + } +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/sanity/WhiteBox.java --- a/hotspot/test/sanity/WhiteBox.java Thu May 07 10:19:31 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test WhiteBox - * @bug 8011675 - * @summary verify that whitebox can be used even if not all functions are declared in java-part - * @author igor.ignatyev@oracle.com - * @library /testlibrary - * @compile WhiteBox.java - * @run main ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI sun.hotspot.WhiteBox - * @clean sun.hotspot.WhiteBox - */ - -package sun.hotspot; - -public class WhiteBox { - private static native void registerNatives(); - static { registerNatives(); } - public native int notExistedMethod(); - public native int getHeapOopSize(); - public static void main(String[] args) { - WhiteBox wb = new WhiteBox(); - if (wb.getHeapOopSize() < 0) { - throw new Error("wb.getHeapOopSize() < 0"); - } - boolean catched = false; - try { - wb.notExistedMethod(); - } catch (UnsatisfiedLinkError e) { - catched = true; - } - if (!catched) { - throw new Error("wb.notExistedMethod() was invoked"); - } - } -} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/serviceability/attach/AttachWithStalePidFile.java --- a/hotspot/test/serviceability/attach/AttachWithStalePidFile.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/serviceability/attach/AttachWithStalePidFile.java Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ * @bug 7162400 * @key regression * @summary Regression test for attach issue where stale pid files in /tmp lead to connection issues - * @ignore 8024055 * @library /testlibrary * @build com.oracle.java.testlibrary.* AttachWithStalePidFileTarget * @run main AttachWithStalePidFile @@ -79,9 +78,7 @@ // wait for vm.paused file to be created and delete it once we find it. waitForAndResumeVM(pid); - // unfortunately there's no reliable way to know the VM is ready to receive the - // attach request so we have to do an arbitrary sleep. - Thread.sleep(5000); + waitForTargetReady(target); HotSpotVirtualMachine vm = (HotSpotVirtualMachine)VirtualMachine.attach(((Integer)pid).toString()); BufferedReader remoteDataReader = new BufferedReader(new InputStreamReader(vm.remoteDataDump())); @@ -101,6 +98,16 @@ } } + private static void waitForTargetReady(Process target) throws IOException { + BufferedReader br = new BufferedReader(new InputStreamReader(target.getInputStream())); + String line = br.readLine(); + // wait for the ready message having been printed or EOF (line == null) + while (line != null && !line.equals(AttachWithStalePidFileTarget.READY_MSG)) { + line = br.readLine(); + } + // target VM ready + } + private static Path createJavaPidFile(int pid) throws Exception { Path pidFile = Paths.get("/tmp/.java_pid" + pid); if(Files.exists(pidFile)) { @@ -108,8 +115,10 @@ Files.delete(pidFile); } catch(FileSystemException e) { - if(e.getReason().equals("Operation not permitted")) { + if(e.getReason().matches("Operation not permitted|Not owner")) { System.out.println("Unable to remove exisiting stale PID file" + pidFile); + System.out.println("==================================================="); + e.printStackTrace(System.out); return null; } throw e; diff -r a4b1c7d6317a -r febd2373771c hotspot/test/serviceability/attach/AttachWithStalePidFileTarget.java --- a/hotspot/test/serviceability/attach/AttachWithStalePidFileTarget.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/serviceability/attach/AttachWithStalePidFileTarget.java Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,7 +21,10 @@ * questions. */ public class AttachWithStalePidFileTarget { + static final String READY_MSG = "*ready*"; public static void main(String... args) throws Exception { - Thread.sleep(2*60*1000); + System.out.println(READY_MSG); + System.out.flush(); + System.in.read(); } } diff -r a4b1c7d6317a -r febd2373771c hotspot/test/serviceability/dcmd/jvmti/DataDumpDcmdTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/dcmd/jvmti/DataDumpDcmdTest.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.dcmd.CommandExecutor; +import com.oracle.java.testlibrary.dcmd.JMXExecutor; +import com.oracle.java.testlibrary.dcmd.PidJcmdExecutor; +import org.testng.annotations.Test; + +/* + * @test + * @bug 8054890 + * @summary Test of JVMTI.data_dump diagnostic command + * @library /testlibrary + * @build com.oracle.java.testlibrary.* + * @run testng DataDumpDcmdTest + */ + +/** + * This test issues the "JVMTI.data_dump" command which will dump the related JVMTI + * data. + * + */ +public class DataDumpDcmdTest { + public void run(CommandExecutor executor) { + OutputAnalyzer output = executor.execute("JVMTI.data_dump"); + + output.stderrShouldBeEmpty(); + } + + @Test + public void jmx() throws Throwable { + run(new JMXExecutor()); + } + + @Test + public void cli() throws Throwable { + run(new PidJcmdExecutor()); + } +} \ No newline at end of file diff -r a4b1c7d6317a -r febd2373771c hotspot/test/serviceability/dcmd/vm/SetVMFlagTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/dcmd/vm/SetVMFlagTest.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.dcmd.CommandExecutor; +import com.oracle.java.testlibrary.dcmd.JMXExecutor; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +/* + * @test + * @bug 8054890 + * @summary Test of VM.set_flag diagnostic command + * @library /testlibrary + * @build com.oracle.java.testlibrary.* + * @build com.oracle.java.testlibrary.dcmd.* + * @run testng SetVMFlagTest + */ + +public class SetVMFlagTest { + private static final String MANAGEABLE_PATTERN = "\\s*bool\\s+(\\S+)\\s+[\\:]?=\\s+" + + "(.*?)\\s+\\{manageable\\}"; + private static final String IMMUTABLE_PATTERN = "\\s*uintx\\s+(\\S+)\\s+[\\:]?=\\s+" + + "(.*?)\\s+\\{product\\}"; + + public void run(CommandExecutor executor) { + setMutableFlag(executor); + setMutableFlagWithInvalidValue(executor); + setImmutableFlag(executor); + setNonExistingFlag(executor); + } + + @Test + public void jmx() { + run(new JMXExecutor()); + } + + private void setMutableFlag(CommandExecutor executor) { + OutputAnalyzer out = getAllFlags(executor); + String flagName = out.firstMatch(MANAGEABLE_PATTERN, 1); + String flagVal = out.firstMatch(MANAGEABLE_PATTERN, 2); + + System.out.println("### Setting a mutable flag '" + flagName + "'"); + + if (flagVal == null) { + System.err.println(out.getOutput()); + throw new Error("Can not find a boolean manageable flag"); + } + + Boolean blnVal = Boolean.parseBoolean(flagVal); + + out = executor.execute("VM.set_flag " + flagName + " " + (blnVal ? 0 : 1)); + out.stderrShouldBeEmpty(); + + out = getAllFlags(executor); + + String newFlagVal = out.firstMatch(MANAGEABLE_PATTERN.replace("(\\S+)", flagName), 1); + + assertNotEquals(newFlagVal, flagVal); + } + + private void setMutableFlagWithInvalidValue(CommandExecutor executor) { + OutputAnalyzer out = getAllFlags(executor); + String flagName = out.firstMatch(MANAGEABLE_PATTERN, 1); + String flagVal = out.firstMatch(MANAGEABLE_PATTERN, 2); + + System.out.println("### Setting a mutable flag '" + flagName + "' to an invalid value"); + + if (flagVal == null) { + System.err.println(out.getOutput()); + throw new Error("Can not find a boolean manageable flag"); + } + + // a boolean flag accepts only 0/1 as its value + out = executor.execute("VM.set_flag " + flagName + " unexpected_value"); + out.stderrShouldBeEmpty(); + out.stdoutShouldContain("flag value must be a boolean (1 or 0)"); + + out = getAllFlags(executor); + + String newFlagVal = out.firstMatch(MANAGEABLE_PATTERN.replace("(\\S+)", flagName), 1); + + assertEquals(newFlagVal, flagVal); + } + + private void setImmutableFlag(CommandExecutor executor) { + OutputAnalyzer out = getAllFlags(executor); + String flagName = out.firstMatch(IMMUTABLE_PATTERN, 1); + String flagVal = out.firstMatch(IMMUTABLE_PATTERN, 2); + + System.out.println("### Setting an immutable flag '" + flagName + "'"); + + if (flagVal == null) { + System.err.println(out.getOutput()); + throw new Error("Can not find an immutable uintx flag"); + } + + Long numVal = Long.parseLong(flagVal); + + out = executor.execute("VM.set_flag " + flagName + " " + (numVal + 1)); + out.stderrShouldBeEmpty(); + out.stdoutShouldContain("only 'writeable' flags can be set"); + + out = getAllFlags(executor); + + String newFlagVal = out.firstMatch(IMMUTABLE_PATTERN.replace("(\\S+)", flagName), 1); + + assertEquals(newFlagVal, flagVal); + } + + private void setNonExistingFlag(CommandExecutor executor) { + String unknownFlag = "ThisIsUnknownFlag"; + System.out.println("### Setting a non-existing flag '" + unknownFlag + "'"); + OutputAnalyzer out = executor.execute("VM.set_flag " + unknownFlag + " 1"); + out.stderrShouldBeEmpty(); + out.stdoutShouldContain("flag " + unknownFlag + " does not exist"); + } + + private OutputAnalyzer getAllFlags(CommandExecutor executor) { + return executor.execute("VM.flags -all", true); + } +} \ No newline at end of file diff -r a4b1c7d6317a -r febd2373771c hotspot/test/serviceability/hprof/cpu002.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/hprof/cpu002.java Thu May 07 20:51:12 2015 -0700 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8076421 + * @summary Test of hprof option crashes Zero + * @compile cpu002.java + * @run main/othervm -Xrunhprof:cpu=times,file=cpu002.hprof.out cpu002 + */ + +import java.io.*; + +public class cpu002 { + public static final int PASSED = 0; + public static final int FAILED = 2; + public static final int JCK_STATUS_BASE = 95; + + public static void main (String argv[]) { + System.exit(run(argv,System.out) + JCK_STATUS_BASE); + } + + public static int run(String argv[], PrintStream out) { + return PASSED; + } +} diff -r a4b1c7d6317a -r febd2373771c hotspot/test/serviceability/sa/jmap-hashcode/Test8028623.java --- a/hotspot/test/serviceability/sa/jmap-hashcode/Test8028623.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/serviceability/sa/jmap-hashcode/Test8028623.java Thu May 07 20:51:12 2015 -0700 @@ -30,7 +30,6 @@ * java.compiler * java.management * jdk.jvmstat/sun.jvmstat.monitor - * @ignore 8044416 * @build com.oracle.java.testlibrary.* * @compile -encoding utf8 Test8028623.java * @run main Test8028623 diff -r a4b1c7d6317a -r febd2373771c hotspot/test/serviceability/threads/TestFalseDeadLock.java --- a/hotspot/test/serviceability/threads/TestFalseDeadLock.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/serviceability/threads/TestFalseDeadLock.java Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ /* * @test - * @ignore 8061157 * @bug 8016304 * @summary Make sure no deadlock is reported for this program which has no deadlocks. * @library /testlibrary diff -r a4b1c7d6317a -r febd2373771c hotspot/test/testlibrary/com/oracle/java/testlibrary/Platform.java --- a/hotspot/test/testlibrary/com/oracle/java/testlibrary/Platform.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Platform.java Thu May 07 20:51:12 2015 -0700 @@ -48,6 +48,10 @@ return vmName.endsWith(" Graal VM"); } + public static boolean isZero() { + return vmName.endsWith(" Zero VM"); + } + public static boolean isMinimal() { return vmName.endsWith(" Minimal VM"); } diff -r a4b1c7d6317a -r febd2373771c hotspot/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java --- a/hotspot/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java Thu May 07 20:51:12 2015 -0700 @@ -139,6 +139,9 @@ args.add(javapath); Collections.addAll(args, getPlatformSpecificVMArgs()); + args.add("-cp"); + args.add(System.getProperty("java.class.path")); + if (addTestVmAndJavaOptions) { Collections.addAll(args, Utils.getTestJavaOpts()); } diff -r a4b1c7d6317a -r febd2373771c hotspot/test/testlibrary/com/oracle/java/testlibrary/dcmd/CommandExecutor.java --- a/hotspot/test/testlibrary/com/oracle/java/testlibrary/dcmd/CommandExecutor.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/dcmd/CommandExecutor.java Thu May 07 20:51:12 2015 -0700 @@ -40,16 +40,34 @@ * stderr, regardless of the specific executor used. */ public final OutputAnalyzer execute(String cmd) throws CommandExecutorException { - System.out.printf("Running DCMD '%s' through '%s'%n", cmd, this.getClass().getSimpleName()); + return execute(cmd, false); + } + + /** + * Execute a diagnostic command + * + * @param cmd The diagnostic command to execute + * @param silent Do not print the command output + * @return an {@link jdk.testlibrary.OutputAnalyzer} encapsulating the output of the command + * @throws CommandExecutorException if there is an exception on the "calling side" while trying to execute the + * Diagnostic Command. Exceptions thrown on the remote side are available as textual representations in + * stderr, regardless of the specific executor used. + */ + public final OutputAnalyzer execute(String cmd, boolean silent) throws CommandExecutorException { + if (!silent) { + System.out.printf("Running DCMD '%s' through '%s'%n", cmd, this.getClass().getSimpleName()); + } + OutputAnalyzer oa = executeImpl(cmd); - System.out.println("---------------- stdout ----------------"); - System.out.println(oa.getStdout()); - System.out.println("---------------- stderr ----------------"); - System.out.println(oa.getStderr()); - System.out.println("----------------------------------------"); - System.out.println(); - + if (!silent) { + System.out.println("---------------- stdout ----------------"); + System.out.println(oa.getStdout()); + System.out.println("---------------- stderr ----------------"); + System.out.println(oa.getStderr()); + System.out.println("----------------------------------------"); + System.out.println(); + } return oa; } diff -r a4b1c7d6317a -r febd2373771c hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java --- a/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java Thu May 07 20:51:12 2015 -0700 @@ -48,7 +48,7 @@ ARCH("isARM", "isPPC", "isSparc", "isX86", "isX64"), BITNESS("is32bit", "is64bit"), OS("isAix", "isLinux", "isOSX", "isSolaris", "isWindows"), - VM_TYPE("isClient", "isServer", "isGraal", "isMinimal"), + VM_TYPE("isClient", "isServer", "isGraal", "isMinimal", "isZero"), IGNORED("isEmbedded", "isDebugBuild", "shouldSAAttach", "canPtraceAttachLinux", "canAttachOSX", "isTieredSupported"); diff -r a4b1c7d6317a -r febd2373771c hotspot/test/testlibrary_tests/whitebox/vm_flags/VmFlagTest.java --- a/hotspot/test/testlibrary_tests/whitebox/vm_flags/VmFlagTest.java Thu May 07 10:19:31 2015 -0700 +++ b/hotspot/test/testlibrary_tests/whitebox/vm_flags/VmFlagTest.java Thu May 07 20:51:12 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,13 +21,13 @@ * questions. */ -import java.util.Objects; import java.util.function.BiConsumer; import java.util.function.Function; import sun.hotspot.WhiteBox; import sun.management.*; import com.sun.management.*; import com.oracle.java.testlibrary.*; +import java.lang.management.ManagementFactory; public final class VmFlagTest { public static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); @@ -96,7 +96,7 @@ return asString(getValue()); } HotSpotDiagnosticMXBean diagnostic - = ManagementFactoryHelper.getDiagnosticMXBean(); + = ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class); VMOption tmp; try { tmp = diagnostic.getVMOption(flagName);