Mercurial > hg > shark > hotspot
changeset 2510:d97b47ea5dbd
Merge
author | Gary Benson <gbenson@redhat.com> |
---|---|
date | Fri, 01 Apr 2011 11:06:30 +0100 |
parents | 633f6a61a117 (current diff) 8010c8c623ac (diff) |
children | 3747a10c6e1f |
files | src/cpu/zero/vm/cppInterpreter_zero.cpp src/share/vm/compiler/compileBroker.cpp src/share/vm/interpreter/bytecodeInterpreter.cpp src/share/vm/interpreter/interpreterRuntime.cpp test/compiler/6987555/Test6987555.java test/compiler/6991596/Test6991596.java |
diffstat | 220 files changed, 4000 insertions(+), 3242 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Fri Apr 01 10:58:10 2011 +0100 +++ b/.hgtags Fri Apr 01 11:06:30 2011 +0100 @@ -153,3 +153,6 @@ e9aa2ca89ad6c53420623d579765f9706ec523d7 hs21-b02 0e531ab5ba04967a0e9aa6aef65e6eb3a0dcf632 jdk7-b132 a8d643a4db47c7b58e0bcb49c77b5c3610de86a8 hs21-b03 +1b3a350709e4325d759bb453ff3fb6a463270488 jdk7-b133 +447e6faab4a8755d4860c2366630729dbaec111c jdk7-b134 +3c76374706ea8a77e15aec8310e831e5734f8775 hs21-b04
--- a/agent/src/share/classes/sun/jvm/hotspot/jdi/ClassObjectReferenceImpl.java Fri Apr 01 10:58:10 2011 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/jdi/ClassObjectReferenceImpl.java Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2011, 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 @@ import com.sun.jdi.*; import sun.jvm.hotspot.oops.Instance; import sun.jvm.hotspot.oops.Klass; -import sun.jvm.hotspot.oops.OopUtilities; +import sun.jvm.hotspot.oops.java_lang_Class; public class ClassObjectReferenceImpl extends ObjectReferenceImpl implements ClassObjectReference { @@ -39,7 +39,7 @@ public ReferenceType reflectedType() { if (reflectedType == null) { - Klass k = OopUtilities.classOopToKlass(ref()); + Klass k = java_lang_Class.asKlass(ref()); reflectedType = vm.referenceType(k); } return reflectedType;
--- a/agent/src/share/classes/sun/jvm/hotspot/jdi/FieldImpl.java Fri Apr 01 10:58:10 2011 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/jdi/FieldImpl.java Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2011, 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 @@ // get the value of static field ValueImpl getValue() { - return getValue(saField.getFieldHolder()); + return getValue(saField.getFieldHolder().getJavaMirror()); } // get the value of this Field from a specific Oop
--- a/agent/src/share/classes/sun/jvm/hotspot/memory/StringTable.java Fri Apr 01 10:58:10 2011 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/memory/StringTable.java Fri Apr 01 11:06:30 2011 +0100 @@ -44,12 +44,10 @@ private static synchronized void initialize(TypeDataBase db) { Type type = db.lookupType("StringTable"); theTableField = type.getAddressField("_the_table"); - stringTableSize = db.lookupIntConstant("StringTable::string_table_size").intValue(); } // Fields private static AddressField theTableField; - private static int stringTableSize; // Accessors public static StringTable getTheTable() { @@ -57,10 +55,6 @@ return (StringTable) VMObjectFactory.newObject(StringTable.class, tmp); } - public static int getStringTableSize() { - return stringTableSize; - } - public StringTable(Address addr) { super(addr); }
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/Instance.java Fri Apr 01 10:58:10 2011 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/Instance.java Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, 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 @@ -64,7 +64,7 @@ public void iterateFields(OopVisitor visitor, boolean doVMFields) { super.iterateFields(visitor, doVMFields); - ((InstanceKlass) getKlass()).iterateNonStaticFields(visitor); + ((InstanceKlass) getKlass()).iterateNonStaticFields(visitor, this); } public void printValueOn(PrintStream tty) {
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java Fri Apr 01 10:58:10 2011 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, 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 @@ -87,7 +87,7 @@ innerClasses = new OopField(type.getOopField("_inner_classes"), Oop.getHeaderSize()); nonstaticFieldSize = new CIntField(type.getCIntegerField("_nonstatic_field_size"), Oop.getHeaderSize()); staticFieldSize = new CIntField(type.getCIntegerField("_static_field_size"), Oop.getHeaderSize()); - staticOopFieldSize = new CIntField(type.getCIntegerField("_static_oop_field_size"), Oop.getHeaderSize()); + staticOopFieldCount = new CIntField(type.getCIntegerField("_static_oop_field_count"), Oop.getHeaderSize()); nonstaticOopMapSize = new CIntField(type.getCIntegerField("_nonstatic_oop_map_size"), Oop.getHeaderSize()); isMarkedDependent = new CIntField(type.getCIntegerField("_is_marked_dependent"), Oop.getHeaderSize()); initState = new CIntField(type.getCIntegerField("_init_state"), Oop.getHeaderSize()); @@ -140,7 +140,7 @@ private static OopField innerClasses; private static CIntField nonstaticFieldSize; private static CIntField staticFieldSize; - private static CIntField staticOopFieldSize; + private static CIntField staticOopFieldCount; private static CIntField nonstaticOopMapSize; private static CIntField isMarkedDependent; private static CIntField initState; @@ -241,6 +241,10 @@ // Byteside of the header private static long headerSize; + public long getObjectSize(Oop object) { + return getSizeHelper() * VM.getVM().getAddressSize(); + } + public static long getHeaderSize() { return headerSize; } // Accessors for declared fields @@ -261,8 +265,7 @@ public Symbol getSourceDebugExtension(){ return getSymbol(sourceDebugExtension); } public TypeArray getInnerClasses() { return (TypeArray) innerClasses.getValue(this); } public long getNonstaticFieldSize() { return nonstaticFieldSize.getValue(this); } - public long getStaticFieldSize() { return staticFieldSize.getValue(this); } - public long getStaticOopFieldSize() { return staticOopFieldSize.getValue(this); } + public long getStaticOopFieldCount() { return staticOopFieldCount.getValue(this); } public long getNonstaticOopMapSize() { return nonstaticOopMapSize.getValue(this); } public boolean getIsMarkedDependent() { return isMarkedDependent.getValue(this) != 0; } public long getVtableLen() { return vtableLen.getValue(this); } @@ -453,14 +456,29 @@ visitor.doOop(innerClasses, true); visitor.doCInt(nonstaticFieldSize, true); visitor.doCInt(staticFieldSize, true); - visitor.doCInt(staticOopFieldSize, true); + visitor.doCInt(staticOopFieldCount, true); visitor.doCInt(nonstaticOopMapSize, true); visitor.doCInt(isMarkedDependent, true); visitor.doCInt(initState, true); visitor.doCInt(vtableLen, true); visitor.doCInt(itableLen, true); } + } + /* + * Visit the static fields of this InstanceKlass with the obj of + * the visitor set to the oop holding the fields, which is + * currently the java mirror. + */ + public void iterateStaticFields(OopVisitor visitor) { + visitor.setObj(getJavaMirror()); + visitor.prologue(); + iterateStaticFieldsInternal(visitor); + visitor.epilogue(); + + } + + void iterateStaticFieldsInternal(OopVisitor visitor) { TypeArray fields = getFields(); int length = (int) fields.getLength(); for (int index = 0; index < length; index += NEXT_OFFSET) { @@ -478,9 +496,9 @@ return getSuper(); } - public void iterateNonStaticFields(OopVisitor visitor) { + public void iterateNonStaticFields(OopVisitor visitor, Oop obj) { if (getSuper() != null) { - ((InstanceKlass) getSuper()).iterateNonStaticFields(visitor); + ((InstanceKlass) getSuper()).iterateNonStaticFields(visitor, obj); } TypeArray fields = getFields(); @@ -692,7 +710,7 @@ public long getObjectSize() { long bodySize = alignObjectOffset(getVtableLen() * getHeap().getOopSize()) + alignObjectOffset(getItableLen() * getHeap().getOopSize()) - + (getStaticFieldSize() + getNonstaticOopMapSize()) * getHeap().getOopSize(); + + (getNonstaticOopMapSize()) * getHeap().getOopSize(); return alignObjectSize(headerSize + bodySize); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceMirrorKlass.java Fri Apr 01 11:06:30 2011 +0100 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2011, 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.oops; + +import java.io.*; +import java.util.*; +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.memory.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.types.*; +import sun.jvm.hotspot.utilities.*; + +// An InstanceKlass is the VM level representation of a Java class. + +public class InstanceMirrorKlass extends InstanceKlass { + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { + // Just make sure it's there for now + Type type = db.lookupType("instanceMirrorKlass"); + } + + InstanceMirrorKlass(OopHandle handle, ObjectHeap heap) { + super(handle, heap); + } + + public long getObjectSize(Oop o) { + return java_lang_Class.getOopSize(o) * VM.getVM().getAddressSize(); + } + + public void iterateNonStaticFields(OopVisitor visitor, Oop obj) { + super.iterateNonStaticFields(visitor, obj); + // Fetch the real klass from the mirror object + Klass klass = java_lang_Class.asKlass(obj); + if (klass instanceof InstanceKlass) { + ((InstanceKlass)klass).iterateStaticFields(visitor); + } + } +}
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/IntField.java Fri Apr 01 10:58:10 2011 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/IntField.java Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, 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 @@ -40,7 +40,12 @@ super(holder, fieldArrayIndex); } - public int getValue(Oop obj) { return obj.getHandle().getJIntAt(getOffset()); } + public int getValue(Oop obj) { + if (!isVMField() && !obj.isInstance() && !obj.isArray()) { + throw new InternalError(obj.toString()); + } + return obj.getHandle().getJIntAt(getOffset()); + } public void setValue(Oop obj, int value) throws MutationException { // Fix this: setJIntAt is missing in Address }
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java Fri Apr 01 10:58:10 2011 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, 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 @@ -362,7 +362,16 @@ if (klass.equals(compiledICHolderKlassHandle)) return new CompiledICHolder(handle, this); if (klass.equals(methodDataKlassHandle)) return new MethodData(handle, this); } - if (klass.equals(instanceKlassKlassHandle)) return new InstanceKlass(handle, this); + if (klass.equals(instanceKlassKlassHandle)) { + InstanceKlass ik = new InstanceKlass(handle, this); + if (ik.getName().asString().equals("java/lang/Class")) { + // We would normally do this using the vtable style + // lookup but since it's not used for these currently + // it's simpler to just check for the name. + return new InstanceMirrorKlass(handle, this); + } + return ik; + } if (klass.equals(objArrayKlassKlassHandle)) return new ObjArrayKlass(handle, this); if (klass.equals(typeArrayKlassKlassHandle)) return new TypeArrayKlass(handle, this);
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java Fri Apr 01 10:58:10 2011 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, 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,12 +103,8 @@ // Returns the byte size of this object public long getObjectSize() { Klass k = getKlass(); - if (k instanceof InstanceKlass) { - return ((InstanceKlass)k).getSizeHelper() - * VM.getVM().getAddressSize(); - } - // If it is not an instance, this method should be replaced. - return getHeaderSize(); + // All other types should be overriding getObjectSize directly + return ((InstanceKlass)k).getObjectSize(this); } // Type test operations
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/OopField.java Fri Apr 01 10:58:10 2011 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/OopField.java Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, 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,11 +41,17 @@ } public Oop getValue(Oop obj) { + if (!isVMField() && !obj.isInstance() && !obj.isArray()) { + throw new InternalError(); + } return obj.getHeap().newOop(getValueAsOopHandle(obj)); } /** Debugging support */ public OopHandle getValueAsOopHandle(Oop obj) { + if (!isVMField() && !obj.isInstance() && !obj.isArray()) { + throw new InternalError(obj.toString()); + } return obj.getHandle().getOopHandleAt(getOffset()); }
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/OopUtilities.java Fri Apr 01 10:58:10 2011 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/OopUtilities.java Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, 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 @@ -74,9 +74,6 @@ private static int THREAD_STATUS_TERMINATED; */ - // java.lang.Class fields - private static OopField hcKlassField; - // java.util.concurrent.locks.AbstractOwnableSynchronizer fields private static OopField absOwnSyncOwnerThreadField; @@ -268,33 +265,6 @@ return null; } - // initialize fields for java.lang.Class - private static void initClassFields() { - if (hcKlassField == null) { - // hc_klass is a HotSpot magic field and hence we can't - // find it from InstanceKlass for java.lang.Class. - TypeDataBase db = VM.getVM().getTypeDataBase(); - int hcKlassOffset = (int) Instance.getHeaderSize(); - try { - hcKlassOffset += (db.lookupIntConstant("java_lang_Class::hc_klass_offset").intValue() * - VM.getVM().getHeapOopSize()); - } catch (RuntimeException re) { - // ignore, currently java_lang_Class::hc_klass_offset is zero - } - if (VM.getVM().isCompressedOopsEnabled()) { - hcKlassField = new NarrowOopField(new NamedFieldIdentifier("hc_klass"), hcKlassOffset, true); - } else { - hcKlassField = new OopField(new NamedFieldIdentifier("hc_klass"), hcKlassOffset, true); - } - } - } - - /** get klassOop field at offset hc_klass_offset from a java.lang.Class object */ - public static Klass classOopToKlass(Oop aClass) { - initClassFields(); - return (Klass) hcKlassField.getValue(aClass); - } - // initialize fields for j.u.c.l AbstractOwnableSynchornizer class private static void initAbsOwnSyncFields() { if (absOwnSyncOwnerThreadField == null) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/java_lang_Class.java Fri Apr 01 11:06:30 2011 +0100 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011, 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.oops; + +import java.util.*; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.memory.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.types.Type; +import sun.jvm.hotspot.types.TypeDataBase; +import sun.jvm.hotspot.utilities.*; +import sun.jvm.hotspot.jdi.JVMTIThreadState; + +/** A utility class encapsulating useful oop operations */ + +// initialize fields for java.lang.Class +public class java_lang_Class { + + // java.lang.Class fields + static OopField klassField; + static IntField oopSizeField; + + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static synchronized void initialize(TypeDataBase db) { + // klass and oop_size are HotSpot magic fields and hence we can't + // find them from InstanceKlass for java.lang.Class. + Type jlc = db.lookupType("java_lang_Class"); + int klassOffset = (int) jlc.getCIntegerField("klass_offset").getValue(); + if (VM.getVM().isCompressedOopsEnabled()) { + klassField = new NarrowOopField(new NamedFieldIdentifier("klass"), klassOffset, true); + } else { + klassField = new OopField(new NamedFieldIdentifier("klass"), klassOffset, true); + } + int oopSizeOffset = (int) jlc.getCIntegerField("oop_size_offset").getValue(); + oopSizeField = new IntField(new NamedFieldIdentifier("oop_size"), oopSizeOffset, true); + } + + /** get klassOop field at offset hc_klass_offset from a java.lang.Class object */ + public static Klass asKlass(Oop aClass) { + return (Klass) java_lang_Class.klassField.getValue(aClass); + } + + /** get oop_size field at offset oop_size_offset from a java.lang.Class object */ + public static long getOopSize(Oop aClass) { + return java_lang_Class.oopSizeField.getValue(aClass); + } +}
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java Fri Apr 01 10:58:10 2011 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, 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 @@ -839,20 +839,18 @@ } private void readSystemProperties() { - InstanceKlass systemKls = getSystemDictionary().getSystemKlass(); - systemKls.iterate(new DefaultOopVisitor() { - ObjectReader objReader = new ObjectReader(); - public void doOop(sun.jvm.hotspot.oops.OopField field, boolean isVMField) { - if (field.getID().getName().equals("props")) { - try { - sysProps = (Properties) objReader.readObject(field.getValue(getObj())); - } catch (Exception e) { - if (Assert.ASSERTS_ENABLED) { - e.printStackTrace(); - } - } - } - } - }, false); + final InstanceKlass systemKls = getSystemDictionary().getSystemKlass(); + systemKls.iterateStaticFields(new DefaultOopVisitor() { + ObjectReader objReader = new ObjectReader(); + public void doOop(sun.jvm.hotspot.oops.OopField field, boolean isVMField) { + if (field.getID().getName().equals("props")) { + try { + sysProps = (Properties) objReader.readObject(field.getValue(getObj())); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + }); } }
--- a/agent/src/share/classes/sun/jvm/hotspot/tools/FinalizerInfo.java Fri Apr 01 10:58:10 2011 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/FinalizerInfo.java Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2011, 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 @@ -64,16 +64,16 @@ */ InstanceKlass ik = SystemDictionaryHelper.findInstanceKlass("java.lang.ref.Finalizer"); - final OopField queueField[] = new OopField[1]; - ik.iterateFields(new DefaultOopVisitor() { + final Oop[] queueref = new Oop[1]; + ik.iterateStaticFields(new DefaultOopVisitor() { public void doOop(OopField field, boolean isVMField) { - String name = field.getID().getName(); - if (name.equals("queue")) { - queueField[0] = field; - } + String name = field.getID().getName(); + if (name.equals("queue")) { + queueref[0] = field.getValue(getObj()); + } } - }, false); - Oop queue = queueField[0].getValue(ik); + }); + Oop queue = queueref[0]; InstanceKlass k = (InstanceKlass) queue.getKlass();
--- a/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapGXLWriter.java Fri Apr 01 10:58:10 2011 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapGXLWriter.java Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2011, 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 @@ -164,7 +164,7 @@ protected void writeClass(Instance instance) throws IOException { writeObjectHeader(instance); - Klass reflectedType = OopUtilities.classOopToKlass(instance); + Klass reflectedType = java_lang_Class.asKlass(instance); boolean isInstanceKlass = (reflectedType instanceof InstanceKlass); // reflectedType is null for primitive types (int.class etc). if (reflectedType != null) {
--- a/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java Fri Apr 01 10:58:10 2011 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2011, 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 @@ -455,7 +455,7 @@ } protected void writeClass(Instance instance) throws IOException { - Klass reflectedKlass = OopUtilities.classOopToKlass(instance); + Klass reflectedKlass = java_lang_Class.asKlass(instance); // dump instance record only for primitive type Class objects. // all other Class objects are covered by writeClassDumpRecords. if (reflectedKlass == null) { @@ -746,7 +746,7 @@ out.writeByte((byte)kind); if (ik != null) { // static field - writeField(field, ik); + writeField(field, ik.getJavaMirror()); } } }
--- a/agent/src/share/classes/sun/jvm/hotspot/utilities/ReversePtrsAnalysis.java Fri Apr 01 10:58:10 2011 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/ReversePtrsAnalysis.java Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2011, 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,10 +117,10 @@ public boolean doObj(Oop obj) { if (obj instanceof InstanceKlass) { final InstanceKlass ik = (InstanceKlass) obj; - ik.iterateFields( + ik.iterateStaticFields( new DefaultOopVisitor() { public void doOop(OopField field, boolean isVMField) { - Oop next = field.getValue(ik); + Oop next = field.getValue(getObj()); LivenessPathElement lp = new LivenessPathElement(null, new NamedFieldIdentifier("Static field \"" + field.getID().getName() + @@ -142,8 +142,7 @@ System.err.println(); } } - }, - false); + }); } return false; }
--- a/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaFactoryImpl.java Fri Apr 01 10:58:10 2011 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaFactoryImpl.java Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2011, 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 @@ -158,7 +158,7 @@ } else if (className.equals(javaLangThread())) { res = new JSJavaThread(instance, this); } else if (className.equals(javaLangClass())) { - Klass reflectedType = OopUtilities.classOopToKlass(instance); + Klass reflectedType = java_lang_Class.asKlass(instance); if (reflectedType != null) { JSJavaKlass jk = newJSJavaKlass(reflectedType); // we don't support mirrors of VM internal Klasses
--- a/agent/test/jdi/sasanity.sh Fri Apr 01 10:58:10 2011 +0100 +++ b/agent/test/jdi/sasanity.sh Fri Apr 01 11:06:30 2011 +0100 @@ -43,6 +43,7 @@ fi jdk=$1 +shift OS=`uname` if [ "$OS" != "Linux" ]; then @@ -68,7 +69,7 @@ tmp=/tmp/sagsetup rm -f $tmp -$jdk/bin/java sagtarg > $tmp & +$jdk/bin/java $* sagtarg > $tmp & pid=$! while [ ! -s $tmp ] ; do # Kludge alert!
--- a/make/hotspot_version Fri Apr 01 10:58:10 2011 +0100 +++ b/make/hotspot_version Fri Apr 01 11:06:30 2011 +0100 @@ -35,7 +35,7 @@ HS_MAJOR_VER=21 HS_MINOR_VER=0 -HS_BUILD_NUMBER=04 +HS_BUILD_NUMBER=05 JDK_MAJOR_VER=1 JDK_MINOR_VER=7
--- a/make/linux/makefiles/adlc.make Fri Apr 01 10:58:10 2011 +0100 +++ b/make/linux/makefiles/adlc.make Fri Apr 01 11:06:30 2011 +0100 @@ -102,7 +102,7 @@ $(EXEC) : $(OBJECTS) @echo Making adlc - $(QUIETLY) $(LINK_NOPROF.CC) -o $(EXEC) $(OBJECTS) + $(QUIETLY) $(HOST.LINK_NOPROF.CC) -o $(EXEC) $(OBJECTS) # Random dependencies: $(OBJECTS): opcodes.hpp classes.hpp adlc.hpp adlcVMDeps.hpp adlparse.hpp archDesc.hpp arena.hpp dict2.hpp filebuff.hpp forms.hpp formsopt.hpp formssel.hpp @@ -204,14 +204,14 @@ $(OUTDIR)/%.o: %.cpp @echo Compiling $< $(QUIETLY) $(REMOVE_TARGET) - $(QUIETLY) $(COMPILE.CC) -o $@ $< $(COMPILE_DONE) + $(QUIETLY) $(HOST.COMPILE.CC) -o $@ $< $(COMPILE_DONE) # Some object files are given a prefix, to disambiguate # them from objects of the same name built for the VM. $(OUTDIR)/adlc-%.o: %.cpp @echo Compiling $< $(QUIETLY) $(REMOVE_TARGET) - $(QUIETLY) $(COMPILE.CC) -o $@ $< $(COMPILE_DONE) + $(QUIETLY) $(HOST.COMPILE.CC) -o $@ $< $(COMPILE_DONE) # #########################################################################
--- a/make/linux/makefiles/gcc.make Fri Apr 01 10:58:10 2011 +0100 +++ b/make/linux/makefiles/gcc.make Fri Apr 01 11:06:30 2011 +0100 @@ -30,9 +30,13 @@ ifdef CROSS_COMPILE_ARCH CPP = $(ALT_COMPILER_PATH)/g++ CC = $(ALT_COMPILER_PATH)/gcc +HOSTCPP = g++ +HOSTCC = gcc else CPP = g++ CC = gcc +HOSTCPP = $(CPP) +HOSTCC = $(CC) endif AS = $(CC) -c
--- a/make/linux/makefiles/rules.make Fri Apr 01 10:58:10 2011 +0100 +++ b/make/linux/makefiles/rules.make Fri Apr 01 11:06:30 2011 +0100 @@ -55,6 +55,14 @@ LINK_LIB.CC = $(CCC) $(LFLAGS) $(SHARED_FLAG) PREPROCESS.CC = $(CC_COMPILE) -E +# cross compiling the jvm with c2 requires host compilers to build +# adlc tool + +HOST.CC_COMPILE = $(HOSTCPP) $(CPPFLAGS) $(CFLAGS) +HOST.COMPILE.CC = $(HOST.CC_COMPILE) -c +HOST.LINK_NOPROF.CC = $(HOSTCPP) $(LFLAGS) $(AOUT_FLAGS) + + # Effect of REMOVE_TARGET is to delete out-of-date files during "gnumake -k". REMOVE_TARGET = rm -f $@
--- a/make/linux/makefiles/sparcWorks.make Fri Apr 01 10:58:10 2011 +0100 +++ b/make/linux/makefiles/sparcWorks.make Fri Apr 01 11:06:30 2011 +0100 @@ -29,6 +29,9 @@ CC = cc AS = $(CC) -c +HOSTCPP = $(CPP) +HOSTCC = $(CC) + ARCHFLAG = $(ARCHFLAG/$(BUILDARCH)) ARCHFLAG/i486 = -m32 ARCHFLAG/amd64 = -m64
--- a/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -301,7 +301,8 @@ // thread. assert(_obj != noreg, "must be a valid register"); assert(_oop_index >= 0, "must have oop index"); - __ ld_ptr(_obj, instanceKlass::init_thread_offset_in_bytes() + sizeof(klassOopDesc), G3); + __ load_heap_oop(_obj, java_lang_Class::klass_offset_in_bytes(), G3); + __ ld_ptr(G3, instanceKlass::init_thread_offset_in_bytes() + sizeof(klassOopDesc), G3); __ cmp(G2_thread, G3); __ br(Assembler::notEqual, false, Assembler::pn, call_patch); __ delayed()->nop();
--- a/src/cpu/sparc/vm/cppInterpreter_sparc.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/sparc/vm/cppInterpreter_sparc.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1188,8 +1188,8 @@ __ st_ptr(O2, XXX_STATE(_stack)); // PREPUSH __ lduh(max_stack, O3); // Full size expression stack - guarantee(!EnableMethodHandles, "no support yet for java.lang.invoke.MethodHandle"); //6815692 - //6815692//if (EnableMethodHandles) + guarantee(!EnableInvokeDynamic, "no support yet for java.lang.invoke.MethodHandle"); //6815692 + //6815692//if (EnableInvokeDynamic) //6815692// __ inc(O3, methodOopDesc::extra_stack_entries()); __ sll(O3, LogBytesPerWord, O3); __ sub(O2, O3, O3);
--- a/src/cpu/sparc/vm/dump_sparc.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/sparc/vm/dump_sparc.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -80,13 +80,19 @@ for (int j = 0; j < num_virtuals; ++j) { dummy_vtable[num_virtuals * i + j] = (void*)masm->pc(); __ save(SP, -256, SP); + int offset = (i << 8) + j; + Register src = G0; + if (!Assembler::is_simm13(offset)) { + __ sethi(offset, L0); + src = L0; + offset = offset & ((1 << 10) - 1); + } __ brx(Assembler::always, false, Assembler::pt, common_code); // Load L0 with a value indicating vtable/offset pair. // -- bits[ 7..0] (8 bits) which virtual method in table? - // -- bits[12..8] (5 bits) which virtual method table? - // -- must fit in 13-bit instruction immediate field. - __ delayed()->set((i << 8) + j, L0); + // -- bits[13..8] (6 bits) which virtual method table? + __ delayed()->or3(src, offset, L0); } }
--- a/src/cpu/sparc/vm/globals_sparc.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/sparc/vm/globals_sparc.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, 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,6 +51,7 @@ define_pd_global(intx, OptoLoopAlignment, 16); // = 4*wordSize define_pd_global(intx, InlineFrequencyCount, 50); // we can use more inlining on the SPARC define_pd_global(intx, InlineSmallCode, 1500); + #ifdef _LP64 // Stack slots are 2X larger in LP64 than in the 32 bit VM. define_pd_global(intx, ThreadStackSize, 1024); @@ -71,4 +72,6 @@ define_pd_global(bool, UseMembar, false); +// GC Ergo Flags +define_pd_global(intx, CMSYoungGenPerWorker, 16*M); // default max size of CMS young gen, per GC worker thread #endif // CPU_SPARC_VM_GLOBALS_SPARC_HPP
--- a/src/cpu/sparc/vm/interp_masm_sparc.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/sparc/vm/interp_masm_sparc.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -743,12 +743,12 @@ if (index_size == sizeof(u2)) { get_2_byte_integer_at_bcp(bcp_offset, cache, tmp, Unsigned); } else if (index_size == sizeof(u4)) { - assert(EnableInvokeDynamic, "giant index used only for EnableInvokeDynamic"); + assert(EnableInvokeDynamic, "giant index used only for JSR 292"); get_4_byte_integer_at_bcp(bcp_offset, cache, tmp); assert(constantPoolCacheOopDesc::decode_secondary_index(~123) == 123, "else change next line"); xor3(tmp, -1, tmp); // convert to plain index } else if (index_size == sizeof(u1)) { - assert(EnableMethodHandles, "tiny index used only for EnableMethodHandles"); + assert(EnableInvokeDynamic, "tiny index used only for JSR 292"); ldub(Lbcp, bcp_offset, tmp); } else { ShouldNotReachHere();
--- a/src/cpu/sparc/vm/interpreter_sparc.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/sparc/vm/interpreter_sparc.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -262,7 +262,7 @@ // Method handle invoker // Dispatch a method of the form java.lang.invoke.MethodHandles::invoke(...) address InterpreterGenerator::generate_method_handle_entry(void) { - if (!EnableMethodHandles) { + if (!EnableInvokeDynamic) { return generate_abstract_entry(); }
--- a/src/cpu/sparc/vm/methodHandles_sparc.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/sparc/vm/methodHandles_sparc.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -775,9 +775,13 @@ switch (ek) { case _adapter_opt_i2l: { - __ ldsw(arg_lsw, O2_scratch); // Load LSW - NOT_LP64(__ srlx(O2_scratch, BitsPerInt, O3_scratch)); // Move high bits to lower bits for std - __ st_long(O2_scratch, arg_msw); // Uses O2/O3 on !_LP64 +#ifdef _LP64 + __ ldsw(arg_lsw, O2_scratch); // Load LSW sign-extended +#else + __ ldsw(arg_lsw, O3_scratch); // Load LSW sign-extended + __ srlx(O3_scratch, BitsPerInt, O2_scratch); // Move MSW value to lower 32-bits for std +#endif + __ st_long(O2_scratch, arg_msw); // Uses O2/O3 on !_LP64 } break; case _adapter_opt_unboxl:
--- a/src/cpu/sparc/vm/nativeInst_sparc.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/sparc/vm/nativeInst_sparc.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -52,6 +52,22 @@ ICache::invalidate_range(instaddr, 7 * BytesPerInstWord); } +void NativeInstruction::verify_data64_sethi(address instaddr, intptr_t x) { + ResourceMark rm; + unsigned char buffer[10 * BytesPerInstWord]; + CodeBuffer buf(buffer, 10 * BytesPerInstWord); + MacroAssembler masm(&buf); + + Register destreg = inv_rd(*(unsigned int *)instaddr); + // Generate the proper sequence into a temporary buffer and compare + // it with the original sequence. + masm.patchable_sethi(x, destreg); + int len = buffer - masm.pc(); + for (int i = 0; i < len; i++) { + assert(instaddr[i] == buffer[i], "instructions must match"); + } +} + void NativeInstruction::verify() { // make sure code pattern is actually an instruction address address addr = addr_at(0);
--- a/src/cpu/sparc/vm/nativeInst_sparc.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/sparc/vm/nativeInst_sparc.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -254,6 +254,7 @@ // sethi. This only does the sethi. The disp field (bottom 10 bits) // must be handled separately. static void set_data64_sethi(address instaddr, intptr_t x); + static void verify_data64_sethi(address instaddr, intptr_t x); // combine the fields of a sethi/simm13 pair (simm13 = or, add, jmpl, ld/st) static int data32(int sethi_insn, int arith_insn) {
--- a/src/cpu/sparc/vm/relocInfo_sparc.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/sparc/vm/relocInfo_sparc.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -30,7 +30,7 @@ #include "oops/oop.inline.hpp" #include "runtime/safepoint.hpp" -void Relocation::pd_set_data_value(address x, intptr_t o) { +void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) { NativeInstruction* ip = nativeInstruction_at(addr()); jint inst = ip->long_at(0); assert(inst != NativeInstruction::illegal_instruction(), "no breakpoint"); @@ -83,7 +83,11 @@ guarantee(Assembler::is_simm13(simm13), "offset can't overflow simm13"); inst &= ~Assembler::simm( -1, 13); inst |= Assembler::simm(simm13, 13); - ip->set_long_at(0, inst); + if (verify_only) { + assert(ip->long_at(0) == inst, "instructions must match"); + } else { + ip->set_long_at(0, inst); + } } break; @@ -97,19 +101,36 @@ jint np = oopDesc::encode_heap_oop((oop)x); inst &= ~Assembler::hi22(-1); inst |= Assembler::hi22((intptr_t)np); - ip->set_long_at(0, inst); + if (verify_only) { + assert(ip->long_at(0) == inst, "instructions must match"); + } else { + ip->set_long_at(0, inst); + } inst2 = ip->long_at( NativeInstruction::nop_instruction_size ); guarantee(Assembler::inv_op(inst2)==Assembler::arith_op, "arith op"); - ip->set_long_at(NativeInstruction::nop_instruction_size, ip->set_data32_simm13( inst2, (intptr_t)np)); + if (verify_only) { + assert(ip->long_at(NativeInstruction::nop_instruction_size) == NativeInstruction::set_data32_simm13( inst2, (intptr_t)np), + "instructions must match"); + } else { + ip->set_long_at(NativeInstruction::nop_instruction_size, NativeInstruction::set_data32_simm13( inst2, (intptr_t)np)); + } break; } - ip->set_data64_sethi( ip->addr_at(0), (intptr_t)x ); + if (verify_only) { + ip->verify_data64_sethi( ip->addr_at(0), (intptr_t)x ); + } else { + ip->set_data64_sethi( ip->addr_at(0), (intptr_t)x ); + } #else guarantee(Assembler::inv_op2(inst)==Assembler::sethi_op2, "must be sethi"); inst &= ~Assembler::hi22( -1); inst |= Assembler::hi22((intptr_t)x); // (ignore offset; it doesn't play into the sethi) - ip->set_long_at(0, inst); + if (verify_only) { + assert(ip->long_at(0) == inst, "instructions must match"); + } else { + ip->set_long_at(0, inst); + } #endif } break;
--- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, 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 @@ -1769,6 +1769,7 @@ // returns. nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler* masm, methodHandle method, + int compile_id, int total_in_args, int comp_args_on_stack, // in VMRegStackSlots BasicType *in_sig_bt, @@ -2462,6 +2463,7 @@ __ flush(); nmethod *nm = nmethod::new_native_nmethod(method, + compile_id, masm->code(), vep_offset, frame_complete,
--- a/src/cpu/sparc/vm/sparc.ad Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/sparc/vm/sparc.ad Fri Apr 01 11:06:30 2011 +0100 @@ -1843,6 +1843,10 @@ // registers? True for Intel but false for most RISCs const bool Matcher::clone_shift_expressions = false; +// Do we need to mask the count passed to shift instructions or does +// the cpu only look at the lower 5/6 bits anyway? +const bool Matcher::need_masked_shift_count = false; + bool Matcher::narrow_oop_use_complex_address() { NOT_LP64(ShouldNotCallThis()); assert(UseCompressedOops, "only for compressed oops code");
--- a/src/cpu/sparc/vm/templateTable_sparc.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/sparc/vm/templateTable_sparc.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -334,8 +334,8 @@ void TemplateTable::fast_aldc(bool wide) { transition(vtos, atos); - if (!EnableMethodHandles) { - // We should not encounter this bytecode if !EnableMethodHandles. + if (!EnableInvokeDynamic) { + // We should not encounter this bytecode if !EnableInvokeDynamic. // The verifier will stop it. However, if we get past the verifier, // this will stop the thread in a reasonable way, without crashing the JVM. __ call_VM(noreg, CAST_FROM_FN_PTR(address,
--- a/src/cpu/x86/vm/assembler_x86.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/x86/vm/assembler_x86.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -3510,7 +3510,6 @@ // anywhere in the codeCache then we are always reachable. // This would have to change if we ever save/restore shared code // to be more pessimistic. - disp = (int64_t)adr._target - ((int64_t)CodeCache::low_bound() + sizeof(int)); if (!is_simm32(disp)) return false; disp = (int64_t)adr._target - ((int64_t)CodeCache::high_bound() + sizeof(int)); @@ -3534,6 +3533,14 @@ return is_simm32(disp); } +// Check if the polling page is not reachable from the code cache using rip-relative +// addressing. +bool Assembler::is_polling_page_far() { + intptr_t addr = (intptr_t)os::get_polling_page(); + return !is_simm32(addr - (intptr_t)CodeCache::low_bound()) || + !is_simm32(addr - (intptr_t)CodeCache::high_bound()); +} + void Assembler::emit_data64(jlong data, relocInfo::relocType rtype, int format) { @@ -6886,6 +6893,11 @@ } } +void MacroAssembler::testl(Register dst, AddressLiteral src) { + assert(reachable(src), "Address should be reachable"); + testl(dst, as_Address(src)); +} + ////////////////////////////////////////////////////////////////////////////////// #ifndef SERIALGC @@ -7121,17 +7133,6 @@ LP64_ONLY(subq(dst, src)) NOT_LP64(subl(dst, src)); } -void MacroAssembler::test32(Register src1, AddressLiteral src2) { - // src2 must be rval - - if (reachable(src2)) { - testl(src1, as_Address(src2)); - } else { - lea(rscratch1, src2); - testl(src1, Address(rscratch1, 0)); - } -} - // C++ bool manipulation void MacroAssembler::testbool(Register dst) { if(sizeof(bool) == 1) @@ -7768,6 +7769,28 @@ } } +void MacroAssembler::cmov32(Condition cc, Register dst, Address src) { + if (VM_Version::supports_cmov()) { + cmovl(cc, dst, src); + } else { + Label L; + jccb(negate_condition(cc), L); + movl(dst, src); + bind(L); + } +} + +void MacroAssembler::cmov32(Condition cc, Register dst, Register src) { + if (VM_Version::supports_cmov()) { + cmovl(cc, dst, src); + } else { + Label L; + jccb(negate_condition(cc), L); + movl(dst, src); + bind(L); + } +} + void MacroAssembler::verify_oop(Register reg, const char* s) { if (!VerifyOops) return; @@ -9018,14 +9041,7 @@ movl(result, cnt1); subl(cnt1, cnt2); push(cnt1); - if (VM_Version::supports_cmov()) { - cmovl(Assembler::lessEqual, cnt2, result); - } else { - Label GT_LABEL; - jccb(Assembler::greater, GT_LABEL); - movl(cnt2, result); - bind(GT_LABEL); - } + cmov32(Assembler::lessEqual, cnt2, result); // Is the minimum length zero? testl(cnt2, cnt2);
--- a/src/cpu/x86/vm/assembler_x86.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/x86/vm/assembler_x86.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -580,7 +580,6 @@ void emit_data64(jlong data, relocInfo::relocType rtype, int format = 0); void emit_data64(jlong data, RelocationHolder const& rspec, int format = 0); - bool reachable(AddressLiteral adr) NOT_LP64({ return true;}); // These are all easily abused and hence protected @@ -683,6 +682,8 @@ static bool is_simm32(int32_t x) { return true; } #endif // _LP64 + static bool is_polling_page_far() NOT_LP64({ return false;}); + // Generic instructions // Does 32bit or 64bit as needed for the platform. In some sense these // belong in macro assembler but there is no need for both varieties to exist @@ -2094,7 +2095,10 @@ void leal32(Register dst, Address src) { leal(dst, src); } - void test32(Register src1, AddressLiteral src2); + // Import other testl() methods from the parent class or else + // they will be hidden by the following overriding declaration. + using Assembler::testl; + void testl(Register dst, AddressLiteral src); void orptr(Register dst, Address src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); } void orptr(Register dst, Register src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); } @@ -2240,10 +2244,13 @@ // Data - void cmov(Condition cc, Register dst, Register src) { LP64_ONLY(cmovq(cc, dst, src)) NOT_LP64(cmovl(cc, dst, src)); } - - void cmovptr(Condition cc, Register dst, Address src) { LP64_ONLY(cmovq(cc, dst, src)) NOT_LP64(cmovl(cc, dst, src)); } - void cmovptr(Condition cc, Register dst, Register src) { LP64_ONLY(cmovq(cc, dst, src)) NOT_LP64(cmovl(cc, dst, src)); } + void cmov32( Condition cc, Register dst, Address src); + void cmov32( Condition cc, Register dst, Register src); + + void cmov( Condition cc, Register dst, Register src) { cmovptr(cc, dst, src); } + + void cmovptr(Condition cc, Register dst, Address src) { LP64_ONLY(cmovq(cc, dst, src)) NOT_LP64(cmov32(cc, dst, src)); } + void cmovptr(Condition cc, Register dst, Register src) { LP64_ONLY(cmovq(cc, dst, src)) NOT_LP64(cmov32(cc, dst, src)); } void movoop(Register dst, jobject obj); void movoop(Address dst, jobject obj);
--- a/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -313,10 +313,13 @@ } assert(_obj != noreg, "must be a valid register"); Register tmp = rax; - if (_obj == tmp) tmp = rbx; + Register tmp2 = rbx; __ push(tmp); + __ push(tmp2); + __ load_heap_oop(tmp2, Address(_obj, java_lang_Class::klass_offset_in_bytes())); __ get_thread(tmp); - __ cmpptr(tmp, Address(_obj, instanceKlass::init_thread_offset_in_bytes() + sizeof(klassOopDesc))); + __ cmpptr(tmp, Address(tmp2, instanceKlass::init_thread_offset_in_bytes() + sizeof(klassOopDesc))); + __ pop(tmp2); __ pop(tmp); __ jcc(Assembler::notEqual, call_patch);
--- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "asm/assembler.hpp" #include "c1/c1_Compilation.hpp" #include "c1/c1_LIRAssembler.hpp" #include "c1/c1_MacroAssembler.hpp" @@ -569,24 +570,13 @@ __ lea (rdi, Address(rdi, rcx, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_CHAR))); // compute minimum length (in rax) and difference of lengths (on top of stack) - if (VM_Version::supports_cmov()) { - __ movl (rbx, Address(rbx, java_lang_String::count_offset_in_bytes())); - __ movl (rax, Address(rax, java_lang_String::count_offset_in_bytes())); - __ mov (rcx, rbx); - __ subptr (rbx, rax); // subtract lengths - __ push (rbx); // result - __ cmov (Assembler::lessEqual, rax, rcx); - } else { - Label L; - __ movl (rbx, Address(rbx, java_lang_String::count_offset_in_bytes())); - __ movl (rcx, Address(rax, java_lang_String::count_offset_in_bytes())); - __ mov (rax, rbx); - __ subptr (rbx, rcx); - __ push (rbx); - __ jcc (Assembler::lessEqual, L); - __ mov (rax, rcx); - __ bind (L); - } + __ movl (rbx, Address(rbx, java_lang_String::count_offset_in_bytes())); + __ movl (rax, Address(rax, java_lang_String::count_offset_in_bytes())); + __ mov (rcx, rbx); + __ subptr(rbx, rax); // subtract lengths + __ push (rbx); // result + __ cmov (Assembler::lessEqual, rax, rcx); + // is minimum length 0? Label noLoop, haveResult; __ testptr (rax, rax); @@ -648,12 +638,13 @@ AddressLiteral polling_page(os::get_polling_page() + (SafepointPollOffset % os::vm_page_size()), relocInfo::poll_return_type); - // NOTE: the requires that the polling page be reachable else the reloc - // goes to the movq that loads the address and not the faulting instruction - // which breaks the signal handler code - - __ test32(rax, polling_page); - + if (Assembler::is_polling_page_far()) { + __ lea(rscratch1, polling_page); + __ relocate(relocInfo::poll_return_type); + __ testl(rax, Address(rscratch1, 0)); + } else { + __ testl(rax, polling_page); + } __ ret(0); } @@ -661,20 +652,17 @@ int LIR_Assembler::safepoint_poll(LIR_Opr tmp, CodeEmitInfo* info) { AddressLiteral polling_page(os::get_polling_page() + (SafepointPollOffset % os::vm_page_size()), relocInfo::poll_type); - - if (info != NULL) { + guarantee(info != NULL, "Shouldn't be NULL"); + int offset = __ offset(); + if (Assembler::is_polling_page_far()) { + __ lea(rscratch1, polling_page); + offset = __ offset(); add_debug_info_for_branch(info); + __ testl(rax, Address(rscratch1, 0)); } else { - ShouldNotReachHere(); + add_debug_info_for_branch(info); + __ testl(rax, polling_page); } - - int offset = __ offset(); - - // NOTE: the requires that the polling page be reachable else the reloc - // goes to the movq that loads the address and not the faulting instruction - // which breaks the signal handler code - - __ test32(rax, polling_page); return offset; }
--- a/src/cpu/x86/vm/c1_Runtime1_x86.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/x86/vm/c1_Runtime1_x86.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "asm/assembler.hpp" #include "c1/c1_Defs.hpp" #include "c1/c1_MacroAssembler.hpp" #include "c1/c1_Runtime1.hpp"
--- a/src/cpu/x86/vm/frame_x86.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/x86/vm/frame_x86.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -125,7 +125,7 @@ // Entry frames #ifdef AMD64 #ifdef _WIN64 - entry_frame_after_call_words = 8, + entry_frame_after_call_words = 28, entry_frame_call_wrapper_offset = 2, arg_reg_save_area_bytes = 32, // Register argument save area
--- a/src/cpu/x86/vm/globals_x86.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/x86/vm/globals_x86.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, 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 @@ -72,4 +72,6 @@ define_pd_global(bool, UseMembar, false); +// GC Ergo Flags +define_pd_global(intx, CMSYoungGenPerWorker, 64*M); // default max size of CMS young gen, per GC worker thread #endif // CPU_X86_VM_GLOBALS_X86_HPP
--- a/src/cpu/x86/vm/interp_masm_x86_32.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/x86/vm/interp_masm_x86_32.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -215,7 +215,7 @@ if (index_size == sizeof(u2)) { load_unsigned_short(reg, Address(rsi, bcp_offset)); } else if (index_size == sizeof(u4)) { - assert(EnableInvokeDynamic, "giant index used only for EnableInvokeDynamic"); + assert(EnableInvokeDynamic, "giant index used only for JSR 292"); movl(reg, Address(rsi, bcp_offset)); // Check if the secondary index definition is still ~x, otherwise // we have to change the following assembler code to calculate the @@ -223,7 +223,7 @@ assert(constantPoolCacheOopDesc::decode_secondary_index(~123) == 123, "else change next line"); notl(reg); // convert to plain index } else if (index_size == sizeof(u1)) { - assert(EnableMethodHandles, "tiny index used only for EnableMethodHandles"); + assert(EnableInvokeDynamic, "tiny index used only for JSR 292"); load_unsigned_byte(reg, Address(rsi, bcp_offset)); } else { ShouldNotReachHere();
--- a/src/cpu/x86/vm/interp_masm_x86_64.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/x86/vm/interp_masm_x86_64.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -213,7 +213,7 @@ if (index_size == sizeof(u2)) { load_unsigned_short(index, Address(r13, bcp_offset)); } else if (index_size == sizeof(u4)) { - assert(EnableInvokeDynamic, "giant index used only for EnableInvokeDynamic"); + assert(EnableInvokeDynamic, "giant index used only for JSR 292"); movl(index, Address(r13, bcp_offset)); // Check if the secondary index definition is still ~x, otherwise // we have to change the following assembler code to calculate the @@ -221,7 +221,7 @@ assert(constantPoolCacheOopDesc::decode_secondary_index(~123) == 123, "else change next line"); notl(index); // convert to plain index } else if (index_size == sizeof(u1)) { - assert(EnableMethodHandles, "tiny index used only for EnableMethodHandles"); + assert(EnableInvokeDynamic, "tiny index used only for JSR 292"); load_unsigned_byte(index, Address(r13, bcp_offset)); } else { ShouldNotReachHere();
--- a/src/cpu/x86/vm/interpreter_x86_32.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/x86/vm/interpreter_x86_32.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -233,7 +233,7 @@ // Method handle invoker // Dispatch a method of the form java.lang.invoke.MethodHandles::invoke(...) address InterpreterGenerator::generate_method_handle_entry(void) { - if (!EnableMethodHandles) { + if (!EnableInvokeDynamic) { return generate_abstract_entry(); }
--- a/src/cpu/x86/vm/interpreter_x86_64.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/x86/vm/interpreter_x86_64.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -320,7 +320,7 @@ // Method handle invoker // Dispatch a method of the form java.lang.invoke.MethodHandles::invoke(...) address InterpreterGenerator::generate_method_handle_entry(void) { - if (!EnableMethodHandles) { + if (!EnableInvokeDynamic) { return generate_abstract_entry(); }
--- a/src/cpu/x86/vm/nativeInst_x86.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/x86/vm/nativeInst_x86.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -519,7 +519,11 @@ class NativeTstRegMem: public NativeInstruction { public: enum Intel_specific_constants { - instruction_code_memXregl = 0x85 + instruction_rex_prefix_mask = 0xF0, + instruction_rex_prefix = Assembler::REX, + instruction_code_memXregl = 0x85, + modrm_mask = 0x38, // select reg from the ModRM byte + modrm_reg = 0x00 // rax }; }; @@ -533,12 +537,25 @@ (ubyte_at(0) & 0xF0) == 0x70; /* short jump */ } inline bool NativeInstruction::is_safepoint_poll() { #ifdef AMD64 - if ( ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl && - ubyte_at(1) == 0x05 ) { // 00 rax 101 - address fault = addr_at(6) + int_at(2); - return os::is_poll_address(fault); + if (Assembler::is_polling_page_far()) { + // two cases, depending on the choice of the base register in the address. + if (((ubyte_at(0) & NativeTstRegMem::instruction_rex_prefix_mask) == NativeTstRegMem::instruction_rex_prefix && + ubyte_at(1) == NativeTstRegMem::instruction_code_memXregl && + (ubyte_at(2) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg) || + ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl && + (ubyte_at(1) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg) { + return true; + } else { + return false; + } } else { - return false; + if (ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl && + ubyte_at(1) == 0x05) { // 00 rax 101 + address fault = addr_at(6) + int_at(2); + return os::is_poll_address(fault); + } else { + return false; + } } #else return ( ubyte_at(0) == NativeMovRegMem::instruction_code_mem2reg ||
--- a/src/cpu/x86/vm/relocInfo_x86.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/x86/vm/relocInfo_x86.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2011, 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,7 +31,7 @@ #include "runtime/safepoint.hpp" -void Relocation::pd_set_data_value(address x, intptr_t o) { +void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) { #ifdef AMD64 x += o; typedef Assembler::WhichOperand WhichOperand; @@ -40,19 +40,35 @@ which == Assembler::narrow_oop_operand || which == Assembler::imm_operand, "format unpacks ok"); if (which == Assembler::imm_operand) { - *pd_address_in_code() = x; + if (verify_only) { + assert(*pd_address_in_code() == x, "instructions must match"); + } else { + *pd_address_in_code() = x; + } } else if (which == Assembler::narrow_oop_operand) { address disp = Assembler::locate_operand(addr(), which); - *(int32_t*) disp = oopDesc::encode_heap_oop((oop)x); + if (verify_only) { + assert(*(uint32_t*) disp == oopDesc::encode_heap_oop((oop)x), "instructions must match"); + } else { + *(int32_t*) disp = oopDesc::encode_heap_oop((oop)x); + } } else { // Note: Use runtime_call_type relocations for call32_operand. address ip = addr(); address disp = Assembler::locate_operand(ip, which); address next_ip = Assembler::locate_next_instruction(ip); - *(int32_t*) disp = x - next_ip; + if (verify_only) { + assert(*(int32_t*) disp == (x - next_ip), "instructions must match"); + } else { + *(int32_t*) disp = x - next_ip; + } } #else - *pd_address_in_code() = x + o; + if (verify_only) { + assert(*pd_address_in_code() == (x + o), "instructions must match"); + } else { + *pd_address_in_code() = x + o; + } #endif // AMD64 } @@ -182,41 +198,44 @@ void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { #ifdef _LP64 - typedef Assembler::WhichOperand WhichOperand; - WhichOperand which = (WhichOperand) format(); - // This format is imm but it is really disp32 - which = Assembler::disp32_operand; - address orig_addr = old_addr_for(addr(), src, dest); - NativeInstruction* oni = nativeInstruction_at(orig_addr); - int32_t* orig_disp = (int32_t*) Assembler::locate_operand(orig_addr, which); - // This poll_addr is incorrect by the size of the instruction it is irrelevant - intptr_t poll_addr = (intptr_t)oni + *orig_disp; + if (!Assembler::is_polling_page_far()) { + typedef Assembler::WhichOperand WhichOperand; + WhichOperand which = (WhichOperand) format(); + // This format is imm but it is really disp32 + which = Assembler::disp32_operand; + address orig_addr = old_addr_for(addr(), src, dest); + NativeInstruction* oni = nativeInstruction_at(orig_addr); + int32_t* orig_disp = (int32_t*) Assembler::locate_operand(orig_addr, which); + // This poll_addr is incorrect by the size of the instruction it is irrelevant + intptr_t poll_addr = (intptr_t)oni + *orig_disp; - NativeInstruction* ni = nativeInstruction_at(addr()); - intptr_t new_disp = poll_addr - (intptr_t) ni; + NativeInstruction* ni = nativeInstruction_at(addr()); + intptr_t new_disp = poll_addr - (intptr_t) ni; - int32_t* disp = (int32_t*) Assembler::locate_operand(addr(), which); - * disp = (int32_t)new_disp; - + int32_t* disp = (int32_t*) Assembler::locate_operand(addr(), which); + * disp = (int32_t)new_disp; + } #endif // _LP64 } void poll_return_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { #ifdef _LP64 - typedef Assembler::WhichOperand WhichOperand; - WhichOperand which = (WhichOperand) format(); - // This format is imm but it is really disp32 - which = Assembler::disp32_operand; - address orig_addr = old_addr_for(addr(), src, dest); - NativeInstruction* oni = nativeInstruction_at(orig_addr); - int32_t* orig_disp = (int32_t*) Assembler::locate_operand(orig_addr, which); - // This poll_addr is incorrect by the size of the instruction it is irrelevant - intptr_t poll_addr = (intptr_t)oni + *orig_disp; + if (!Assembler::is_polling_page_far()) { + typedef Assembler::WhichOperand WhichOperand; + WhichOperand which = (WhichOperand) format(); + // This format is imm but it is really disp32 + which = Assembler::disp32_operand; + address orig_addr = old_addr_for(addr(), src, dest); + NativeInstruction* oni = nativeInstruction_at(orig_addr); + int32_t* orig_disp = (int32_t*) Assembler::locate_operand(orig_addr, which); + // This poll_addr is incorrect by the size of the instruction it is irrelevant + intptr_t poll_addr = (intptr_t)oni + *orig_disp; - NativeInstruction* ni = nativeInstruction_at(addr()); - intptr_t new_disp = poll_addr - (intptr_t) ni; + NativeInstruction* ni = nativeInstruction_at(addr()); + intptr_t new_disp = poll_addr - (intptr_t) ni; - int32_t* disp = (int32_t*) Assembler::locate_operand(addr(), which); - * disp = (int32_t)new_disp; + int32_t* disp = (int32_t*) Assembler::locate_operand(addr(), which); + * disp = (int32_t)new_disp; + } #endif // _LP64 }
--- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1111,6 +1111,7 @@ // returns. nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, methodHandle method, + int compile_id, int total_in_args, int comp_args_on_stack, BasicType *in_sig_bt, @@ -1854,6 +1855,7 @@ __ flush(); nmethod *nm = nmethod::new_native_nmethod(method, + compile_id, masm->code(), vep_offset, frame_complete,
--- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1174,6 +1174,7 @@ // returns. nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, methodHandle method, + int compile_id, int total_in_args, int comp_args_on_stack, BasicType *in_sig_bt, @@ -1881,6 +1882,7 @@ __ flush(); nmethod *nm = nmethod::new_native_nmethod(method, + compile_id, masm->code(), vep_offset, frame_complete,
--- a/src/cpu/x86/vm/stubGenerator_x86_64.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/x86/vm/stubGenerator_x86_64.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -144,8 +144,11 @@ // [ return_from_Java ] <--- rsp // [ argument word n ] // ... - // -8 [ argument word 1 ] - // -7 [ saved r15 ] <--- rsp_after_call + // -28 [ argument word 1 ] + // -27 [ saved xmm15 ] <--- rsp_after_call + // [ saved xmm7-xmm14 ] + // -9 [ saved xmm6 ] (each xmm register takes 2 slots) + // -7 [ saved r15 ] // -6 [ saved r14 ] // -5 [ saved r13 ] // -4 [ saved r12 ] @@ -169,8 +172,11 @@ // Call stub stack layout word offsets from rbp enum call_stub_layout { #ifdef _WIN64 - rsp_after_call_off = -7, - r15_off = rsp_after_call_off, + xmm_save_first = 6, // save from xmm6 + xmm_save_last = 15, // to xmm15 + xmm_save_base = -9, + rsp_after_call_off = xmm_save_base - 2 * (xmm_save_last - xmm_save_first), // -27 + r15_off = -7, r14_off = -6, r13_off = -5, r12_off = -4, @@ -208,6 +214,13 @@ #endif }; +#ifdef _WIN64 + Address xmm_save(int reg) { + assert(reg >= xmm_save_first && reg <= xmm_save_last, "XMM register number out of range"); + return Address(rbp, (xmm_save_base - (reg - xmm_save_first) * 2) * wordSize); + } +#endif + address generate_call_stub(address& return_address) { assert((int)frame::entry_frame_after_call_words == -(int)rsp_after_call_off + 1 && (int)frame::entry_frame_call_wrapper_offset == (int)call_wrapper_off, @@ -256,8 +269,11 @@ __ movptr(r13_save, r13); __ movptr(r14_save, r14); __ movptr(r15_save, r15); - #ifdef _WIN64 + for (int i = 6; i <= 15; i++) { + __ movdqu(xmm_save(i), as_XMMRegister(i)); + } + const Address rdi_save(rbp, rdi_off * wordSize); const Address rsi_save(rbp, rsi_off * wordSize); @@ -360,6 +376,11 @@ #endif // restore regs belonging to calling function +#ifdef _WIN64 + for (int i = 15; i >= 6; i--) { + __ movdqu(as_XMMRegister(i), xmm_save(i)); + } +#endif __ movptr(r15, r15_save); __ movptr(r14, r14_save); __ movptr(r13, r13_save); @@ -2428,8 +2449,8 @@ // address generate_generic_copy(const char *name, address byte_copy_entry, address short_copy_entry, - address int_copy_entry, address long_copy_entry, - address oop_copy_entry, address checkcast_copy_entry) { + address int_copy_entry, address oop_copy_entry, + address long_copy_entry, address checkcast_copy_entry) { Label L_failed, L_failed_0, L_objArray; Label L_copy_bytes, L_copy_shorts, L_copy_ints, L_copy_longs;
--- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1527,7 +1527,7 @@ if (interpreter_frame != NULL) { #ifdef ASSERT - if (!EnableMethodHandles) + if (!EnableInvokeDynamic) // @@@ FIXME: Should we correct interpreter_frame_sender_sp in the calling sequences? // Probably, since deoptimization doesn't work yet. assert(caller->unextended_sp() == interpreter_frame->interpreter_frame_sender_sp(), "Frame not properly walkable");
--- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1541,7 +1541,7 @@ tempcount* Interpreter::stackElementWords + popframe_extra_args; if (interpreter_frame != NULL) { #ifdef ASSERT - if (!EnableMethodHandles) + if (!EnableInvokeDynamic) // @@@ FIXME: Should we correct interpreter_frame_sender_sp in the calling sequences? // Probably, since deoptimization doesn't work yet. assert(caller->unextended_sp() == interpreter_frame->interpreter_frame_sender_sp(), "Frame not properly walkable");
--- a/src/cpu/x86/vm/templateTable_x86_32.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/x86/vm/templateTable_x86_32.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "asm/assembler.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" #include "interpreter/templateTable.hpp" @@ -391,8 +392,8 @@ void TemplateTable::fast_aldc(bool wide) { transition(vtos, atos); - if (!EnableMethodHandles) { - // We should not encounter this bytecode if !EnableMethodHandles. + if (!EnableInvokeDynamic) { + // We should not encounter this bytecode if !EnableInvokeDynamic. // The verifier will stop it. However, if we get past the verifier, // this will stop the thread in a reasonable way, without crashing the JVM. __ call_VM(noreg, CAST_FROM_FN_PTR(address, @@ -1939,18 +1940,10 @@ __ movl(temp, Address(array, h, Address::times_8, 0*wordSize)); __ bswapl(temp); __ cmpl(key, temp); - if (VM_Version::supports_cmov()) { - __ cmovl(Assembler::less , j, h); // j = h if (key < array[h].fast_match()) - __ cmovl(Assembler::greaterEqual, i, h); // i = h if (key >= array[h].fast_match()) - } else { - Label set_i, end_of_if; - __ jccb(Assembler::greaterEqual, set_i); // { - __ mov(j, h); // j = h; - __ jmp(end_of_if); // } - __ bind(set_i); // else { - __ mov(i, h); // i = h; - __ bind(end_of_if); // } - } + // j = h if (key < array[h].fast_match()) + __ cmov32(Assembler::less , j, h); + // i = h if (key >= array[h].fast_match()) + __ cmov32(Assembler::greaterEqual, i, h); // while (i+1 < j) __ bind(entry); __ leal(h, Address(i, 1)); // i+1 @@ -3478,22 +3471,14 @@ // find a free slot in the monitor block (result in rdx) { Label entry, loop, exit; - __ movptr(rcx, monitor_block_top); // points to current entry, starting with top-most entry - __ lea(rbx, monitor_block_bot); // points to word before bottom of monitor block + __ movptr(rcx, monitor_block_top); // points to current entry, starting with top-most entry + + __ lea(rbx, monitor_block_bot); // points to word before bottom of monitor block __ jmpb(entry); __ bind(loop); __ cmpptr(Address(rcx, BasicObjectLock::obj_offset_in_bytes()), (int32_t)NULL_WORD); // check if current entry is used - -// TODO - need new func here - kbt - if (VM_Version::supports_cmov()) { - __ cmov(Assembler::equal, rdx, rcx); // if not used then remember entry in rdx - } else { - Label L; - __ jccb(Assembler::notEqual, L); - __ mov(rdx, rcx); // if not used then remember entry in rdx - __ bind(L); - } + __ cmovptr(Assembler::equal, rdx, rcx); // if not used then remember entry in rdx __ cmpptr(rax, Address(rcx, BasicObjectLock::obj_offset_in_bytes())); // check if current entry is for same object __ jccb(Assembler::equal, exit); // if same object then stop searching __ addptr(rcx, entry_size); // otherwise advance to next entry
--- a/src/cpu/x86/vm/templateTable_x86_64.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/x86/vm/templateTable_x86_64.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -405,8 +405,8 @@ void TemplateTable::fast_aldc(bool wide) { transition(vtos, atos); - if (!EnableMethodHandles) { - // We should not encounter this bytecode if !EnableMethodHandles. + if (!EnableInvokeDynamic) { + // We should not encounter this bytecode if !EnableInvokeDynamic. // The verifier will stop it. However, if we get past the verifier, // this will stop the thread in a reasonable way, without crashing the JVM. __ call_VM(noreg, CAST_FROM_FN_PTR(address,
--- a/src/cpu/x86/vm/vm_version_x86.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/x86/vm/vm_version_x86.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -429,6 +429,11 @@ UseXmmI2D = false; } } + if( FLAG_IS_DEFAULT(UseSSE42Intrinsics) ) { + if( supports_sse4_2() && UseSSE >= 4 ) { + UseSSE42Intrinsics = true; + } + } // Use count leading zeros count instruction if available. if (supports_lzcnt()) {
--- a/src/cpu/x86/vm/x86_32.ad Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/x86/vm/x86_32.ad Fri Apr 01 11:06:30 2011 +0100 @@ -1393,6 +1393,10 @@ // registers? True for Intel but false for most RISCs const bool Matcher::clone_shift_expressions = true; +// Do we need to mask the count passed to shift instructions or does +// the cpu only look at the lower 5/6 bits anyway? +const bool Matcher::need_masked_shift_count = false; + bool Matcher::narrow_oop_use_complex_address() { ShouldNotCallThis(); return true;
--- a/src/cpu/x86/vm/x86_64.ad Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/x86/vm/x86_64.ad Fri Apr 01 11:06:30 2011 +0100 @@ -574,12 +574,11 @@ // In os_cpu .ad file // int MachCallRuntimeNode::ret_addr_offset() -// Indicate if the safepoint node needs the polling page as an input. -// Since amd64 does not have absolute addressing but RIP-relative -// addressing and the polling page is within 2G, it doesn't. +// Indicate if the safepoint node needs the polling page as an input, +// it does if the polling page is more than disp32 away. bool SafePointNode::needs_polling_address_input() { - return false; + return Assembler::is_polling_page_far(); } // @@ -992,15 +991,21 @@ framesize -= 2*wordSize; if (framesize) { - st->print_cr("addq\trsp, %d\t# Destroy frame", framesize); + st->print_cr("addq rsp, %d\t# Destroy frame", framesize); st->print("\t"); } - st->print_cr("popq\trbp"); + st->print_cr("popq rbp"); if (do_polling() && C->is_method_compilation()) { - st->print_cr("\ttestl\trax, [rip + #offset_to_poll_page]\t" - "# Safepoint: poll for GC"); st->print("\t"); + if (Assembler::is_polling_page_far()) { + st->print_cr("movq rscratch1, #polling_page_address\n\t" + "testl rax, [rscratch1]\t" + "# Safepoint: poll for GC"); + } else { + st->print_cr("testl rax, [rip + #offset_to_poll_page]\t" + "# Safepoint: poll for GC"); + } } } #endif @@ -1033,45 +1038,22 @@ emit_opcode(cbuf, 0x58 | RBP_enc); if (do_polling() && C->is_method_compilation()) { - // testl %rax, off(%rip) // Opcode + ModRM + Disp32 == 6 bytes - // XXX reg_mem doesn't support RIP-relative addressing yet - cbuf.set_insts_mark(); - cbuf.relocate(cbuf.insts_mark(), relocInfo::poll_return_type, 0); // XXX - emit_opcode(cbuf, 0x85); // testl - emit_rm(cbuf, 0x0, RAX_enc, 0x5); // 00 rax 101 == 0x5 - // cbuf.insts_mark() is beginning of instruction - emit_d32_reloc(cbuf, os::get_polling_page()); -// relocInfo::poll_return_type, + MacroAssembler _masm(&cbuf); + AddressLiteral polling_page(os::get_polling_page(), relocInfo::poll_return_type); + if (Assembler::is_polling_page_far()) { + __ lea(rscratch1, polling_page); + __ relocate(relocInfo::poll_return_type); + __ testl(rax, Address(rscratch1, 0)); + } else { + __ testl(rax, polling_page); + } } } uint MachEpilogNode::size(PhaseRegAlloc* ra_) const { - Compile* C = ra_->C; - int framesize = C->frame_slots() << LogBytesPerInt; - assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned"); - // Remove word for return adr already pushed - // and RBP - framesize -= 2*wordSize; - - uint size = 0; - - if (do_polling() && C->is_method_compilation()) { - size += 6; - } - - // count popq rbp - size++; - - if (framesize) { - if (framesize < 0x80) { - size += 4; - } else if (framesize) { - size += 7; - } - } - - return size; + return MachNode::size(ra_); // too many variables; just compute it + // the hard way } int MachEpilogNode::reloc() const @@ -2000,6 +1982,10 @@ // into registers? True for Intel but false for most RISCs const bool Matcher::clone_shift_expressions = true; +// Do we need to mask the count passed to shift instructions or does +// the cpu only look at the lower 5/6 bits anyway? +const bool Matcher::need_masked_shift_count = false; + bool Matcher::narrow_oop_use_complex_address() { assert(UseCompressedOops, "only for compressed oops code"); return (LogMinObjAlignmentInBytes <= 3); @@ -3406,8 +3392,8 @@ } if (EmitSync & 1) { // Without cast to int32_t a movptr will destroy r10 which is typically obj - masm.movptr (Address(boxReg, 0), (int32_t)intptr_t(markOopDesc::unused_mark())) ; - masm.cmpptr(rsp, (int32_t)NULL_WORD) ; + masm.movptr (Address(boxReg, 0), (int32_t)intptr_t(markOopDesc::unused_mark())) ; + masm.cmpptr(rsp, (int32_t)NULL_WORD) ; } else if (EmitSync & 2) { Label DONE_LABEL; @@ -3435,10 +3421,10 @@ } else { Label DONE_LABEL, IsInflated, Egress; - masm.movptr(tmpReg, Address(objReg, 0)) ; + masm.movptr(tmpReg, Address(objReg, 0)) ; masm.testl (tmpReg, 0x02) ; // inflated vs stack-locked|neutral|biased - masm.jcc (Assembler::notZero, IsInflated) ; - + masm.jcc (Assembler::notZero, IsInflated) ; + // it's stack-locked, biased or neutral // TODO: optimize markword triage order to reduce the number of // conditional branches in the most common cases. @@ -3452,9 +3438,9 @@ } // was q will it destroy high? - masm.orl (tmpReg, 1) ; - masm.movptr(Address(boxReg, 0), tmpReg) ; - if (os::is_MP()) { masm.lock(); } + masm.orl (tmpReg, 1) ; + masm.movptr(Address(boxReg, 0), tmpReg) ; + if (os::is_MP()) { masm.lock(); } masm.cmpxchgptr(boxReg, Address(objReg, 0)); // Updates tmpReg if (_counters != NULL) { masm.cond_inc32(Assembler::equal, @@ -3481,16 +3467,16 @@ // fetched _owner. If the CAS is successful we may // avoid an RTO->RTS upgrade on the $line. // Without cast to int32_t a movptr will destroy r10 which is typically obj - masm.movptr(Address(boxReg, 0), (int32_t)intptr_t(markOopDesc::unused_mark())) ; - - masm.mov (boxReg, tmpReg) ; - masm.movptr (tmpReg, Address(tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)) ; - masm.testptr(tmpReg, tmpReg) ; - masm.jcc (Assembler::notZero, DONE_LABEL) ; + masm.movptr(Address(boxReg, 0), (int32_t)intptr_t(markOopDesc::unused_mark())) ; + + masm.mov (boxReg, tmpReg) ; + masm.movptr (tmpReg, Address(tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)) ; + masm.testptr(tmpReg, tmpReg) ; + masm.jcc (Assembler::notZero, DONE_LABEL) ; // It's inflated and appears unlocked - if (os::is_MP()) { masm.lock(); } - masm.cmpxchgptr(r15_thread, Address(boxReg, ObjectMonitor::owner_offset_in_bytes()-2)) ; + if (os::is_MP()) { masm.lock(); } + masm.cmpxchgptr(r15_thread, Address(boxReg, ObjectMonitor::owner_offset_in_bytes()-2)) ; // Intentional fall-through into DONE_LABEL ... masm.bind (DONE_LABEL) ; @@ -3509,8 +3495,8 @@ Register tmpReg = as_Register($tmp$$reg); MacroAssembler masm(&cbuf); - if (EmitSync & 4) { - masm.cmpptr(rsp, 0) ; + if (EmitSync & 4) { + masm.cmpptr(rsp, 0) ; } else if (EmitSync & 8) { Label DONE_LABEL; @@ -3537,25 +3523,25 @@ if (UseBiasedLocking && !UseOptoBiasInlining) { masm.biased_locking_exit(objReg, tmpReg, DONE_LABEL); } - - masm.movptr(tmpReg, Address(objReg, 0)) ; - masm.cmpptr(Address(boxReg, 0), (int32_t)NULL_WORD) ; - masm.jcc (Assembler::zero, DONE_LABEL) ; - masm.testl (tmpReg, 0x02) ; - masm.jcc (Assembler::zero, Stacked) ; - + + masm.movptr(tmpReg, Address(objReg, 0)) ; + masm.cmpptr(Address(boxReg, 0), (int32_t)NULL_WORD) ; + masm.jcc (Assembler::zero, DONE_LABEL) ; + masm.testl (tmpReg, 0x02) ; + masm.jcc (Assembler::zero, Stacked) ; + // It's inflated - masm.movptr(boxReg, Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)) ; - masm.xorptr(boxReg, r15_thread) ; - masm.orptr (boxReg, Address (tmpReg, ObjectMonitor::recursions_offset_in_bytes()-2)) ; - masm.jcc (Assembler::notZero, DONE_LABEL) ; - masm.movptr(boxReg, Address (tmpReg, ObjectMonitor::cxq_offset_in_bytes()-2)) ; - masm.orptr (boxReg, Address (tmpReg, ObjectMonitor::EntryList_offset_in_bytes()-2)) ; - masm.jcc (Assembler::notZero, CheckSucc) ; - masm.movptr(Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2), (int32_t)NULL_WORD) ; - masm.jmp (DONE_LABEL) ; - - if ((EmitSync & 65536) == 0) { + masm.movptr(boxReg, Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)) ; + masm.xorptr(boxReg, r15_thread) ; + masm.orptr (boxReg, Address (tmpReg, ObjectMonitor::recursions_offset_in_bytes()-2)) ; + masm.jcc (Assembler::notZero, DONE_LABEL) ; + masm.movptr(boxReg, Address (tmpReg, ObjectMonitor::cxq_offset_in_bytes()-2)) ; + masm.orptr (boxReg, Address (tmpReg, ObjectMonitor::EntryList_offset_in_bytes()-2)) ; + masm.jcc (Assembler::notZero, CheckSucc) ; + masm.movptr(Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2), (int32_t)NULL_WORD) ; + masm.jmp (DONE_LABEL) ; + + if ((EmitSync & 65536) == 0) { Label LSuccess, LGoSlowPath ; masm.bind (CheckSucc) ; masm.cmpptr(Address (tmpReg, ObjectMonitor::succ_offset_in_bytes()-2), (int32_t)NULL_WORD) ; @@ -3587,9 +3573,9 @@ masm.jmp (DONE_LABEL) ; } - masm.bind (Stacked) ; + masm.bind (Stacked) ; masm.movptr(tmpReg, Address (boxReg, 0)) ; // re-fetch - if (os::is_MP()) { masm.lock(); } + if (os::is_MP()) { masm.lock(); } masm.cmpxchgptr(tmpReg, Address(objReg, 0)); // Uses RAX which is box if (EmitSync & 65536) { @@ -3910,22 +3896,6 @@ // done: %} - - // Safepoint Poll. This polls the safepoint page, and causes an - // exception if it is not readable. Unfortunately, it kills - // RFLAGS in the process. - enc_class enc_safepoint_poll - %{ - // testl %rax, off(%rip) // Opcode + ModRM + Disp32 == 6 bytes - // XXX reg_mem doesn't support RIP-relative addressing yet - cbuf.set_insts_mark(); - cbuf.relocate(cbuf.insts_mark(), relocInfo::poll_type, 0); // XXX - emit_opcode(cbuf, 0x85); // testl - emit_rm(cbuf, 0x0, RAX_enc, 0x5); // 00 rax 101 == 0x5 - // cbuf.insts_mark() is beginning of instruction - emit_d32_reloc(cbuf, os::get_polling_page()); -// relocInfo::poll_type, - %} %} @@ -4229,6 +4199,15 @@ interface(CONST_INTER); %} +operand immP_poll() %{ + predicate(n->get_ptr() != 0 && n->get_ptr() == (intptr_t)os::get_polling_page()); + match(ConP); + + // formats are generated automatically for constants and base registers + format %{ %} + interface(CONST_INTER); +%} + // Pointer Immediate operand immN() %{ match(ConN); @@ -4836,7 +4815,7 @@ %} // Double register operands -operand regD() +operand regD() %{ constraint(ALLOC_IN_RC(double_reg)); match(RegD); @@ -6564,6 +6543,16 @@ ins_pipe(ialu_reg); %} +instruct loadConP_poll(rRegP dst, immP_poll src) %{ + match(Set dst src); + format %{ "movq $dst, $src\t!ptr" %} + ins_encode %{ + AddressLiteral polling_page(os::get_polling_page(), relocInfo::poll_type); + __ lea($dst$$Register, polling_page); + %} + ins_pipe(ialu_reg_fat); +%} + instruct loadConP31(rRegP dst, immP31 src, rFlagsReg cr) %{ match(Set dst src); @@ -7237,11 +7226,11 @@ instruct bytes_reverse_unsigned_short(rRegI dst) %{ match(Set dst (ReverseBytesUS dst)); - format %{ "bswapl $dst\n\t" + format %{ "bswapl $dst\n\t" "shrl $dst,16\n\t" %} ins_encode %{ __ bswapl($dst$$Register); - __ shrl($dst$$Register, 16); + __ shrl($dst$$Register, 16); %} ins_pipe( ialu_reg ); %} @@ -7249,11 +7238,11 @@ instruct bytes_reverse_short(rRegI dst) %{ match(Set dst (ReverseBytesS dst)); - format %{ "bswapl $dst\n\t" + format %{ "bswapl $dst\n\t" "sar $dst,16\n\t" %} ins_encode %{ __ bswapl($dst$$Register); - __ sarl($dst$$Register, 16); + __ sarl($dst$$Register, 16); %} ins_pipe( ialu_reg ); %} @@ -7476,7 +7465,7 @@ effect(KILL cr); ins_cost(400); - format %{ + format %{ $$template if (os::is_MP()) { $$emit$$"lock addl [rsp + #0], 0\t! membar_volatile" @@ -8287,7 +8276,7 @@ rFlagsReg cr) %{ match(Set cr (StorePConditional heap_top_ptr (Binary oldval newval))); - + format %{ "cmpxchgq $heap_top_ptr, $newval\t# (ptr) " "If rax == $heap_top_ptr then store $newval into $heap_top_ptr" %} opcode(0x0F, 0xB1); @@ -9850,9 +9839,9 @@ // Xor Register with Immediate -1 instruct xorI_rReg_im1(rRegI dst, immI_M1 imm) %{ - match(Set dst (XorI dst imm)); - - format %{ "not $dst" %} + match(Set dst (XorI dst imm)); + + format %{ "not $dst" %} ins_encode %{ __ notl($dst$$Register); %} @@ -10093,9 +10082,9 @@ // Xor Register with Immediate -1 instruct xorL_rReg_im1(rRegL dst, immL_M1 imm) %{ - match(Set dst (XorL dst imm)); - - format %{ "notq $dst" %} + match(Set dst (XorL dst imm)); + + format %{ "notq $dst" %} ins_encode %{ __ notq($dst$$Register); %} @@ -12469,14 +12458,33 @@ // Safepoint Instructions instruct safePoint_poll(rFlagsReg cr) %{ + predicate(!Assembler::is_polling_page_far()); match(SafePoint); effect(KILL cr); - format %{ "testl rax, [rip + #offset_to_poll_page]\t" + format %{ "testl rax, [rip + #offset_to_poll_page]\t" "# Safepoint: poll for GC" %} - size(6); // Opcode + ModRM + Disp32 == 6 bytes ins_cost(125); - ins_encode(enc_safepoint_poll); + ins_encode %{ + AddressLiteral addr(os::get_polling_page(), relocInfo::poll_type); + __ testl(rax, addr); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct safePoint_poll_far(rFlagsReg cr, rRegP poll) +%{ + predicate(Assembler::is_polling_page_far()); + match(SafePoint poll); + effect(KILL cr, USE poll); + + format %{ "testl rax, [$poll]\t" + "# Safepoint: poll for GC" %} + ins_cost(125); + ins_encode %{ + __ relocate(relocInfo::poll_type); + __ testl(rax, Address($poll$$Register, 0)); + %} ins_pipe(ialu_reg_mem); %}
--- a/src/cpu/zero/vm/cppInterpreter_zero.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/cpu/zero/vm/cppInterpreter_zero.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, 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. * @@ -303,7 +303,7 @@ if (method->is_static()) { istate->set_oop_temp( - method->constants()->pool_holder()->klass_part()->java_mirror()); + method->constants()->pool_holder()->java_mirror()); mirror = istate->oop_temp_addr(); *(dst++) = &mirror; } @@ -1192,7 +1192,7 @@ (BasicObjectLock *) stack->alloc(monitor_words * wordSize); oop object; if (method->is_static()) - object = method->constants()->pool_holder()->klass_part()->java_mirror(); + object = method->constants()->pool_holder()->java_mirror(); else object = (oop) locals[0]; monitor->set_obj(object);
--- a/src/os/solaris/dtrace/libjvm_db.c Fri Apr 01 10:58:10 2011 +0100 +++ b/src/os/solaris/dtrace/libjvm_db.c Fri Apr 01 11:06:30 2011 +0100 @@ -524,6 +524,8 @@ CHECK_FAIL(err); err = read_pointer(J, constantPool + nameIndex * POINTER_SIZE + SIZE_constantPoolOopDesc, &nameSymbol); CHECK_FAIL(err); + // The symbol is a CPSlot and has lower bit set to indicate metadata + nameSymbol &= (~1); // remove metadata lsb err = ps_pread(J->P, nameSymbol + OFFSET_Symbol_length, &nameSymbolLength, 2); CHECK_FAIL(err); nameString = (char*)calloc(nameSymbolLength + 1, 1); @@ -535,6 +537,7 @@ CHECK_FAIL(err); err = read_pointer(J, constantPool + signatureIndex * POINTER_SIZE + SIZE_constantPoolOopDesc, &signatureSymbol); CHECK_FAIL(err); + signatureSymbol &= (~1); // remove metadata lsb err = ps_pread(J->P, signatureSymbol + OFFSET_Symbol_length, &signatureSymbolLength, 2); CHECK_FAIL(err); signatureString = (char*)calloc(signatureSymbolLength + 1, 1);
--- a/src/os/windows/vm/os_windows.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/os/windows/vm/os_windows.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -3297,9 +3297,14 @@ "possibility of dangling Thread pointer"); OSThread* osthread = thread->osthread(); - bool interrupted; - interrupted = osthread->interrupted(); - if (clear_interrupted == true) { + bool interrupted = osthread->interrupted(); + // There is no synchronization between the setting of the interrupt + // and it being cleared here. It is critical - see 6535709 - that + // we only clear the interrupt state, and reset the interrupt event, + // if we are going to report that we were indeed interrupted - else + // an interrupt can be "lost", leading to spurious wakeups or lost wakeups + // depending on the timing + if (interrupted && clear_interrupted) { osthread->set_interrupted(false); ResetEvent(osthread->interrupt_event()); } // Otherwise leave the interrupted state alone
--- a/src/share/vm/adlc/main.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/adlc/main.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -240,6 +240,11 @@ AD.addInclude(AD._CPP_file, "nativeInst_sparc.hpp"); AD.addInclude(AD._CPP_file, "vmreg_sparc.inline.hpp"); #endif +#ifdef TARGET_ARCH_arm + AD.addInclude(AD._CPP_file, "assembler_arm.inline.hpp"); + AD.addInclude(AD._CPP_file, "nativeInst_arm.hpp"); + AD.addInclude(AD._CPP_file, "vmreg_arm.inline.hpp"); +#endif AD.addInclude(AD._HPP_file, "memory/allocation.hpp"); AD.addInclude(AD._HPP_file, "opto/machnode.hpp"); AD.addInclude(AD._HPP_file, "opto/node.hpp");
--- a/src/share/vm/c1/c1_GraphBuilder.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/c1/c1_GraphBuilder.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -30,6 +30,7 @@ #include "c1/c1_InstructionPrinter.hpp" #include "ci/ciField.hpp" #include "ci/ciKlass.hpp" +#include "compiler/compileBroker.hpp" #include "interpreter/bytecode.hpp" #include "runtime/sharedRuntime.hpp" #include "utilities/bitMap.inline.hpp" @@ -1471,9 +1472,9 @@ if (code == Bytecodes::_getstatic || code == Bytecodes::_putstatic) { if (state_before != NULL) { // build a patching constant - obj = new Constant(new ClassConstant(holder), state_before); + obj = new Constant(new InstanceConstant(holder->java_mirror()), state_before); } else { - obj = new Constant(new ClassConstant(holder)); + obj = new Constant(new InstanceConstant(holder->java_mirror())); } } @@ -3775,24 +3776,7 @@ #ifndef PRODUCT void GraphBuilder::print_inline_result(ciMethod* callee, bool res) { - const char sync_char = callee->is_synchronized() ? 's' : ' '; - const char exception_char = callee->has_exception_handlers() ? '!' : ' '; - const char monitors_char = callee->has_monitor_bytecodes() ? 'm' : ' '; - tty->print(" %c%c%c ", sync_char, exception_char, monitors_char); - for (int i = 0; i < scope()->level(); i++) tty->print(" "); - if (res) { - tty->print(" "); - } else { - tty->print("- "); - } - tty->print("@ %d ", bci()); - callee->print_short_name(); - tty->print(" (%d bytes)", callee->code_size()); - if (_inline_bailout_msg) { - tty->print(" %s", _inline_bailout_msg); - } - tty->cr(); - + CompileTask::print_inlining(callee, scope()->level(), bci(), _inline_bailout_msg); if (res && CIPrintMethodCodes) { callee->print_codes(); }
--- a/src/share/vm/c1/c1_LinearScan.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/c1/c1_LinearScan.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -2703,7 +2703,7 @@ assert(_fpu_stack_allocator != NULL, "must be present"); opr = _fpu_stack_allocator->to_fpu_stack(opr); - assert(opr->fpu_regnrLo() == opr->fpu_regnrHi(), "assumed in calculation (only fpu_regnrHi is used)"); + assert(opr->fpu_regnrLo() == opr->fpu_regnrHi(), "assumed in calculation (only fpu_regnrLo is used)"); #endif #ifdef SPARC assert(opr->fpu_regnrLo() == opr->fpu_regnrHi() + 1, "assumed in calculation (only fpu_regnrHi is used)"); @@ -2715,7 +2715,12 @@ assert(opr->fpu_regnrLo() == opr->fpu_regnrHi(), "assumed in calculation (only fpu_regnrHi is used)"); #endif +#ifdef VM_LITTLE_ENDIAN + VMReg rname_first = frame_map()->fpu_regname(opr->fpu_regnrLo()); +#else VMReg rname_first = frame_map()->fpu_regname(opr->fpu_regnrHi()); +#endif + #ifdef _LP64 first = new LocationValue(Location::new_reg_loc(Location::dbl, rname_first)); second = &_int_0_scope_value;
--- a/src/share/vm/c1/c1_Runtime1.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/c1/c1_Runtime1.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -808,7 +808,7 @@ { klassOop klass = resolve_field_return_klass(caller_method, bci, CHECK); // Save a reference to the class that has to be checked for initialization init_klass = KlassHandle(THREAD, klass); - k = klass; + k = klass->java_mirror(); } break; case Bytecodes::_new:
--- a/src/share/vm/ci/ciCPCache.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/ci/ciCPCache.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2011, 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,8 +46,7 @@ // ciCPCache::is_f1_null_at bool ciCPCache::is_f1_null_at(int index) { VM_ENTRY_MARK; - oop f1 = entry_at(index)->f1(); - return (f1 == NULL); + return entry_at(index)->is_f1_null(); }
--- a/src/share/vm/ci/ciField.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/ci/ciField.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -213,7 +213,7 @@ // may change. The three examples are java.lang.System.in, // java.lang.System.out, and java.lang.System.err. - Handle k = _holder->get_klassOop(); + KlassHandle k = _holder->get_klassOop(); assert( SystemDictionary::System_klass() != NULL, "Check once per vm"); if( k() == SystemDictionary::System_klass() ) { // Check offsets for case 2: System.in, System.out, or System.err @@ -225,36 +225,38 @@ } } + Handle mirror = k->java_mirror(); + _is_constant = true; switch(type()->basic_type()) { case T_BYTE: - _constant_value = ciConstant(type()->basic_type(), k->byte_field(_offset)); + _constant_value = ciConstant(type()->basic_type(), mirror->byte_field(_offset)); break; case T_CHAR: - _constant_value = ciConstant(type()->basic_type(), k->char_field(_offset)); + _constant_value = ciConstant(type()->basic_type(), mirror->char_field(_offset)); break; case T_SHORT: - _constant_value = ciConstant(type()->basic_type(), k->short_field(_offset)); + _constant_value = ciConstant(type()->basic_type(), mirror->short_field(_offset)); break; case T_BOOLEAN: - _constant_value = ciConstant(type()->basic_type(), k->bool_field(_offset)); + _constant_value = ciConstant(type()->basic_type(), mirror->bool_field(_offset)); break; case T_INT: - _constant_value = ciConstant(type()->basic_type(), k->int_field(_offset)); + _constant_value = ciConstant(type()->basic_type(), mirror->int_field(_offset)); break; case T_FLOAT: - _constant_value = ciConstant(k->float_field(_offset)); + _constant_value = ciConstant(mirror->float_field(_offset)); break; case T_DOUBLE: - _constant_value = ciConstant(k->double_field(_offset)); + _constant_value = ciConstant(mirror->double_field(_offset)); break; case T_LONG: - _constant_value = ciConstant(k->long_field(_offset)); + _constant_value = ciConstant(mirror->long_field(_offset)); break; case T_OBJECT: case T_ARRAY: { - oop o = k->obj_field(_offset); + oop o = mirror->obj_field(_offset); // A field will be "constant" if it is known always to be // a non-null reference to an instance of a particular class,
--- a/src/share/vm/ci/ciInstance.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/ci/ciInstance.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, 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 @@ -138,3 +138,9 @@ st->print(" type="); klass()->print(st); } + + +ciKlass* ciInstance::java_lang_Class_klass() { + VM_ENTRY_MARK; + return CURRENT_ENV->get_object(java_lang_Class::as_klassOop(get_oop()))->as_klass(); +}
--- a/src/share/vm/ci/ciInstance.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/ci/ciInstance.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, 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 @@ -64,6 +64,8 @@ // Constant value of a field at the specified offset. ciConstant field_value_by_offset(int field_offset); + + ciKlass* java_lang_Class_klass(); }; #endif // SHARE_VM_CI_CIINSTANCE_HPP
--- a/src/share/vm/ci/ciInstanceKlass.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/ci/ciInstanceKlass.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, 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 @@ -85,7 +85,6 @@ if (h_k() != SystemDictionary::Object_klass()) { super(); } - java_mirror(); //compute_nonstatic_fields(); // done outside of constructor } @@ -320,6 +319,9 @@ // Get the instance of java.lang.Class corresponding to this klass. // Cache it on this->_java_mirror. ciInstance* ciInstanceKlass::java_mirror() { + if (is_shared()) { + return ciKlass::java_mirror(); + } if (_java_mirror == NULL) { _java_mirror = ciKlass::java_mirror(); }
--- a/src/share/vm/ci/ciObjectFactory.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/ci/ciObjectFactory.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -663,7 +663,7 @@ if (key->is_perm() && _non_perm_count == 0) { return emptyBucket; } else if (key->is_instance()) { - if (key->klass() == SystemDictionary::Class_klass()) { + if (key->klass() == SystemDictionary::Class_klass() && JavaObjectsInPerm) { // class mirror instances are always perm return emptyBucket; }
--- a/src/share/vm/ci/ciTypeFlow.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/ci/ciTypeFlow.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1871,7 +1871,8 @@ // ------------------------------------------------------------------ // ciTypeFlow::Block::print_on void ciTypeFlow::Block::print_on(outputStream* st) const { - if ((Verbose || WizardMode)) { + if ((Verbose || WizardMode) && (limit() >= 0)) { + // Don't print 'dummy' blocks (i.e. blocks with limit() '-1') outer()->method()->print_codes_on(start(), limit(), st); } st->print_cr(" ==================================================== ");
--- a/src/share/vm/classfile/classFileParser.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/classfile/classFileParser.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -37,6 +37,7 @@ #include "memory/universe.inline.hpp" #include "oops/constantPoolOop.hpp" #include "oops/instanceKlass.hpp" +#include "oops/instanceMirrorKlass.hpp" #include "oops/klass.inline.hpp" #include "oops/klassOop.hpp" #include "oops/klassVtable.hpp" @@ -151,7 +152,7 @@ "Class file version does not support constant tag %u in class file %s", tag, CHECK); } - if (!EnableMethodHandles) { + if (!EnableInvokeDynamic) { classfile_parse_error( "This JVM does not support constant tag %u in class file %s", tag, CHECK); @@ -259,7 +260,7 @@ verify_legal_utf8((unsigned char*)utf8_buffer, utf8_length, CHECK); } - if (AnonymousClasses && has_cp_patch_at(index)) { + if (EnableInvokeDynamic && has_cp_patch_at(index)) { Handle patch = clear_cp_patch_at(index); guarantee_property(java_lang_String::is_instance(patch()), "Illegal utf8 patch at %d in class file %s", @@ -442,7 +443,7 @@ int ref_index = cp->method_handle_index_at(index); check_property( valid_cp_range(ref_index, length) && - EnableMethodHandles, + EnableInvokeDynamic, "Invalid constant pool index %u in class file %s", ref_index, CHECK_(nullHandle)); constantTag tag = cp->tag_at(ref_index); @@ -486,7 +487,7 @@ check_property( valid_cp_range(ref_index, length) && cp->tag_at(ref_index).is_utf8() && - EnableMethodHandles, + EnableInvokeDynamic, "Invalid constant pool index %u in class file %s", ref_index, CHECK_(nullHandle)); } @@ -521,7 +522,7 @@ if (_cp_patches != NULL) { // need to treat this_class specially... - assert(AnonymousClasses, ""); + assert(EnableInvokeDynamic, ""); int this_class_index; { cfs->guarantee_more(8, CHECK_(nullHandle)); // flags, this_class, super_class, infs_len @@ -676,7 +677,7 @@ void ClassFileParser::patch_constant_pool(constantPoolHandle cp, int index, Handle patch, TRAPS) { - assert(AnonymousClasses, ""); + assert(EnableInvokeDynamic, ""); BasicType patch_type = T_VOID; switch (cp->tag_at(index).value()) { @@ -2102,7 +2103,7 @@ _has_vanilla_constructor = true; } - if (EnableMethodHandles && (m->is_method_handle_invoke() || + if (EnableInvokeDynamic && (m->is_method_handle_invoke() || m->is_method_handle_adapter())) { THROW_MSG_(vmSymbols::java_lang_VirtualMachineError(), "Method handle invokers must be defined internally to the VM", nullHandle); @@ -2606,54 +2607,6 @@ } -static void initialize_static_field(fieldDescriptor* fd, TRAPS) { - KlassHandle h_k (THREAD, fd->field_holder()); - assert(h_k.not_null() && fd->is_static(), "just checking"); - if (fd->has_initial_value()) { - BasicType t = fd->field_type(); - switch (t) { - case T_BYTE: - h_k()->byte_field_put(fd->offset(), fd->int_initial_value()); - break; - case T_BOOLEAN: - h_k()->bool_field_put(fd->offset(), fd->int_initial_value()); - break; - case T_CHAR: - h_k()->char_field_put(fd->offset(), fd->int_initial_value()); - break; - case T_SHORT: - h_k()->short_field_put(fd->offset(), fd->int_initial_value()); - break; - case T_INT: - h_k()->int_field_put(fd->offset(), fd->int_initial_value()); - break; - case T_FLOAT: - h_k()->float_field_put(fd->offset(), fd->float_initial_value()); - break; - case T_DOUBLE: - h_k()->double_field_put(fd->offset(), fd->double_initial_value()); - break; - case T_LONG: - h_k()->long_field_put(fd->offset(), fd->long_initial_value()); - break; - case T_OBJECT: - { - #ifdef ASSERT - TempNewSymbol sym = SymbolTable::new_symbol("Ljava/lang/String;", CHECK); - assert(fd->signature() == sym, "just checking"); - #endif - oop string = fd->string_initial_value(CHECK); - h_k()->obj_field_put(fd->offset(), string); - } - break; - default: - THROW_MSG(vmSymbols::java_lang_ClassFormatError(), - "Illegal ConstantValue attribute in class file"); - } - } -} - - void ClassFileParser::java_lang_ref_Reference_fix_pre(typeArrayHandle* fields_ptr, constantPoolHandle cp, FieldAllocationCount *fac_ptr, TRAPS) { // This code is for compatibility with earlier jdk's that do not @@ -2769,8 +2722,8 @@ } -void ClassFileParser::java_lang_Class_fix_pre(objArrayHandle* methods_ptr, - FieldAllocationCount *fac_ptr, TRAPS) { +void ClassFileParser::java_lang_Class_fix_pre(int* nonstatic_field_size, + FieldAllocationCount *fac_ptr) { // Add fake fields for java.lang.Class instances // // This is not particularly nice. We should consider adding a @@ -2787,10 +2740,13 @@ // versions because when the offsets are computed at bootstrap // time we don't know yet which version of the JDK we're running in. - // The values below are fake but will force two non-static oop fields and + // The values below are fake but will force three non-static oop fields and // a corresponding non-static oop map block to be allocated. const int extra = java_lang_Class::number_of_fake_oop_fields; fac_ptr->nonstatic_oop_count += extra; + + // Reserve some leading space for fake ints + *nonstatic_field_size += align_size_up(java_lang_Class::hc_number_of_fake_int_fields * BytesPerInt, heapOopSize) / heapOopSize; } @@ -2815,7 +2771,7 @@ // This is not particularly nice, but since there is no way to express // a native wordSize field in Java, we must do it at this level. - if (!EnableMethodHandles) return; + if (!EnableInvokeDynamic) return; int word_sig_index = 0; const int cp_size = cp->length(); @@ -3205,9 +3161,7 @@ int next_nonstatic_field_offset; // Calculate the starting byte offsets - next_static_oop_offset = (instanceKlass::header_size() + - align_object_offset(vtable_size) + - align_object_offset(itable_size)) * wordSize; + next_static_oop_offset = instanceMirrorKlass::offset_of_static_fields(); next_static_double_offset = next_static_oop_offset + (fac.static_oop_count * heapOopSize); if ( fac.static_double_count && @@ -3226,25 +3180,26 @@ fac.static_byte_count ), wordSize ); static_field_size = (next_static_type_offset - next_static_oop_offset) / wordSize; - first_nonstatic_field_offset = instanceOopDesc::base_offset_in_bytes() + - nonstatic_field_size * heapOopSize; - next_nonstatic_field_offset = first_nonstatic_field_offset; // Add fake fields for java.lang.Class instances (also see below) if (class_name == vmSymbols::java_lang_Class() && class_loader.is_null()) { - java_lang_Class_fix_pre(&methods, &fac, CHECK_(nullHandle)); + java_lang_Class_fix_pre(&nonstatic_field_size, &fac); } + first_nonstatic_field_offset = instanceOopDesc::base_offset_in_bytes() + + nonstatic_field_size * heapOopSize; + next_nonstatic_field_offset = first_nonstatic_field_offset; + // adjust the vmentry field declaration in java.lang.invoke.MethodHandle - if (EnableMethodHandles && class_name == vmSymbols::java_lang_invoke_MethodHandle() && class_loader.is_null()) { + if (EnableInvokeDynamic && class_name == vmSymbols::java_lang_invoke_MethodHandle() && class_loader.is_null()) { java_lang_invoke_MethodHandle_fix_pre(cp, fields, &fac, CHECK_(nullHandle)); } if (AllowTransitionalJSR292 && - EnableMethodHandles && class_name == vmSymbols::java_dyn_MethodHandle() && class_loader.is_null()) { + EnableInvokeDynamic && class_name == vmSymbols::java_dyn_MethodHandle() && class_loader.is_null()) { java_lang_invoke_MethodHandle_fix_pre(cp, fields, &fac, CHECK_(nullHandle)); } if (AllowTransitionalJSR292 && - EnableMethodHandles && class_name == vmSymbols::sun_dyn_MethodHandleImpl() && class_loader.is_null()) { + EnableInvokeDynamic && class_name == vmSymbols::sun_dyn_MethodHandleImpl() && class_loader.is_null()) { // allow vmentry field in MethodHandleImpl also java_lang_invoke_MethodHandle_fix_pre(cp, fields, &fac, CHECK_(nullHandle)); } @@ -3566,7 +3521,7 @@ } // We can now create the basic klassOop for this klass - klassOop ik = oopFactory::new_instanceKlass(vtable_size, itable_size, + klassOop ik = oopFactory::new_instanceKlass(name, vtable_size, itable_size, static_field_size, total_oop_map_count, rt, CHECK_(nullHandle)); @@ -3588,7 +3543,7 @@ this_klass->set_class_loader(class_loader()); this_klass->set_nonstatic_field_size(nonstatic_field_size); this_klass->set_has_nonstatic_fields(has_nonstatic_fields); - this_klass->set_static_oop_field_size(fac.static_oop_count); + this_klass->set_static_oop_field_count(fac.static_oop_count); cp->set_pool_holder(this_klass()); error_handler.set_in_error(false); // turn off error handler for cp this_klass->set_constants(cp()); @@ -3649,9 +3604,6 @@ // Make sure this is the end of class file stream guarantee_property(cfs->at_eos(), "Extra bytes at the end of class file %s", CHECK_(nullHandle)); - // Initialize static fields - this_klass->do_local_static_fields(&initialize_static_field, CHECK_(nullHandle)); - // VerifyOops believes that once this has been set, the object is completely loaded. // Compute transitive closure of interfaces this class implements this_klass->set_transitive_interfaces(transitive_interfaces()); @@ -3685,6 +3637,9 @@ check_illegal_static_method(this_klass, CHECK_(nullHandle)); } + // Allocate mirror and initialize static fields + java_lang_Class::create_mirror(this_klass, CHECK_(nullHandle)); + ClassLoadingService::notify_class_loaded(instanceKlass::cast(this_klass()), false /* not shared class */);
--- a/src/share/vm/classfile/classFileParser.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/classfile/classFileParser.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -154,11 +154,12 @@ // Add the "discovered" field to java.lang.ref.Reference if // it does not exist. void java_lang_ref_Reference_fix_pre(typeArrayHandle* fields_ptr, - constantPoolHandle cp, FieldAllocationCount *fac_ptr, TRAPS); + constantPoolHandle cp, + FieldAllocationCount *fac_ptr, TRAPS); // Adjust the field allocation counts for java.lang.Class to add // fake fields. - void java_lang_Class_fix_pre(objArrayHandle* methods_ptr, - FieldAllocationCount *fac_ptr, TRAPS); + void java_lang_Class_fix_pre(int* nonstatic_field_size, + FieldAllocationCount *fac_ptr); // Adjust the next_nonstatic_oop_offset to place the fake fields // before any Java fields. void java_lang_Class_fix_post(int* next_nonstatic_oop_offset); @@ -230,11 +231,11 @@ char* skip_over_field_signature(char* signature, bool void_ok, unsigned int length, TRAPS); bool is_anonymous() { - assert(AnonymousClasses || _host_klass.is_null(), ""); + assert(EnableInvokeDynamic || _host_klass.is_null(), ""); return _host_klass.not_null(); } bool has_cp_patch_at(int index) { - assert(AnonymousClasses, ""); + assert(EnableInvokeDynamic, ""); assert(index >= 0, "oob"); return (_cp_patches != NULL && index < _cp_patches->length() @@ -257,7 +258,7 @@ // constant pool construction, but in later versions they can. // %%% Let's phase out the old is_klass_reference. bool is_klass_reference(constantPoolHandle cp, int index) { - return ((LinkWellKnownClasses || AnonymousClasses) + return ((LinkWellKnownClasses || EnableInvokeDynamic) ? cp->tag_at(index).is_klass_or_reference() : cp->tag_at(index).is_klass_reference()); }
--- a/src/share/vm/classfile/javaClasses.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/classfile/javaClasses.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -33,6 +33,7 @@ #include "memory/resourceArea.hpp" #include "memory/universe.inline.hpp" #include "oops/instanceKlass.hpp" +#include "oops/instanceMirrorKlass.hpp" #include "oops/klass.hpp" #include "oops/klassOop.hpp" #include "oops/methodOop.hpp" @@ -161,7 +162,7 @@ } Handle java_lang_String::create_tenured_from_unicode(jchar* unicode, int length, TRAPS) { - return basic_create_from_unicode(unicode, length, true, CHECK_NH); + return basic_create_from_unicode(unicode, length, JavaObjectsInPerm, CHECK_NH); } oop java_lang_String::create_oop_from_unicode(jchar* unicode, int length, TRAPS) { @@ -300,6 +301,15 @@ return result; } +unsigned int java_lang_String::hash_string(oop java_string) { + typeArrayOop value = java_lang_String::value(java_string); + int offset = java_lang_String::offset(java_string); + int length = java_lang_String::length(java_string); + + if (length == 0) return 0; + return hash_string(value->char_at_addr(offset), length); +} + Symbol* java_lang_String::as_symbol(Handle java_string, TRAPS) { oop obj = java_string(); typeArrayOop value = java_lang_String::value(obj); @@ -391,6 +401,75 @@ } } +static void initialize_static_field(fieldDescriptor* fd, TRAPS) { + Handle mirror (THREAD, fd->field_holder()->java_mirror()); + assert(mirror.not_null() && fd->is_static(), "just checking"); + if (fd->has_initial_value()) { + BasicType t = fd->field_type(); + switch (t) { + case T_BYTE: + mirror()->byte_field_put(fd->offset(), fd->int_initial_value()); + break; + case T_BOOLEAN: + mirror()->bool_field_put(fd->offset(), fd->int_initial_value()); + break; + case T_CHAR: + mirror()->char_field_put(fd->offset(), fd->int_initial_value()); + break; + case T_SHORT: + mirror()->short_field_put(fd->offset(), fd->int_initial_value()); + break; + case T_INT: + mirror()->int_field_put(fd->offset(), fd->int_initial_value()); + break; + case T_FLOAT: + mirror()->float_field_put(fd->offset(), fd->float_initial_value()); + break; + case T_DOUBLE: + mirror()->double_field_put(fd->offset(), fd->double_initial_value()); + break; + case T_LONG: + mirror()->long_field_put(fd->offset(), fd->long_initial_value()); + break; + case T_OBJECT: + { + #ifdef ASSERT + TempNewSymbol sym = SymbolTable::new_symbol("Ljava/lang/String;", CHECK); + assert(fd->signature() == sym, "just checking"); + #endif + oop string = fd->string_initial_value(CHECK); + mirror()->obj_field_put(fd->offset(), string); + } + break; + default: + THROW_MSG(vmSymbols::java_lang_ClassFormatError(), + "Illegal ConstantValue attribute in class file"); + } + } +} + + +// During bootstrap, java.lang.Class wasn't loaded so static field +// offsets were computed without the size added it. Go back and +// update all the static field offsets to included the size. +static void fixup_static_field(fieldDescriptor* fd, TRAPS) { + if (fd->is_static()) { + int real_offset = fd->offset() + instanceMirrorKlass::offset_of_static_fields(); + typeArrayOop fields = instanceKlass::cast(fd->field_holder())->fields(); + fields->short_at_put(fd->index() + instanceKlass::low_offset, extract_low_short_from_int(real_offset)); + fields->short_at_put(fd->index() + instanceKlass::high_offset, extract_high_short_from_int(real_offset)); + } +} + +void java_lang_Class::fixup_mirror(KlassHandle k, TRAPS) { + assert(instanceMirrorKlass::offset_of_static_fields() != 0, "must have been computed already"); + + if (k->oop_is_instance()) { + // Fixup the offsets + instanceKlass::cast(k())->do_local_static_fields(&fixup_static_field, CHECK); + } + create_mirror(k, CHECK); +} oop java_lang_Class::create_mirror(KlassHandle k, TRAPS) { assert(k->java_mirror() == NULL, "should only assign mirror once"); @@ -400,12 +479,17 @@ // class is put into the system dictionary. int computed_modifiers = k->compute_modifier_flags(CHECK_0); k->set_modifier_flags(computed_modifiers); - if (SystemDictionary::Class_klass_loaded()) { + if (SystemDictionary::Class_klass_loaded() && (k->oop_is_instance() || k->oop_is_javaArray())) { // Allocate mirror (java.lang.Class instance) - Handle mirror = instanceKlass::cast(SystemDictionary::Class_klass())->allocate_permanent_instance(CHECK_0); + Handle mirror = instanceMirrorKlass::cast(SystemDictionary::Class_klass())->allocate_instance(k, CHECK_0); // Setup indirections mirror->obj_field_put(klass_offset, k()); k->set_java_mirror(mirror()); + + instanceMirrorKlass* mk = instanceMirrorKlass::cast(mirror->klass()); + java_lang_Class::set_oop_size(mirror(), mk->instance_size(k)); + java_lang_Class::set_static_oop_field_count(mirror(), mk->compute_static_oop_field_count(mirror())); + // It might also have a component mirror. This mirror must already exist. if (k->oop_is_javaArray()) { Handle comp_mirror; @@ -428,6 +512,9 @@ arrayKlass::cast(k->as_klassOop())->set_component_mirror(comp_mirror()); set_array_klass(comp_mirror(), k->as_klassOop()); } + } else if (k->oop_is_instance()) { + // Initialize static fields + instanceKlass::cast(k())->do_local_static_fields(&initialize_static_field, CHECK_NULL); } return mirror(); } else { @@ -436,21 +523,46 @@ } + +int java_lang_Class::oop_size(oop java_class) { + assert(oop_size_offset != 0, "must be set"); + return java_class->int_field(oop_size_offset); +} +void java_lang_Class::set_oop_size(oop java_class, int size) { + assert(oop_size_offset != 0, "must be set"); + java_class->int_field_put(oop_size_offset, size); +} +int java_lang_Class::static_oop_field_count(oop java_class) { + assert(static_oop_field_count_offset != 0, "must be set"); + return java_class->int_field(static_oop_field_count_offset); +} +void java_lang_Class::set_static_oop_field_count(oop java_class, int size) { + assert(static_oop_field_count_offset != 0, "must be set"); + java_class->int_field_put(static_oop_field_count_offset, size); +} + + + + oop java_lang_Class::create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS) { // This should be improved by adding a field at the Java level or by // introducing a new VM klass (see comment in ClassFileParser) - oop java_class = instanceKlass::cast(SystemDictionary::Class_klass())->allocate_permanent_instance(CHECK_0); + oop java_class = instanceMirrorKlass::cast(SystemDictionary::Class_klass())->allocate_instance((oop)NULL, CHECK_0); if (type != T_VOID) { klassOop aklass = Universe::typeArrayKlassObj(type); assert(aklass != NULL, "correct bootstrap"); set_array_klass(java_class, aklass); } + instanceMirrorKlass* mk = instanceMirrorKlass::cast(SystemDictionary::Class_klass()); + java_lang_Class::set_oop_size(java_class, mk->instance_size(oop(NULL))); + java_lang_Class::set_static_oop_field_count(java_class, 0); return java_class; } klassOop java_lang_Class::as_klassOop(oop java_class) { //%note memory_2 + assert(java_lang_Class::is_instance(java_class), "must be a Class object"); klassOop k = klassOop(java_class->obj_field(klass_offset)); assert(k == NULL || k->is_klass(), "type check"); return k; @@ -2152,7 +2264,7 @@ // Support for java_lang_ref_Reference oop java_lang_ref_Reference::pending_list_lock() { instanceKlass* ik = instanceKlass::cast(SystemDictionary::Reference_klass()); - char *addr = (((char *)ik->start_of_static_fields()) + static_lock_offset); + address addr = ik->static_field_addr(static_lock_offset); if (UseCompressedOops) { return oopDesc::load_decode_heap_oop((narrowOop *)addr); } else { @@ -2162,7 +2274,7 @@ HeapWord *java_lang_ref_Reference::pending_list_addr() { instanceKlass* ik = instanceKlass::cast(SystemDictionary::Reference_klass()); - char *addr = (((char *)ik->start_of_static_fields()) + static_pending_offset); + address addr = ik->static_field_addr(static_pending_offset); // XXX This might not be HeapWord aligned, almost rather be char *. return (HeapWord*)addr; } @@ -2185,16 +2297,14 @@ jlong java_lang_ref_SoftReference::clock() { instanceKlass* ik = instanceKlass::cast(SystemDictionary::SoftReference_klass()); - int offset = ik->offset_of_static_fields() + static_clock_offset; - - return SystemDictionary::SoftReference_klass()->long_field(offset); + jlong* offset = (jlong*)ik->static_field_addr(static_clock_offset); + return *offset; } void java_lang_ref_SoftReference::set_clock(jlong value) { instanceKlass* ik = instanceKlass::cast(SystemDictionary::SoftReference_klass()); - int offset = ik->offset_of_static_fields() + static_clock_offset; - - SystemDictionary::SoftReference_klass()->long_field_put(offset, value); + jlong* offset = (jlong*)ik->static_field_addr(static_clock_offset); + *offset = value; } @@ -2221,7 +2331,7 @@ void java_lang_invoke_MethodHandle::compute_offsets() { klassOop k = SystemDictionary::MethodHandle_klass(); - if (k != NULL && EnableMethodHandles) { + if (k != NULL && EnableInvokeDynamic) { bool allow_super = false; if (AllowTransitionalJSR292) allow_super = true; // temporary, to access java.dyn.MethodHandleImpl compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::java_lang_invoke_MethodType_signature(), allow_super); @@ -2236,7 +2346,7 @@ void java_lang_invoke_MemberName::compute_offsets() { klassOop k = SystemDictionary::MemberName_klass(); - if (k != NULL && EnableMethodHandles) { + if (k != NULL && EnableInvokeDynamic) { compute_offset(_clazz_offset, k, vmSymbols::clazz_name(), vmSymbols::class_signature()); compute_offset(_name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature()); compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::object_signature()); @@ -2248,14 +2358,14 @@ void java_lang_invoke_DirectMethodHandle::compute_offsets() { klassOop k = SystemDictionary::DirectMethodHandle_klass(); - if (k != NULL && EnableMethodHandles) { + if (k != NULL && EnableInvokeDynamic) { compute_offset(_vmindex_offset, k, vmSymbols::vmindex_name(), vmSymbols::int_signature(), true); } } void java_lang_invoke_BoundMethodHandle::compute_offsets() { klassOop k = SystemDictionary::BoundMethodHandle_klass(); - if (k != NULL && EnableMethodHandles) { + if (k != NULL && EnableInvokeDynamic) { compute_offset(_vmargslot_offset, k, vmSymbols::vmargslot_name(), vmSymbols::int_signature(), true); compute_offset(_argument_offset, k, vmSymbols::argument_name(), vmSymbols::object_signature(), true); } @@ -2263,7 +2373,7 @@ void java_lang_invoke_AdapterMethodHandle::compute_offsets() { klassOop k = SystemDictionary::AdapterMethodHandle_klass(); - if (k != NULL && EnableMethodHandles) { + if (k != NULL && EnableInvokeDynamic) { compute_offset(_conversion_offset, k, vmSymbols::conversion_name(), vmSymbols::int_signature(), true); } } @@ -2625,26 +2735,18 @@ // Support for java_lang_System - -void java_lang_System::compute_offsets() { - assert(offset_of_static_fields == 0, "offsets should be initialized only once"); - - instanceKlass* ik = instanceKlass::cast(SystemDictionary::System_klass()); - offset_of_static_fields = ik->offset_of_static_fields(); -} - int java_lang_System::in_offset_in_bytes() { - return (offset_of_static_fields + static_in_offset); + return (instanceMirrorKlass::offset_of_static_fields() + static_in_offset); } int java_lang_System::out_offset_in_bytes() { - return (offset_of_static_fields + static_out_offset); + return (instanceMirrorKlass::offset_of_static_fields() + static_out_offset); } int java_lang_System::err_offset_in_bytes() { - return (offset_of_static_fields + static_err_offset); + return (instanceMirrorKlass::offset_of_static_fields() + static_err_offset); } @@ -2657,6 +2759,8 @@ int java_lang_Class::array_klass_offset; int java_lang_Class::resolved_constructor_offset; int java_lang_Class::number_of_fake_oop_fields; +int java_lang_Class::oop_size_offset; +int java_lang_Class::static_oop_field_count_offset; int java_lang_Throwable::backtrace_offset; int java_lang_Throwable::detailMessage_offset; int java_lang_Throwable::cause_offset; @@ -2700,7 +2804,6 @@ int java_lang_ref_SoftReference::timestamp_offset; int java_lang_ref_SoftReference::static_clock_offset; int java_lang_ClassLoader::parent_offset; -int java_lang_System::offset_of_static_fields; int java_lang_System::static_in_offset; int java_lang_System::static_out_offset; int java_lang_System::static_err_offset; @@ -2817,10 +2920,19 @@ java_lang_String::count_offset = java_lang_String::offset_offset + sizeof (jint); java_lang_String::hash_offset = java_lang_String::count_offset + sizeof (jint); - // Do the Class Class - java_lang_Class::klass_offset = java_lang_Class::hc_klass_offset * x + header; - java_lang_Class::array_klass_offset = java_lang_Class::hc_array_klass_offset * x + header; - java_lang_Class::resolved_constructor_offset = java_lang_Class::hc_resolved_constructor_offset * x + header; + { + // Do the Class Class + int offset = header; + java_lang_Class::oop_size_offset = header; + offset += BytesPerInt; + java_lang_Class::static_oop_field_count_offset = offset; + offset = align_size_up(offset + BytesPerInt, x); + java_lang_Class::klass_offset = offset; + offset += x; + java_lang_Class::array_klass_offset = offset; + offset += x; + java_lang_Class::resolved_constructor_offset = offset; + } // This is NOT an offset java_lang_Class::number_of_fake_oop_fields = java_lang_Class::hc_number_of_fake_oop_fields; @@ -2877,10 +2989,9 @@ void JavaClasses::compute_offsets() { java_lang_Class::compute_offsets(); - java_lang_System::compute_offsets(); java_lang_Thread::compute_offsets(); java_lang_ThreadGroup::compute_offsets(); - if (EnableMethodHandles) { + if (EnableInvokeDynamic) { java_lang_invoke_MethodHandle::compute_offsets(); java_lang_invoke_MemberName::compute_offsets(); java_lang_invoke_DirectMethodHandle::compute_offsets(); @@ -2888,8 +2999,6 @@ java_lang_invoke_AdapterMethodHandle::compute_offsets(); java_lang_invoke_MethodType::compute_offsets(); java_lang_invoke_MethodTypeForm::compute_offsets(); - } - if (EnableInvokeDynamic) { java_lang_invoke_CallSite::compute_offsets(); } java_security_AccessControlContext::compute_offsets(); @@ -2961,10 +3070,10 @@ tty->print_cr("Static field %s.%s appears to be nonstatic", klass_name, field_name); return false; } - if (fd.offset() == hardcoded_offset + h_klass->offset_of_static_fields()) { + if (fd.offset() == hardcoded_offset + instanceMirrorKlass::offset_of_static_fields()) { return true; } else { - tty->print_cr("Offset of static field %s.%s is hardcoded as %d but should really be %d.", klass_name, field_name, hardcoded_offset, fd.offset() - h_klass->offset_of_static_fields()); + tty->print_cr("Offset of static field %s.%s is hardcoded as %d but should really be %d.", klass_name, field_name, hardcoded_offset, fd.offset() - instanceMirrorKlass::offset_of_static_fields()); return false; } }
--- a/src/share/vm/classfile/javaClasses.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/classfile/javaClasses.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -109,6 +109,30 @@ static char* as_platform_dependent_str(Handle java_string, TRAPS); static jchar* as_unicode_string(oop java_string, int& length); + // Compute the hash value for a java.lang.String object which would + // contain the characters passed in. This hash value is used for at + // least two purposes. + // + // (a) As the hash value used by the StringTable for bucket selection + // and comparison (stored in the HashtableEntry structures). This + // is used in the String.intern() method. + // + // (b) As the hash value used by the String object itself, in + // String.hashCode(). This value is normally calculate in Java code + // in the String.hashCode method(), but is precomputed for String + // objects in the shared archive file. + // + // For this reason, THIS ALGORITHM MUST MATCH String.hashCode(). + static unsigned int hash_string(jchar* s, int len) { + unsigned int h = 0; + while (len-- > 0) { + h = 31*h + (unsigned int) *s; + s++; + } + return h; + } + static unsigned int hash_string(oop java_string); + static bool equals(oop java_string, jchar* chars, int len); // Conversion between '.' and '/' formats @@ -138,10 +162,8 @@ // The fake offsets are added by the class loader when java.lang.Class is loaded enum { - hc_klass_offset = 0, - hc_array_klass_offset = 1, - hc_resolved_constructor_offset = 2, - hc_number_of_fake_oop_fields = 3 + hc_number_of_fake_oop_fields = 3, + hc_number_of_fake_int_fields = 2 }; static int klass_offset; @@ -149,6 +171,9 @@ static int array_klass_offset; static int number_of_fake_oop_fields; + static int oop_size_offset; + static int static_oop_field_count_offset; + static void compute_offsets(); static bool offsets_computed; static int classRedefinedCount_offset; @@ -157,6 +182,7 @@ public: // Instance creation static oop create_mirror(KlassHandle k, TRAPS); + static void fixup_mirror(KlassHandle k, TRAPS); static oop create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS); // Conversion static klassOop as_klassOop(oop java_class); @@ -191,6 +217,12 @@ static void set_classRedefinedCount(oop the_class_mirror, int value); // Support for parallelCapable field static bool parallelCapable(oop the_class_mirror); + + static int oop_size(oop java_class); + static void set_oop_size(oop java_class, int size); + static int static_oop_field_count(oop java_class); + static void set_static_oop_field_count(oop java_class, int size); + // Debugging friend class JavaClasses; friend class instanceKlass; // verification code accesses offsets @@ -1165,13 +1197,10 @@ hc_static_err_offset = 2 }; - static int offset_of_static_fields; static int static_in_offset; static int static_out_offset; static int static_err_offset; - static void compute_offsets(); - public: static int in_offset_in_bytes(); static int out_offset_in_bytes();
--- a/src/share/vm/classfile/symbolTable.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/classfile/symbolTable.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -480,33 +480,6 @@ // -------------------------------------------------------------------------- - - -// Compute the hash value for a java.lang.String object which would -// contain the characters passed in. This hash value is used for at -// least two purposes. -// -// (a) As the hash value used by the StringTable for bucket selection -// and comparison (stored in the HashtableEntry structures). This -// is used in the String.intern() method. -// -// (b) As the hash value used by the String object itself, in -// String.hashCode(). This value is normally calculate in Java code -// in the String.hashCode method(), but is precomputed for String -// objects in the shared archive file. -// -// For this reason, THIS ALGORITHM MUST MATCH String.hashCode(). - -int StringTable::hash_string(jchar* s, int len) { - unsigned h = 0; - while (len-- > 0) { - h = 31*h + (unsigned) *s; - s++; - } - return h; -} - - StringTable* StringTable::_the_table = NULL; oop StringTable::lookup(int index, jchar* name, @@ -530,7 +503,7 @@ Handle string; // try to reuse the string if possible - if (!string_or_null.is_null() && string_or_null()->is_perm()) { + if (!string_or_null.is_null() && (!JavaObjectsInPerm || string_or_null()->is_perm())) { string = string_or_null; } else { string = java_lang_String::create_tenured_from_unicode(name, len, CHECK_NULL); @@ -561,7 +534,7 @@ ResourceMark rm; int length; jchar* chars = symbol->as_unicode(length); - unsigned int hashValue = hash_string(chars, length); + unsigned int hashValue = java_lang_String::hash_string(chars, length); int index = the_table()->hash_to_index(hashValue); return the_table()->lookup(index, chars, length, hashValue); } @@ -569,7 +542,7 @@ oop StringTable::intern(Handle string_or_null, jchar* name, int len, TRAPS) { - unsigned int hashValue = hash_string(name, len); + unsigned int hashValue = java_lang_String::hash_string(name, len); int index = the_table()->hash_to_index(hashValue); oop string = the_table()->lookup(index, name, len, hashValue); @@ -662,11 +635,8 @@ for ( ; p != NULL; p = p->next()) { oop s = p->literal(); guarantee(s != NULL, "interned string is NULL"); - guarantee(s->is_perm(), "interned string not in permspace"); - - int length; - jchar* chars = java_lang_String::as_unicode_string(s, length); - unsigned int h = hash_string(chars, length); + guarantee(s->is_perm() || !JavaObjectsInPerm, "interned string not in permspace"); + unsigned int h = java_lang_String::hash_string(s); guarantee(p->hash() == h, "broken hash in string table entry"); guarantee(the_table()->hash_to_index(h) == i, "wrong index in string table");
--- a/src/share/vm/classfile/symbolTable.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/classfile/symbolTable.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -216,18 +216,14 @@ oop basic_add(int index, Handle string_or_null, jchar* name, int len, unsigned int hashValue, TRAPS); - // Table size - enum { - string_table_size = 1009 - }; - oop lookup(int index, jchar* chars, int length, unsigned int hashValue); - StringTable() : Hashtable<oop>(string_table_size, sizeof (HashtableEntry<oop>)) {} + StringTable() : Hashtable<oop>((int)StringTableSize, + sizeof (HashtableEntry<oop>)) {} StringTable(HashtableBucket* t, int number_of_entries) - : Hashtable<oop>(string_table_size, sizeof (HashtableEntry<oop>), t, - number_of_entries) {} + : Hashtable<oop>((int)StringTableSize, sizeof (HashtableEntry<oop>), t, + number_of_entries) {} public: // The string table @@ -241,13 +237,11 @@ static void create_table(HashtableBucket* t, int length, int number_of_entries) { assert(_the_table == NULL, "One string table allowed."); - assert(length == string_table_size * sizeof(HashtableBucket), + assert((size_t)length == StringTableSize * sizeof(HashtableBucket), "bad shared string size."); _the_table = new StringTable(t, number_of_entries); } - static int hash_string(jchar* s, int len); - // GC support // Delete pointers to otherwise-unreachable objects. static void unlink(BoolObjectClosure* cl);
--- a/src/share/vm/classfile/systemDictionary.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/classfile/systemDictionary.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1017,7 +1017,7 @@ } if (host_klass.not_null() && k.not_null()) { - assert(AnonymousClasses, ""); + assert(EnableInvokeDynamic, ""); // If it's anonymous, initialize it now, since nobody else will. k->set_host_klass(host_klass()); @@ -1940,7 +1940,7 @@ } Symbol* backup_symbol = NULL; // symbol to try if the current symbol fails if (init_opt == SystemDictionary::Pre_JSR292) { - if (!EnableMethodHandles) try_load = false; // do not bother to load such classes + if (!EnableInvokeDynamic) try_load = false; // do not bother to load such classes if (AllowTransitionalJSR292) { backup_symbol = find_backup_class_name(symbol); if (try_load && PreferTransitionalJSR292) { @@ -2038,25 +2038,15 @@ instanceKlass::cast(WK_KLASS(FinalReference_klass))->set_reference_type(REF_FINAL); instanceKlass::cast(WK_KLASS(PhantomReference_klass))->set_reference_type(REF_PHANTOM); - WKID meth_group_start = WK_KLASS_ENUM_NAME(MethodHandle_klass); - WKID meth_group_end = WK_KLASS_ENUM_NAME(WrongMethodTypeException_klass); - initialize_wk_klasses_until(meth_group_start, scan, CHECK); - if (EnableMethodHandles) { - initialize_wk_klasses_through(meth_group_end, scan, CHECK); - } - if (_well_known_klasses[meth_group_start] == NULL) { - // Skip the rest of the method handle classes, if MethodHandle is not loaded. - scan = WKID(meth_group_end+1); - } - WKID indy_group_start = WK_KLASS_ENUM_NAME(Linkage_klass); - WKID indy_group_end = WK_KLASS_ENUM_NAME(CallSite_klass); - initialize_wk_klasses_until(indy_group_start, scan, CHECK); + // JSR 292 classes + WKID jsr292_group_start = WK_KLASS_ENUM_NAME(MethodHandle_klass); + WKID jsr292_group_end = WK_KLASS_ENUM_NAME(CallSite_klass); + initialize_wk_klasses_until(jsr292_group_start, scan, CHECK); if (EnableInvokeDynamic) { - initialize_wk_klasses_through(indy_group_end, scan, CHECK); - } - if (_well_known_klasses[indy_group_start] == NULL) { - // Skip the rest of the dynamic typing classes, if Linkage is not loaded. - scan = WKID(indy_group_end+1); + initialize_wk_klasses_through(jsr292_group_end, scan, CHECK); + } else { + // Skip the JSR 292 classes, if not enabled. + scan = WKID(jsr292_group_end + 1); } initialize_wk_klasses_until(WKID_LIMIT, scan, CHECK); @@ -2407,7 +2397,7 @@ Symbol* signature, KlassHandle accessing_klass, TRAPS) { - if (!EnableMethodHandles) return NULL; + if (!EnableInvokeDynamic) return NULL; vmSymbols::SID name_id = vmSymbols::find_sid(name); assert(name_id != vmSymbols::NO_SID, "must be a known name"); unsigned int hash = invoke_method_table()->compute_hash(signature, name_id);
--- a/src/share/vm/classfile/systemDictionary.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/classfile/systemDictionary.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -207,7 +207,7 @@ enum InitOption { Pre, // preloaded; error if not present - Pre_JSR292, // preloaded if EnableMethodHandles + Pre_JSR292, // preloaded if EnableInvokeDynamic // Order is significant. Options before this point require resolve_or_fail. // Options after this point will use resolve_or_null instead.
--- a/src/share/vm/code/codeCache.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/code/codeCache.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -337,7 +337,6 @@ if (is_live) { // Perform cur->oops_do(f), maybe just once per nmethod. f->do_code_blob(cur); - cur->fix_oop_relocations(); } } @@ -552,6 +551,19 @@ } +void CodeCache::verify_oops() { + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + VerifyOopClosure voc; + FOR_ALL_ALIVE_BLOBS(cb) { + if (cb->is_nmethod()) { + nmethod *nm = (nmethod*)cb; + nm->oops_do(&voc); + nm->verify_oop_relocations(); + } + } +} + + address CodeCache::first_address() { assert_locked_or_safepoint(CodeCache_lock); return (address)_heap->begin();
--- a/src/share/vm/code/codeCache.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/code/codeCache.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -122,6 +122,7 @@ // GC support static void gc_epilogue(); static void gc_prologue(); + static void verify_oops(); // If "unloading_occurred" is true, then unloads (i.e., breaks root links // to) any unmarked codeBlobs in the cache. Sets "marked_for_unloading" // to "true" iff some code got unloaded.
--- a/src/share/vm/code/nmethod.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/code/nmethod.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -28,6 +28,7 @@ #include "code/nmethod.hpp" #include "code/scopeDesc.hpp" #include "compiler/abstractCompiler.hpp" +#include "compiler/compileBroker.hpp" #include "compiler/compileLog.hpp" #include "compiler/compilerOracle.hpp" #include "compiler/disassembler.hpp" @@ -170,7 +171,7 @@ int pc_desc_resets; // number of resets (= number of caches) int pc_desc_queries; // queries to nmethod::find_pc_desc int pc_desc_approx; // number of those which have approximate true - int pc_desc_repeats; // number of _last_pc_desc hits + int pc_desc_repeats; // number of _pc_descs[0] hits int pc_desc_hits; // number of LRU cache hits int pc_desc_tests; // total number of PcDesc examinations int pc_desc_searches; // total number of quasi-binary search steps @@ -278,40 +279,44 @@ void PcDescCache::reset_to(PcDesc* initial_pc_desc) { if (initial_pc_desc == NULL) { - _last_pc_desc = NULL; // native method + _pc_descs[0] = NULL; // native method; no PcDescs at all return; } NOT_PRODUCT(++nmethod_stats.pc_desc_resets); // reset the cache by filling it with benign (non-null) values assert(initial_pc_desc->pc_offset() < 0, "must be sentinel"); - _last_pc_desc = initial_pc_desc + 1; // first valid one is after sentinel for (int i = 0; i < cache_size; i++) _pc_descs[i] = initial_pc_desc; } PcDesc* PcDescCache::find_pc_desc(int pc_offset, bool approximate) { NOT_PRODUCT(++nmethod_stats.pc_desc_queries); - NOT_PRODUCT(if (approximate) ++nmethod_stats.pc_desc_approx); + NOT_PRODUCT(if (approximate) ++nmethod_stats.pc_desc_approx); + + // Note: one might think that caching the most recently + // read value separately would be a win, but one would be + // wrong. When many threads are updating it, the cache + // line it's in would bounce between caches, negating + // any benefit. // In order to prevent race conditions do not load cache elements // repeatedly, but use a local copy: PcDesc* res; - // Step one: Check the most recently returned value. - res = _last_pc_desc; - if (res == NULL) return NULL; // native method; no PcDescs at all + // Step one: Check the most recently added value. + res = _pc_descs[0]; + if (res == NULL) return NULL; // native method; no PcDescs at all if (match_desc(res, pc_offset, approximate)) { NOT_PRODUCT(++nmethod_stats.pc_desc_repeats); return res; } - // Step two: Check the LRU cache. - for (int i = 0; i < cache_size; i++) { + // Step two: Check the rest of the LRU cache. + for (int i = 1; i < cache_size; ++i) { res = _pc_descs[i]; - if (res->pc_offset() < 0) break; // optimization: skip empty cache + if (res->pc_offset() < 0) break; // optimization: skip empty cache if (match_desc(res, pc_offset, approximate)) { NOT_PRODUCT(++nmethod_stats.pc_desc_hits); - _last_pc_desc = res; // record this cache hit in case of repeat return res; } } @@ -322,24 +327,23 @@ void PcDescCache::add_pc_desc(PcDesc* pc_desc) { NOT_PRODUCT(++nmethod_stats.pc_desc_adds); - // Update the LRU cache by shifting pc_desc forward: + // Update the LRU cache by shifting pc_desc forward. for (int i = 0; i < cache_size; i++) { PcDesc* next = _pc_descs[i]; _pc_descs[i] = pc_desc; pc_desc = next; } - // Note: Do not update _last_pc_desc. It fronts for the LRU cache. } // adjust pcs_size so that it is a multiple of both oopSize and // sizeof(PcDesc) (assumes that if sizeof(PcDesc) is not a multiple // of oopSize, then 2*sizeof(PcDesc) is) -static int adjust_pcs_size(int pcs_size) { +static int adjust_pcs_size(int pcs_size) { int nsize = round_to(pcs_size, oopSize); if ((nsize % sizeof(PcDesc)) != 0) { nsize = pcs_size + sizeof(PcDesc); } - assert((nsize % oopSize) == 0, "correct alignment"); + assert((nsize % oopSize) == 0, "correct alignment"); return nsize; } @@ -466,6 +470,7 @@ nmethod* nmethod::new_native_nmethod(methodHandle method, + int compile_id, CodeBuffer *code_buffer, int vep_offset, int frame_complete, @@ -482,7 +487,7 @@ offsets.set_value(CodeOffsets::Verified_Entry, vep_offset); offsets.set_value(CodeOffsets::Frame_Complete, frame_complete); nm = new (native_nmethod_size) - nmethod(method(), native_nmethod_size, &offsets, + nmethod(method(), native_nmethod_size, compile_id, &offsets, code_buffer, frame_size, basic_lock_owner_sp_offset, basic_lock_sp_offset, oop_maps); @@ -607,6 +612,7 @@ nmethod::nmethod( methodOop method, int nmethod_size, + int compile_id, CodeOffsets* offsets, CodeBuffer* code_buffer, int frame_size, @@ -641,7 +647,7 @@ _handler_table_offset = _dependencies_offset; _nul_chk_table_offset = _handler_table_offset; _nmethod_end_offset = _nul_chk_table_offset; - _compile_id = 0; // default + _compile_id = compile_id; _comp_level = CompLevel_none; _entry_point = code_begin() + offsets->value(CodeOffsets::Entry); _verified_entry_point = code_begin() + offsets->value(CodeOffsets::Verified_Entry); @@ -650,6 +656,9 @@ _pc_desc_cache.reset_to(NULL); code_buffer->copy_oops_to(this); + if (ScavengeRootsInCode && detect_scavenge_root_oops()) { + CodeCache::add_scavenge_root_nmethod(this); + } debug_only(verify_scavenge_root_oops()); CodeCache::commit(this); } @@ -924,72 +933,11 @@ #undef LOG_OFFSET -void nmethod::print_compilation(outputStream *st, const char *method_name, const char *title, - methodOop method, bool is_blocking, int compile_id, int bci, int comp_level) { - bool is_synchronized = false, has_xhandler = false, is_native = false; - int code_size = -1; - if (method != NULL) { - is_synchronized = method->is_synchronized(); - has_xhandler = method->has_exception_handler(); - is_native = method->is_native(); - code_size = method->code_size(); - } - // print compilation number - st->print("%7d %3d", (int)tty->time_stamp().milliseconds(), compile_id); - - // print method attributes - const bool is_osr = bci != InvocationEntryBci; - const char blocking_char = is_blocking ? 'b' : ' '; - const char compile_type = is_osr ? '%' : ' '; - const char sync_char = is_synchronized ? 's' : ' '; - const char exception_char = has_xhandler ? '!' : ' '; - const char native_char = is_native ? 'n' : ' '; - st->print("%c%c%c%c%c ", compile_type, sync_char, exception_char, blocking_char, native_char); - if (TieredCompilation) { - st->print("%d ", comp_level); - } - - // print optional title - bool do_nl = false; - if (title != NULL) { - int tlen = (int) strlen(title); - bool do_nl = false; - if (tlen > 0 && title[tlen-1] == '\n') { tlen--; do_nl = true; } - st->print("%.*s", tlen, title); - } else { - do_nl = true; - } - - // print method name string if given - if (method_name != NULL) { - st->print(method_name); - } else { - // otherwise as the method to print itself - if (method != NULL && !Universe::heap()->is_gc_active()) { - method->print_short_name(st); - } else { - st->print("(method)"); - } - } - - if (method != NULL) { - // print osr_bci if any - if (is_osr) st->print(" @ %d", bci); - // print method size - st->print(" (%d bytes)", code_size); - } - if (do_nl) st->cr(); -} - // Print out more verbose output usually for a newly created nmethod. -void nmethod::print_on(outputStream* st, const char* title) const { +void nmethod::print_on(outputStream* st, const char* msg) const { if (st != NULL) { ttyLocker ttyl; - print_compilation(st, /*method_name*/NULL, title, - method(), /*is_blocking*/false, - compile_id(), - is_osr_method() ? osr_entry_bci() : InvocationEntryBci, - comp_level()); + CompileTask::print_compilation(st, this, msg); if (WizardMode) st->print(" (" INTPTR_FORMAT ")", this); } } @@ -1102,6 +1050,20 @@ } +void nmethod::verify_oop_relocations() { + // Ensure sure that the code matches the current oop values + RelocIterator iter(this, NULL, NULL); + while (iter.next()) { + if (iter.type() == relocInfo::oop_type) { + oop_Relocation* reloc = iter.oop_reloc(); + if (!reloc->oop_is_immediate()) { + reloc->verify_oop_relocation(); + } + } + } +} + + ScopeDesc* nmethod::scope_desc_at(address pc) { PcDesc* pd = pc_desc_at(pc); guarantee(pd != NULL, "scope must be present"); @@ -1180,14 +1142,17 @@ set_stack_traversal_mark(NMethodSweeper::traversal_count()); } -// Tell if a non-entrant method can be converted to a zombie (i.e., there is no activations on the stack) +// Tell if a non-entrant method can be converted to a zombie (i.e., +// there are no activations on the stack, not in use by the VM, +// and not in use by the ServiceThread) bool nmethod::can_not_entrant_be_converted() { assert(is_not_entrant(), "must be a non-entrant method"); // Since the nmethod sweeper only does partial sweep the sweeper's traversal // count can be greater than the stack traversal count before it hits the // nmethod for the second time. - return stack_traversal_mark()+1 < NMethodSweeper::traversal_count(); + return stack_traversal_mark()+1 < NMethodSweeper::traversal_count() && + !is_locked_by_vm(); } void nmethod::inc_decompile_count() { @@ -1286,14 +1251,14 @@ } } if (PrintCompilation && _state != unloaded) { - print_on(tty, _state == zombie ? "made zombie " : "made not entrant "); - tty->cr(); + print_on(tty, _state == zombie ? "made zombie" : "made not entrant"); } } // Common functionality for both make_not_entrant and make_zombie bool nmethod::make_not_entrant_or_zombie(unsigned int state) { assert(state == zombie || state == not_entrant, "must be zombie or not_entrant"); + assert(!is_zombie(), "should not already be a zombie"); // Make sure neither the nmethod nor the method is flushed in case of a safepoint in code below. nmethodLocker nml(this); @@ -1301,11 +1266,6 @@ No_Safepoint_Verifier nsv; { - // If the method is already zombie there is nothing to do - if (is_zombie()) { - return false; - } - // invalidate osr nmethod before acquiring the patching lock since // they both acquire leaf locks and we don't want a deadlock. // This logic is equivalent to the logic below for patching the @@ -1375,13 +1335,12 @@ flush_dependencies(NULL); } - { - // zombie only - if a JVMTI agent has enabled the CompiledMethodUnload event - // and it hasn't already been reported for this nmethod then report it now. - // (the event may have been reported earilier if the GC marked it for unloading). - Pause_No_Safepoint_Verifier pnsv(&nsv); - post_compiled_method_unload(); - } + // zombie only - if a JVMTI agent has enabled the CompiledMethodUnload + // event and it hasn't already been reported for this nmethod then + // report it now. The event may have been reported earilier if the GC + // marked it for unloading). JvmtiDeferredEventQueue support means + // we no longer go to a safepoint here. + post_compiled_method_unload(); #ifdef ASSERT // It's no longer safe to access the oops section since zombie @@ -1566,7 +1525,7 @@ if (_jmethod_id != NULL && JvmtiExport::should_post_compiled_method_unload()) { assert(!unload_reported(), "already unloaded"); JvmtiDeferredEvent event = - JvmtiDeferredEvent::compiled_method_unload_event( + JvmtiDeferredEvent::compiled_method_unload_event(this, _jmethod_id, insts_begin()); if (SafepointSynchronize::is_at_safepoint()) { // Don't want to take the queueing lock. Add it as pending and @@ -1798,7 +1757,7 @@ break; } // Mark was clear when we first saw this guy. - NOT_PRODUCT(if (TraceScavenge) print_on(tty, "oops_do, mark\n")); + NOT_PRODUCT(if (TraceScavenge) print_on(tty, "oops_do, mark")); return false; } } @@ -1822,7 +1781,8 @@ assert(cur != NULL, "not NULL-terminated"); nmethod* next = cur->_oops_do_mark_link; cur->_oops_do_mark_link = NULL; - NOT_PRODUCT(if (TraceScavenge) cur->print_on(tty, "oops_do, unmark\n")); + cur->fix_oop_relocations(); + NOT_PRODUCT(if (TraceScavenge) cur->print_on(tty, "oops_do, unmark")); cur = next; } void* required = _oops_do_mark_nmethods; @@ -2171,10 +2131,12 @@ lock_nmethod(_nm); } -void nmethodLocker::lock_nmethod(nmethod* nm) { +// Only JvmtiDeferredEvent::compiled_method_unload_event() +// should pass zombie_ok == true. +void nmethodLocker::lock_nmethod(nmethod* nm, bool zombie_ok) { if (nm == NULL) return; Atomic::inc(&nm->_lock_count); - guarantee(!nm->is_zombie(), "cannot lock a zombie method"); + guarantee(zombie_ok || !nm->is_zombie(), "cannot lock a zombie method"); } void nmethodLocker::unlock_nmethod(nmethod* nm) { @@ -2375,7 +2337,7 @@ ResourceMark rm; ttyLocker ttyl; // keep the following output all in one block - tty->print("Compiled "); + tty->print("Compiled method "); if (is_compiled_by_c1()) { tty->print("(c1) "); @@ -2387,8 +2349,8 @@ tty->print("(nm) "); } - print_on(tty, "nmethod"); - tty->cr(); + print_on(tty, NULL); + if (WizardMode) { tty->print("((nmethod*) "INTPTR_FORMAT ") ", this); tty->print(" for method " INTPTR_FORMAT , (address)method()); @@ -2775,7 +2737,8 @@ #ifndef PRODUCT void nmethod::print_value_on(outputStream* st) const { - print_on(st, "nmethod"); + st->print("nmethod"); + print_on(st, NULL); } void nmethod::print_calls(outputStream* st) {
--- a/src/share/vm/code/nmethod.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/code/nmethod.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -69,14 +69,13 @@ friend class VMStructs; private: enum { cache_size = 4 }; - PcDesc* _last_pc_desc; // most recent pc_desc found PcDesc* _pc_descs[cache_size]; // last cache_size pc_descs found public: - PcDescCache() { debug_only(_last_pc_desc = NULL); } + PcDescCache() { debug_only(_pc_descs[0] = NULL); } void reset_to(PcDesc* initial_pc_desc); PcDesc* find_pc_desc(int pc_offset, bool approximate); void add_pc_desc(PcDesc* pc_desc); - PcDesc* last_pc_desc() { return _last_pc_desc; } + PcDesc* last_pc_desc() { return _pc_descs[0]; } }; @@ -178,7 +177,7 @@ unsigned int _has_method_handle_invokes:1; // Has this method MethodHandle invokes? // Protected by Patching_lock - unsigned char _state; // {alive, not_entrant, zombie, unloaded) + unsigned char _state; // {alive, not_entrant, zombie, unloaded} #ifdef ASSERT bool _oops_are_stale; // indicates that it's no longer safe to access oops section @@ -194,7 +193,10 @@ NOT_PRODUCT(bool _has_debug_info; ) - // Nmethod Flushing lock (if non-zero, then the nmethod is not removed) + // Nmethod Flushing lock. If non-zero, then the nmethod is not removed + // and is not made into a zombie. However, once the nmethod is made into + // a zombie, it will be locked one final time if CompiledMethodUnload + // event processing needs to be done. jint _lock_count; // not_entrant method removal. Each mark_sweep pass will update @@ -227,6 +229,7 @@ // For native wrappers nmethod(methodOop method, int nmethod_size, + int compile_id, CodeOffsets* offsets, CodeBuffer *code_buffer, int frame_size, @@ -297,6 +300,7 @@ int comp_level); static nmethod* new_native_nmethod(methodHandle method, + int compile_id, CodeBuffer *code_buffer, int vep_offset, int frame_complete, @@ -457,6 +461,7 @@ public: void fix_oop_relocations(address begin, address end) { fix_oop_relocations(begin, end, false); } void fix_oop_relocations() { fix_oop_relocations(NULL, NULL, false); } + void verify_oop_relocations(); bool is_at_poll_return(address pc); bool is_at_poll_or_poll_return(address pc); @@ -497,8 +502,8 @@ address continuation_for_implicit_exception(address pc); // On-stack replacement support - int osr_entry_bci() const { assert(_entry_bci != InvocationEntryBci, "wrong kind of nmethod"); return _entry_bci; } - address osr_entry() const { assert(_entry_bci != InvocationEntryBci, "wrong kind of nmethod"); return _osr_entry_point; } + int osr_entry_bci() const { assert(is_osr_method(), "wrong kind of nmethod"); return _entry_bci; } + address osr_entry() const { assert(is_osr_method(), "wrong kind of nmethod"); return _osr_entry_point; } void invalidate_osr_method(); nmethod* osr_link() const { return _osr_link; } void set_osr_link(nmethod *n) { _osr_link = n; } @@ -522,8 +527,9 @@ void flush(); public: - // If returning true, it is unsafe to remove this nmethod even though it is a zombie - // nmethod, since the VM might have a reference to it. Should only be called from a safepoint. + // When true is returned, it is unsafe to remove this nmethod even if + // it is a zombie, since the VM or the ServiceThread might still be + // using it. bool is_locked_by_vm() const { return _lock_count >0; } // See comment at definition of _last_seen_on_stack @@ -604,10 +610,6 @@ void verify_scopes(); void verify_interrupt_point(address interrupt_point); - // print compilation helper - static void print_compilation(outputStream *st, const char *method_name, const char *title, - methodOop method, bool is_blocking, int compile_id, int bci, int comp_level); - // printing support void print() const; void print_code(); @@ -623,7 +625,7 @@ // need to re-define this from CodeBlob else the overload hides it virtual void print_on(outputStream* st) const { CodeBlob::print_on(st); } - void print_on(outputStream* st, const char* title) const; + void print_on(outputStream* st, const char* msg) const; // Logging void log_identity(xmlStream* log) const; @@ -689,13 +691,20 @@ }; -// Locks an nmethod so its code will not get removed, even if it is a zombie/not_entrant method +// Locks an nmethod so its code will not get removed and it will not +// be made into a zombie, even if it is a not_entrant method. After the +// nmethod becomes a zombie, if CompiledMethodUnload event processing +// needs to be done, then lock_nmethod() is used directly to keep the +// generated code from being reused too early. class nmethodLocker : public StackObj { nmethod* _nm; public: - static void lock_nmethod(nmethod* nm); // note: nm can be NULL + // note: nm can be NULL + // Only JvmtiDeferredEvent::compiled_method_unload_event() + // should pass zombie_ok == true. + static void lock_nmethod(nmethod* nm, bool zombie_ok = false); static void unlock_nmethod(nmethod* nm); // (ditto) nmethodLocker(address pc); // derive nm from pc
--- a/src/share/vm/code/relocInfo.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/code/relocInfo.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -798,6 +798,14 @@ } +void oop_Relocation::verify_oop_relocation() { + if (!oop_is_immediate()) { + // get the oop from the pool, and re-insert it into the instruction: + verify_value(value()); + } +} + + RelocIterator virtual_call_Relocation::parse_ic(nmethod* &nm, address &ic_call, address &first_oop, oop* &oop_addr, bool *is_optimized) { assert(ic_call != NULL, "ic_call address must be set");
--- a/src/share/vm/code/relocInfo.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/code/relocInfo.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -765,7 +765,8 @@ protected: // platform-dependent utilities for decoding and patching instructions - void pd_set_data_value (address x, intptr_t off); // a set or mem-ref + void pd_set_data_value (address x, intptr_t off, bool verify_only = false); // a set or mem-ref + void pd_verify_data_value (address x, intptr_t off) { pd_set_data_value(x, off, true); } address pd_call_destination (address orig_addr = NULL); void pd_set_call_destination (address x); void pd_swap_in_breakpoint (address x, short* instrs, int instrlen); @@ -880,6 +881,12 @@ else pd_set_data_value(x, o); } + void verify_value(address x) { + if (addr_in_const()) + assert(*(address*)addr() == x, "must agree"); + else + pd_verify_data_value(x, offset()); + } // The "o" (displacement) argument is relevant only to split relocations // on RISC machines. In some CPUs (SPARC), the set-hi and set-lo ins'ns @@ -950,6 +957,8 @@ void fix_oop_relocation(); // reasserts oop value + void verify_oop_relocation(); + address value() { return (address) *oop_addr(); } bool oop_is_immediate() { return oop_index() == 0; }
--- a/src/share/vm/compiler/compileBroker.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/compiler/compileBroker.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -268,11 +268,6 @@ } -void CompileTask::print_compilation(outputStream *st, methodOop method, char* method_name) { - nmethod::print_compilation(st, method_name,/*title*/ NULL, method, - is_blocking(), compile_id(), osr_bci(), comp_level()); -} - // ------------------------------------------------------------------ // CompileTask::print_line_on_error // @@ -284,31 +279,115 @@ // Otherwise it's the same as CompileTask::print_line() // void CompileTask::print_line_on_error(outputStream* st, char* buf, int buflen) { - methodOop method = (methodOop)JNIHandles::resolve(_method); // print compiler name st->print("%s:", CompileBroker::compiler(comp_level())->name()); - char* method_name = NULL; - if (method != NULL) { - method_name = method->name_and_sig_as_C_string(buf, buflen); - } - print_compilation(st, method, method_name); + print_compilation(st); } // ------------------------------------------------------------------ // CompileTask::print_line void CompileTask::print_line() { - Thread *thread = Thread::current(); - methodHandle method(thread, - (methodOop)JNIHandles::resolve(method_handle())); - ResourceMark rm(thread); - ttyLocker ttyl; // keep the following output all in one block - // print compiler name if requested if (CIPrintCompilerName) tty->print("%s:", CompileBroker::compiler(comp_level())->name()); - print_compilation(tty, method(), NULL); + print_compilation(); +} + + +// ------------------------------------------------------------------ +// CompileTask::print_compilation_impl +void CompileTask::print_compilation_impl(outputStream* st, methodOop method, int compile_id, int comp_level, bool is_osr_method, int osr_bci, bool is_blocking, const char* msg) { + st->print("%7d ", (int) st->time_stamp().milliseconds()); // print timestamp + st->print("%4d ", compile_id); // print compilation number + + // method attributes + const char compile_type = is_osr_method ? '%' : ' '; + const char sync_char = method->is_synchronized() ? 's' : ' '; + const char exception_char = method->has_exception_handler() ? '!' : ' '; + const char blocking_char = is_blocking ? 'b' : ' '; + const char native_char = method->is_native() ? 'n' : ' '; + + // print method attributes + st->print("%c%c%c%c%c ", compile_type, sync_char, exception_char, blocking_char, native_char); + + if (TieredCompilation) { + if (comp_level != -1) st->print("%d ", comp_level); + else st->print("- "); + } + st->print(" "); // more indent + + method->print_short_name(st); + if (is_osr_method) { + st->print(" @ %d", osr_bci); + } + st->print(" (%d bytes)", method->code_size()); + + if (msg != NULL) { + st->print(" %s", msg); + } + st->cr(); } +// ------------------------------------------------------------------ +// CompileTask::print_inlining +void CompileTask::print_inlining(outputStream* st, ciMethod* method, int inline_level, int bci, const char* msg) { + // 1234567 + st->print(" "); // print timestamp + // 1234 + st->print(" "); // print compilation number + + // method attributes + const char sync_char = method->is_synchronized() ? 's' : ' '; + const char exception_char = method->has_exception_handlers() ? '!' : ' '; + const char monitors_char = method->has_monitor_bytecodes() ? 'm' : ' '; + + // print method attributes + st->print(" %c%c%c ", sync_char, exception_char, monitors_char); + + if (TieredCompilation) { + st->print(" "); + } + st->print(" "); // more indent + st->print(" "); // initial inlining indent + + for (int i = 0; i < inline_level; i++) st->print(" "); + + st->print("@ %d ", bci); // print bci + method->print_short_name(st); + st->print(" (%d bytes)", method->code_size()); + + if (msg != NULL) { + st->print(" %s", msg); + } + st->cr(); +} + +// ------------------------------------------------------------------ +// CompileTask::print_inline_indent +void CompileTask::print_inline_indent(int inline_level, outputStream* st) { + // 1234567 + st->print(" "); // print timestamp + // 1234 + st->print(" "); // print compilation number + // %s!bn + st->print(" "); // print method attributes + if (TieredCompilation) { + st->print(" "); + } + st->print(" "); // more indent + st->print(" "); // initial inlining indent + for (int i = 0; i < inline_level; i++) st->print(" "); +} + +// ------------------------------------------------------------------ +// CompileTask::print_compilation +void CompileTask::print_compilation(outputStream* st) { + oop rem = JNIHandles::resolve(method_handle()); + assert(rem != NULL && rem->is_method(), "must be"); + methodOop method = (methodOop) rem; + bool is_osr_method = osr_bci() != InvocationEntryBci; + print_compilation_impl(st, method, compile_id(), comp_level(), is_osr_method, osr_bci(), is_blocking()); +} // ------------------------------------------------------------------ // CompileTask::log_task @@ -874,6 +953,14 @@ return; } +#ifndef PRODUCT + if (osr_bci != -1 && !FLAG_IS_DEFAULT(OSROnlyBCI)) { + if ((OSROnlyBCI > 0) ? (OSROnlyBCI != osr_bci) : (-OSROnlyBCI == osr_bci)) { + // Positive OSROnlyBCI means only compile that bci. Negative means don't compile that BCI. + return; + } + } +#endif // If this method is already in the compile queue, then // we do not block the current thread. @@ -1078,7 +1165,13 @@ // do the compilation if (method->is_native()) { if (!PreferInterpreterNativeStubs) { - (void) AdapterHandlerLibrary::create_native_wrapper(method); + // Acquire our lock. + int compile_id; + { + MutexLocker locker(MethodCompileQueue_lock, THREAD); + compile_id = assign_compile_id(method, standard_entry_bci); + } + (void) AdapterHandlerLibrary::create_native_wrapper(method, compile_id); } else { return NULL; } @@ -1186,7 +1279,6 @@ assert(MethodCompileQueue_lock->owner() == Thread::current(), "must hold the compilation queue lock"); bool is_osr = (osr_bci != standard_entry_bci); - assert(!method->is_native(), "no longer compile natives"); uint id; if (CICountOSR && is_osr) { id = ++_osr_compilation_id;
--- a/src/share/vm/compiler/compileBroker.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/compiler/compileBroker.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, 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 @@ -56,7 +56,6 @@ int _hot_count; // information about its invocation counter const char* _comment; // more info about the task - void print_compilation(outputStream *st, methodOop method, char* method_name); public: CompileTask() { _lock = new Monitor(Mutex::nonleaf+2, "CompileTaskLock"); @@ -96,10 +95,26 @@ CompileTask* prev() const { return _prev; } void set_prev(CompileTask* prev) { _prev = prev; } +private: + static void print_compilation_impl(outputStream* st, methodOop method, int compile_id, int comp_level, bool is_osr_method = false, int osr_bci = -1, bool is_blocking = false, const char* msg = NULL); + +public: + void print_compilation(outputStream* st = tty); + static void print_compilation(outputStream* st, const nmethod* nm, const char* msg = NULL) { + print_compilation_impl(st, nm->method(), nm->compile_id(), nm->comp_level(), nm->is_osr_method(), nm->is_osr_method() ? nm->osr_entry_bci() : -1, /*is_blocking*/ false, msg); + } + + static void print_inlining(outputStream* st, ciMethod* method, int inline_level, int bci, const char* msg = NULL); + static void print_inlining(ciMethod* method, int inline_level, int bci, const char* msg = NULL) { + print_inlining(tty, method, inline_level, bci, msg); + } + + static void print_inline_indent(int inline_level, outputStream* st = tty); + void print(); void print_line(); + void print_line_on_error(outputStream* st, char* buf, int buflen); - void print_line_on_error(outputStream* st, char* buf, int buflen); void log_task(xmlStream* log); void log_task_queued(); void log_task_start(CompileLog* log);
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, 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 @@ -292,13 +292,15 @@ void CMSCollector::ref_processor_init() { if (_ref_processor == NULL) { // Allocate and initialize a reference processor - _ref_processor = ReferenceProcessor::create_ref_processor( - _span, // span - _cmsGen->refs_discovery_is_atomic(), // atomic_discovery - _cmsGen->refs_discovery_is_mt(), // mt_discovery - &_is_alive_closure, - ParallelGCThreads, - ParallelRefProcEnabled); + _ref_processor = + new ReferenceProcessor(_span, // span + (ParallelGCThreads > 1) && ParallelRefProcEnabled, // mt processing + (int) ParallelGCThreads, // mt processing degree + _cmsGen->refs_discovery_is_mt(), // mt discovery + (int) MAX2(ConcGCThreads, ParallelGCThreads), // mt discovery degree + _cmsGen->refs_discovery_is_atomic(), // discovery is not atomic + &_is_alive_closure, // closure for liveness info + false); // next field updates do not need write barrier // Initialize the _ref_processor field of CMSGen _cmsGen->set_ref_processor(_ref_processor); @@ -641,7 +643,7 @@ } // Support for multi-threaded concurrent phases - if (CollectedHeap::use_parallel_gc_threads() && CMSConcurrentMTEnabled) { + if (CMSConcurrentMTEnabled) { if (FLAG_IS_DEFAULT(ConcGCThreads)) { // just for now FLAG_SET_DEFAULT(ConcGCThreads, (ParallelGCThreads + 3)/4); @@ -1689,6 +1691,8 @@ MutexLockerEx y(CGC_lock, Mutex::_no_safepoint_check_flag); _full_gc_requested = true; CGC_lock->notify(); // nudge CMS thread + } else { + assert(gc_count > full_gc_count, "Error: causal loop"); } } @@ -1988,17 +1992,16 @@ // Temporarily widen the span of the weak reference processing to // the entire heap. MemRegion new_span(GenCollectedHeap::heap()->reserved_region()); - ReferenceProcessorSpanMutator x(ref_processor(), new_span); - + ReferenceProcessorSpanMutator rp_mut_span(ref_processor(), new_span); // Temporarily, clear the "is_alive_non_header" field of the // reference processor. - ReferenceProcessorIsAliveMutator y(ref_processor(), NULL); - + ReferenceProcessorIsAliveMutator rp_mut_closure(ref_processor(), NULL); // Temporarily make reference _processing_ single threaded (non-MT). - ReferenceProcessorMTProcMutator z(ref_processor(), false); - + ReferenceProcessorMTProcMutator rp_mut_mt_processing(ref_processor(), false); // Temporarily make refs discovery atomic - ReferenceProcessorAtomicMutator w(ref_processor(), true); + ReferenceProcessorAtomicMutator rp_mut_atomic(ref_processor(), true); + // Temporarily make reference _discovery_ single threaded (non-MT) + ReferenceProcessorMTDiscoveryMutator rp_mut_discovery(ref_processor(), false); ref_processor()->set_enqueuing_is_done(false); ref_processor()->enable_discovery(); @@ -4263,9 +4266,7 @@ // Refs discovery is already non-atomic. assert(!ref_processor()->discovery_is_atomic(), "Should be non-atomic"); - // Mutate the Refs discovery so it is MT during the - // multi-threaded marking phase. - ReferenceProcessorMTMutator mt(ref_processor(), num_workers > 1); + assert(ref_processor()->discovery_is_mt(), "Discovery should be MT"); DEBUG_ONLY(RememberKlassesChecker cmx(should_unload_classes());) conc_workers()->start_task(&tsk); while (tsk.yielded()) { @@ -4318,6 +4319,8 @@ ResourceMark rm; HandleMark hm; + // Temporarily make refs discovery single threaded (non-MT) + ReferenceProcessorMTDiscoveryMutator rp_mut_discovery(ref_processor(), false); MarkFromRootsClosure markFromRootsClosure(this, _span, &_markBitMap, &_markStack, &_revisitStack, CMSYield && asynch); // the last argument to iterate indicates whether the iteration @@ -4356,10 +4359,6 @@ verify_overflow_empty(); _abort_preclean = false; if (CMSPrecleaningEnabled) { - // Precleaning is currently not MT but the reference processor - // may be set for MT. Disable it temporarily here. - ReferenceProcessor* rp = ref_processor(); - ReferenceProcessorMTProcMutator z(rp, false); _eden_chunk_index = 0; size_t used = get_eden_used(); size_t capacity = get_eden_capacity(); @@ -4502,11 +4501,16 @@ _collectorState == AbortablePreclean, "incorrect state"); ResourceMark rm; HandleMark hm; + + // Precleaning is currently not MT but the reference processor + // may be set for MT. Disable it temporarily here. + ReferenceProcessor* rp = ref_processor(); + ReferenceProcessorMTDiscoveryMutator rp_mut_discovery(rp, false); + // Do one pass of scrubbing the discovered reference lists // to remove any reference objects with strongly-reachable // referents. if (clean_refs) { - ReferenceProcessor* rp = ref_processor(); CMSPrecleanRefsYieldClosure yield_cl(this); assert(rp->span().equals(_span), "Spans should be equal"); CMSKeepAliveClosure keep_alive(this, _span, &_markBitMap, @@ -5576,8 +5580,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) { - // Make refs discovery MT-safe - ReferenceProcessorMTMutator mt(ref_processor(), true); + // Make refs discovery MT-safe, if it isn't already: it may not + // necessarily be so, since it's possible that we are doing + // ST marking. + ReferenceProcessorMTDiscoveryMutator mt(ref_processor(), true); GenCollectedHeap::StrongRootsScope srs(gch); workers->run_task(&tsk); } else { @@ -5703,14 +5709,19 @@ CMSBitMap* mark_bit_map, AbstractWorkGang* workers, OopTaskQueueSet* task_queues): + // XXX Should superclass AGTWOQ also know about AWG since it knows + // about the task_queues used by the AWG? Then it could initialize + // the terminator() object. See 6984287. The set_for_termination() + // below is a temporary band-aid for the regression in 6984287. AbstractGangTaskWOopQueues("Process referents by policy in parallel", task_queues), _task(task), _collector(collector), _span(span), _mark_bit_map(mark_bit_map) - { - assert(_collector->_span.equals(_span) && !_span.is_empty(), - "Inconsistency in _span"); - } + { + assert(_collector->_span.equals(_span) && !_span.is_empty(), + "Inconsistency in _span"); + set_for_termination(workers->active_workers()); + } OopTaskQueueSet* task_queues() { return queues(); } @@ -5872,8 +5883,7 @@ // That is OK as long as the Reference lists are balanced (see // balance_all_queues() and balance_queues()). - - rp->set_mt_degree(ParallelGCThreads); + rp->set_active_mt_degree(ParallelGCThreads); CMSRefProcTaskExecutor task_executor(*this); rp->process_discovered_references(&_is_alive_closure, &cmsKeepAliveClosure, @@ -5920,14 +5930,18 @@ } { - TraceTime t("scrub symbol & string tables", PrintGCDetails, false, gclog_or_tty); - // Now clean up stale oops in StringTable - StringTable::unlink(&_is_alive_closure); + TraceTime t("scrub symbol table", PrintGCDetails, false, gclog_or_tty); // Clean up unreferenced symbols in symbol table. SymbolTable::unlink(); } } + if (should_unload_classes() || !JavaObjectsInPerm) { + TraceTime t("scrub string table", PrintGCDetails, false, gclog_or_tty); + // Now clean up stale oops in StringTable + StringTable::unlink(&_is_alive_closure); + } + verify_work_stacks_empty(); // Restore any preserved marks as a result of mark stack or // work queue overflow
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, 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 @@ -1133,7 +1133,7 @@ // rare that the cost of the CAS's involved is in the // noise. That's a measurement that should be done, and // the code simplified if that turns out to be the case. - return false; + return ConcGCThreads > 1; } // Override
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, 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,7 @@ volatile jint ConcurrentMarkSweepThread::_pending_yields = 0; volatile jint ConcurrentMarkSweepThread::_pending_decrements = 0; -volatile bool ConcurrentMarkSweepThread::_icms_enabled = false; +volatile jint ConcurrentMarkSweepThread::_icms_disabled = 0; volatile bool ConcurrentMarkSweepThread::_should_run = false; // When icms is enabled, the icms thread is stopped until explicitly // started. @@ -84,7 +84,7 @@ } } _sltMonitor = SLT_lock; - set_icms_enabled(CMSIncrementalMode); + assert(!CMSIncrementalMode || icms_is_enabled(), "Error"); } void ConcurrentMarkSweepThread::run() { @@ -341,11 +341,11 @@ void ConcurrentMarkSweepThread::icms_wait() { assert(UseConcMarkSweepGC && CMSIncrementalMode, "just checking"); - if (_should_stop && icms_enabled()) { + if (_should_stop && icms_is_enabled()) { MutexLockerEx x(iCMS_lock, Mutex::_no_safepoint_check_flag); trace_state("pause_icms"); _collector->stats().stop_cms_timer(); - while(!_should_run && icms_enabled()) { + while(!_should_run && icms_is_enabled()) { iCMS_lock->wait(Mutex::_no_safepoint_check_flag); } _collector->stats().start_cms_timer();
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, 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 @@ -40,7 +40,7 @@ class ConcurrentMarkSweepGeneration; class CMSCollector; -// The Concurrent Mark Sweep GC Thread (could be several in the future). +// The Concurrent Mark Sweep GC Thread class ConcurrentMarkSweepThread: public ConcurrentGCThread { friend class VMStructs; friend class ConcurrentMarkSweepGeneration; // XXX should remove friendship @@ -55,8 +55,6 @@ static SurrogateLockerThread::SLT_msg_type _sltBuffer; static Monitor* _sltMonitor; - ConcurrentMarkSweepThread* _next; - static bool _should_terminate; enum CMS_flag_type { @@ -84,7 +82,7 @@ // Tracing messages, enabled by CMSTraceThreadState. static inline void trace_state(const char* desc); - static volatile bool _icms_enabled; // iCMS enabled? + static volatile int _icms_disabled; // a counter to track #iCMS disable & enable static volatile bool _should_run; // iCMS may run static volatile bool _should_stop; // iCMS should stop @@ -214,10 +212,25 @@ // Incremental mode is enabled globally by the flag CMSIncrementalMode. It // must also be enabled/disabled dynamically to allow foreground collections. - static inline void enable_icms() { _icms_enabled = true; } - static inline void disable_icms() { _icms_enabled = false; } - static inline void set_icms_enabled(bool val) { _icms_enabled = val; } - static inline bool icms_enabled() { return _icms_enabled; } +#define ICMS_ENABLING_ASSERT \ + assert((CMSIncrementalMode && _icms_disabled >= 0) || \ + (!CMSIncrementalMode && _icms_disabled <= 0), "Error") + + static inline void enable_icms() { + ICMS_ENABLING_ASSERT; + Atomic::dec(&_icms_disabled); + } + static inline void disable_icms() { + ICMS_ENABLING_ASSERT; + Atomic::inc(&_icms_disabled); + } + static inline bool icms_is_disabled() { + ICMS_ENABLING_ASSERT; + return _icms_disabled > 0; + } + static inline bool icms_is_enabled() { + return !icms_is_disabled(); + } }; inline void ConcurrentMarkSweepThread::trace_state(const char* desc) {
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2011, 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 @@ -192,14 +192,18 @@ "total_collections() should be monotonically increasing"); MutexLockerEx x(FullGCCount_lock, Mutex::_no_safepoint_check_flag); + assert(_full_gc_count_before <= gch->total_full_collections(), "Error"); if (gch->total_full_collections() == _full_gc_count_before) { - // Disable iCMS until the full collection is done. + // Disable iCMS until the full collection is done, and + // remember that we did so. CMSCollector::disable_icms(); + _disabled_icms = true; // In case CMS thread was in icms_wait(), wake it up. CMSCollector::start_icms(); // Nudge the CMS thread to start a concurrent collection. CMSCollector::request_full_gc(_full_gc_count_before); } else { + assert(_full_gc_count_before < gch->total_full_collections(), "Error"); FullGCCount_lock->notify_all(); // Inform the Java thread its work is done } } @@ -259,6 +263,8 @@ FullGCCount_lock->wait(Mutex::_no_safepoint_check_flag); } } - // Enable iCMS back. - CMSCollector::enable_icms(); + // Enable iCMS back if we disabled it earlier. + if (_disabled_icms) { + CMSCollector::enable_icms(); + } }
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -128,11 +128,14 @@ // VM operation to invoke a concurrent collection of the heap as a // GenCollectedHeap heap. class VM_GenCollectFullConcurrent: public VM_GC_Operation { + bool _disabled_icms; public: VM_GenCollectFullConcurrent(unsigned int gc_count_before, unsigned int full_gc_count_before, GCCause::Cause gc_cause) - : VM_GC_Operation(gc_count_before, gc_cause, full_gc_count_before, true /* full */) { + : VM_GC_Operation(gc_count_before, gc_cause, full_gc_count_before, true /* full */), + _disabled_icms(false) + { assert(FullGCCount_lock != NULL, "Error"); assert(UseAsyncConcMarkSweepGC, "Else will hang caller"); }
--- a/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -373,7 +373,7 @@ // RSet updating while within an evacuation pause. // In this case worker_i should be the id of a GC worker thread assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause"); - assert(worker_i < (int) DirtyCardQueueSet::num_par_ids(), "incorrect worker id"); + assert(worker_i < (int) (ParallelGCThreads == 0 ? 1 : ParallelGCThreads), "incorrect worker id"); into_cset_dcq->enqueue(entry); } }
--- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1828,7 +1828,7 @@ G1CollectedHeap* g1h = G1CollectedHeap::heap(); _cleanup_list.verify_optional(); - FreeRegionList local_free_list("Local Cleanup List"); + FreeRegionList tmp_free_list("Tmp Free List"); if (G1ConcRegionFreeingVerbose) { gclog_or_tty->print_cr("G1ConcRegionFreeing [complete cleanup] : " @@ -1842,7 +1842,7 @@ HeapRegion* hr = _cleanup_list.remove_head(); assert(hr != NULL, "the list was not empty"); hr->rem_set()->clear(); - local_free_list.add_as_tail(hr); + tmp_free_list.add_as_tail(hr); // Instead of adding one region at a time to the secondary_free_list, // we accumulate them in the local list and move them a few at a @@ -1850,20 +1850,20 @@ // we do during this process. We'll also append the local list when // _cleanup_list is empty (which means we just removed the last // region from the _cleanup_list). - if ((local_free_list.length() % G1SecondaryFreeListAppendLength == 0) || + if ((tmp_free_list.length() % G1SecondaryFreeListAppendLength == 0) || _cleanup_list.is_empty()) { if (G1ConcRegionFreeingVerbose) { gclog_or_tty->print_cr("G1ConcRegionFreeing [complete cleanup] : " "appending "SIZE_FORMAT" entries to the " "secondary_free_list, clean list still has " SIZE_FORMAT" entries", - local_free_list.length(), + tmp_free_list.length(), _cleanup_list.length()); } { MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag); - g1h->secondary_free_list_add_as_tail(&local_free_list); + g1h->secondary_free_list_add_as_tail(&tmp_free_list); SecondaryFreeList_lock->notify_all(); } @@ -1874,7 +1874,7 @@ } } } - assert(local_free_list.is_empty(), "post-condition"); + assert(tmp_free_list.is_empty(), "post-condition"); } // Support closures for reference procssing in G1 @@ -2141,21 +2141,22 @@ G1CMKeepAliveClosure g1_keep_alive(g1h, this, nextMarkBitMap()); G1CMDrainMarkingStackClosure g1_drain_mark_stack(nextMarkBitMap(), &_markStack, &g1_keep_alive); - // We use the work gang from the G1CollectedHeap and we utilize all // the worker threads. - int active_workers = MAX2(MIN2(g1h->workers()->total_workers(), (int)_max_task_num), 1); + int active_workers = g1h->workers() ? g1h->workers()->total_workers() : 1; + active_workers = MAX2(MIN2(active_workers, (int)_max_task_num), 1); G1RefProcTaskExecutor par_task_executor(g1h, this, nextMarkBitMap(), g1h->workers(), active_workers); + if (rp->processing_is_mt()) { // Set the degree of MT here. If the discovery is done MT, there // may have been a different number of threads doing the discovery // and a different number of discovered lists may have Ref objects. // That is OK as long as the Reference lists are balanced (see // balance_all_queues() and balance_queues()). - rp->set_mt_degree(active_workers); + rp->set_active_mt_degree(active_workers); rp->process_discovered_references(&g1_is_alive, &g1_keep_alive, @@ -3182,7 +3183,7 @@ template <class T> void do_oop_work(T* p) { assert( _g1h->is_in_g1_reserved((HeapWord*) p), "invariant"); - assert(!_g1h->is_on_free_list( + assert(!_g1h->is_on_master_free_list( _g1h->heap_region_containing((HeapWord*) p)), "invariant"); oop obj = oopDesc::load_decode_heap_oop(p); @@ -3403,7 +3404,7 @@ void CMTask::push(oop obj) { HeapWord* objAddr = (HeapWord*) obj; assert(_g1h->is_in_g1_reserved(objAddr), "invariant"); - assert(!_g1h->is_on_free_list( + assert(!_g1h->is_on_master_free_list( _g1h->heap_region_containing((HeapWord*) objAddr)), "invariant"); assert(!_g1h->is_obj_ill(obj), "invariant"); assert(_nextMarkBitMap->isMarked(objAddr), "invariant"); @@ -3649,7 +3650,7 @@ (void*) obj); assert(_g1h->is_in_g1_reserved((HeapWord*) obj), "invariant" ); - assert(!_g1h->is_on_free_list( + assert(!_g1h->is_on_master_free_list( _g1h->heap_region_containing((HeapWord*) obj)), "invariant"); scan_object(obj);
--- a/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -237,9 +237,9 @@ // The following will finish freeing up any regions that we // found to be empty during cleanup. We'll do this part // without joining the suspendible set. If an evacuation pause - // takes places, then we would carry on freeing regions in + // takes place, then we would carry on freeing regions in // case they are needed by the pause. If a Full GC takes - // places, it would wait for us to process the regions + // place, it would wait for us to process the regions // reclaimed by cleanup. double cleanup_start_sec = os::elapsedTime();
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -479,7 +479,7 @@ // Private methods. HeapRegion* -G1CollectedHeap::new_region_try_secondary_free_list(size_t word_size) { +G1CollectedHeap::new_region_try_secondary_free_list() { MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag); while (!_secondary_free_list.is_empty() || free_regions_coming()) { if (!_secondary_free_list.is_empty()) { @@ -531,7 +531,7 @@ gclog_or_tty->print_cr("G1ConcRegionFreeing [region alloc] : " "forced to look at the secondary_free_list"); } - res = new_region_try_secondary_free_list(word_size); + res = new_region_try_secondary_free_list(); if (res != NULL) { return res; } @@ -543,7 +543,7 @@ gclog_or_tty->print_cr("G1ConcRegionFreeing [region alloc] : " "res == NULL, trying the secondary_free_list"); } - res = new_region_try_secondary_free_list(word_size); + res = new_region_try_secondary_free_list(); } if (res == NULL && do_expand) { if (expand(word_size * HeapWordSize)) { @@ -579,6 +579,9 @@ int G1CollectedHeap::humongous_obj_allocate_find_first(size_t num_regions, size_t word_size) { + assert(isHumongous(word_size), "word_size should be humongous"); + assert(num_regions * HeapRegion::GrainWords >= word_size, "pre-condition"); + int first = -1; if (num_regions == 1) { // Only one region to allocate, no need to go through the slower @@ -600,7 +603,7 @@ // request. If we are only allocating one region we use the common // region allocation code (see above). wait_while_free_regions_coming(); - append_secondary_free_list_if_not_empty(); + append_secondary_free_list_if_not_empty_with_lock(); if (free_regions() >= num_regions) { first = _hrs->find_contiguous(num_regions); @@ -608,7 +611,7 @@ for (int i = first; i < first + (int) num_regions; ++i) { HeapRegion* hr = _hrs->at(i); assert(hr->is_empty(), "sanity"); - assert(is_on_free_list(hr), "sanity"); + assert(is_on_master_free_list(hr), "sanity"); hr->set_pending_removal(true); } _free_list.remove_all_pending(num_regions); @@ -618,6 +621,126 @@ return first; } +HeapWord* +G1CollectedHeap::humongous_obj_allocate_initialize_regions(int first, + size_t num_regions, + size_t word_size) { + assert(first != -1, "pre-condition"); + assert(isHumongous(word_size), "word_size should be humongous"); + assert(num_regions * HeapRegion::GrainWords >= word_size, "pre-condition"); + + // Index of last region in the series + 1. + int last = first + (int) num_regions; + + // We need to initialize the region(s) we just discovered. This is + // a bit tricky given that it can happen concurrently with + // refinement threads refining cards on these regions and + // potentially wanting to refine the BOT as they are scanning + // those cards (this can happen shortly after a cleanup; see CR + // 6991377). So we have to set up the region(s) carefully and in + // a specific order. + + // The word size sum of all the regions we will allocate. + size_t word_size_sum = num_regions * HeapRegion::GrainWords; + assert(word_size <= word_size_sum, "sanity"); + + // This will be the "starts humongous" region. + HeapRegion* first_hr = _hrs->at(first); + // The header of the new object will be placed at the bottom of + // the first region. + HeapWord* new_obj = first_hr->bottom(); + // This will be the new end of the first region in the series that + // should also match the end of the last region in the seriers. + HeapWord* new_end = new_obj + word_size_sum; + // This will be the new top of the first region that will reflect + // this allocation. + HeapWord* new_top = new_obj + word_size; + + // First, we need to zero the header of the space that we will be + // allocating. When we update top further down, some refinement + // threads might try to scan the region. By zeroing the header we + // ensure that any thread that will try to scan the region will + // come across the zero klass word and bail out. + // + // NOTE: It would not have been correct to have used + // CollectedHeap::fill_with_object() and make the space look like + // an int array. The thread that is doing the allocation will + // later update the object header to a potentially different array + // type and, for a very short period of time, the klass and length + // fields will be inconsistent. This could cause a refinement + // thread to calculate the object size incorrectly. + Copy::fill_to_words(new_obj, oopDesc::header_size(), 0); + + // We will set up the first region as "starts humongous". This + // will also update the BOT covering all the regions to reflect + // that there is a single object that starts at the bottom of the + // first region. + first_hr->set_startsHumongous(new_top, new_end); + + // Then, if there are any, we will set up the "continues + // humongous" regions. + HeapRegion* hr = NULL; + for (int i = first + 1; i < last; ++i) { + hr = _hrs->at(i); + hr->set_continuesHumongous(first_hr); + } + // If we have "continues humongous" regions (hr != NULL), then the + // end of the last one should match new_end. + assert(hr == NULL || hr->end() == new_end, "sanity"); + + // Up to this point no concurrent thread would have been able to + // do any scanning on any region in this series. All the top + // fields still point to bottom, so the intersection between + // [bottom,top] and [card_start,card_end] will be empty. Before we + // update the top fields, we'll do a storestore to make sure that + // no thread sees the update to top before the zeroing of the + // object header and the BOT initialization. + OrderAccess::storestore(); + + // Now that the BOT and the object header have been initialized, + // we can update top of the "starts humongous" region. + assert(first_hr->bottom() < new_top && new_top <= first_hr->end(), + "new_top should be in this region"); + first_hr->set_top(new_top); + + // Now, we will update the top fields of the "continues humongous" + // regions. The reason we need to do this is that, otherwise, + // these regions would look empty and this will confuse parts of + // G1. For example, the code that looks for a consecutive number + // of empty regions will consider them empty and try to + // re-allocate them. We can extend is_empty() to also include + // !continuesHumongous(), but it is easier to just update the top + // fields here. The way we set top for all regions (i.e., top == + // end for all regions but the last one, top == new_top for the + // last one) is actually used when we will free up the humongous + // region in free_humongous_region(). + hr = NULL; + for (int i = first + 1; i < last; ++i) { + hr = _hrs->at(i); + if ((i + 1) == last) { + // last continues humongous region + assert(hr->bottom() < new_top && new_top <= hr->end(), + "new_top should fall on this region"); + hr->set_top(new_top); + } else { + // not last one + assert(new_top > hr->end(), "new_top should be above this region"); + hr->set_top(hr->end()); + } + } + // If we have continues humongous regions (hr != NULL), then the + // end of the last one should match new_end and its top should + // match new_top. + assert(hr == NULL || + (hr->end() == new_end && hr->top() == new_top), "sanity"); + + assert(first_hr->used() == word_size * HeapWordSize, "invariant"); + _summary_bytes_used += first_hr->used(); + _humongous_set.add(first_hr); + + return new_obj; +} + // If could fit into free regions w/o expansion, try. // Otherwise, if can expand, do so. // Otherwise, if using ex regions might help, try with ex given back. @@ -653,121 +776,16 @@ } } + HeapWord* result = NULL; if (first != -1) { - // Index of last region in the series + 1. - int last = first + (int) num_regions; - - // We need to initialize the region(s) we just discovered. This is - // a bit tricky given that it can happen concurrently with - // refinement threads refining cards on these regions and - // potentially wanting to refine the BOT as they are scanning - // those cards (this can happen shortly after a cleanup; see CR - // 6991377). So we have to set up the region(s) carefully and in - // a specific order. - - // The word size sum of all the regions we will allocate. - size_t word_size_sum = num_regions * HeapRegion::GrainWords; - assert(word_size <= word_size_sum, "sanity"); - - // This will be the "starts humongous" region. - HeapRegion* first_hr = _hrs->at(first); - // The header of the new object will be placed at the bottom of - // the first region. - HeapWord* new_obj = first_hr->bottom(); - // This will be the new end of the first region in the series that - // should also match the end of the last region in the seriers. - HeapWord* new_end = new_obj + word_size_sum; - // This will be the new top of the first region that will reflect - // this allocation. - HeapWord* new_top = new_obj + word_size; - - // First, we need to zero the header of the space that we will be - // allocating. When we update top further down, some refinement - // threads might try to scan the region. By zeroing the header we - // ensure that any thread that will try to scan the region will - // come across the zero klass word and bail out. - // - // NOTE: It would not have been correct to have used - // CollectedHeap::fill_with_object() and make the space look like - // an int array. The thread that is doing the allocation will - // later update the object header to a potentially different array - // type and, for a very short period of time, the klass and length - // fields will be inconsistent. This could cause a refinement - // thread to calculate the object size incorrectly. - Copy::fill_to_words(new_obj, oopDesc::header_size(), 0); - - // We will set up the first region as "starts humongous". This - // will also update the BOT covering all the regions to reflect - // that there is a single object that starts at the bottom of the - // first region. - first_hr->set_startsHumongous(new_top, new_end); - - // Then, if there are any, we will set up the "continues - // humongous" regions. - HeapRegion* hr = NULL; - for (int i = first + 1; i < last; ++i) { - hr = _hrs->at(i); - hr->set_continuesHumongous(first_hr); - } - // If we have "continues humongous" regions (hr != NULL), then the - // end of the last one should match new_end. - assert(hr == NULL || hr->end() == new_end, "sanity"); - - // Up to this point no concurrent thread would have been able to - // do any scanning on any region in this series. All the top - // fields still point to bottom, so the intersection between - // [bottom,top] and [card_start,card_end] will be empty. Before we - // update the top fields, we'll do a storestore to make sure that - // no thread sees the update to top before the zeroing of the - // object header and the BOT initialization. - OrderAccess::storestore(); - - // Now that the BOT and the object header have been initialized, - // we can update top of the "starts humongous" region. - assert(first_hr->bottom() < new_top && new_top <= first_hr->end(), - "new_top should be in this region"); - first_hr->set_top(new_top); - - // Now, we will update the top fields of the "continues humongous" - // regions. The reason we need to do this is that, otherwise, - // these regions would look empty and this will confuse parts of - // G1. For example, the code that looks for a consecutive number - // of empty regions will consider them empty and try to - // re-allocate them. We can extend is_empty() to also include - // !continuesHumongous(), but it is easier to just update the top - // fields here. The way we set top for all regions (i.e., top == - // end for all regions but the last one, top == new_top for the - // last one) is actually used when we will free up the humongous - // region in free_humongous_region(). - hr = NULL; - for (int i = first + 1; i < last; ++i) { - hr = _hrs->at(i); - if ((i + 1) == last) { - // last continues humongous region - assert(hr->bottom() < new_top && new_top <= hr->end(), - "new_top should fall on this region"); - hr->set_top(new_top); - } else { - // not last one - assert(new_top > hr->end(), "new_top should be above this region"); - hr->set_top(hr->end()); - } - } - // If we have continues humongous regions (hr != NULL), then the - // end of the last one should match new_end and its top should - // match new_top. - assert(hr == NULL || - (hr->end() == new_end && hr->top() == new_top), "sanity"); - - assert(first_hr->used() == word_size * HeapWordSize, "invariant"); - _summary_bytes_used += first_hr->used(); - _humongous_set.add(first_hr); - - return new_obj; + result = + humongous_obj_allocate_initialize_regions(first, num_regions, word_size); + assert(result != NULL, "it should always return a valid result"); } verify_region_sets_optional(); - return NULL; + + return result; } void @@ -1389,7 +1407,7 @@ g1_policy()->record_full_collection_start(); wait_while_free_regions_coming(); - append_secondary_free_list_if_not_empty(); + append_secondary_free_list_if_not_empty_with_lock(); gc_prologue(true); increment_total_collections(true /* full gc */); @@ -1444,7 +1462,7 @@ // how reference processing currently works in G1. // Temporarily make reference _discovery_ single threaded (non-MT). - ReferenceProcessorMTMutator rp_disc_ser(ref_processor(), false); + ReferenceProcessorMTDiscoveryMutator rp_disc_ser(ref_processor(), false); // Temporarily make refs discovery atomic ReferenceProcessorAtomicMutator rp_disc_atomic(ref_processor(), true); @@ -2201,16 +2219,16 @@ SharedHeap::ref_processing_init(); MemRegion mr = reserved_region(); - _ref_processor = ReferenceProcessor::create_ref_processor( - mr, // span - false, // Reference discovery is not atomic - true, // mt_discovery - &_is_alive_closure, // is alive closure - // for efficiency - ParallelGCThreads, - ParallelRefProcEnabled, - true); // Setting next fields of discovered - // lists requires a barrier. + _ref_processor = + new ReferenceProcessor(mr, // span + ParallelRefProcEnabled && (ParallelGCThreads > 1), // mt processing + (int) ParallelGCThreads, // degree of mt processing + ParallelGCThreads > 1 || ConcGCThreads > 1, // mt discovery + (int) MAX2(ParallelGCThreads, ConcGCThreads), // degree of mt discovery + false, // Reference discovery is not atomic + &_is_alive_closure, // is alive closure for efficiency + true); // Setting next fields of discovered + // lists requires a barrier. } size_t G1CollectedHeap::capacity() const { @@ -3377,15 +3395,14 @@ TraceMemoryManagerStats tms(false /* fullGC */); - // If there are any free regions available on the secondary_free_list - // make sure we append them to the free_list. However, we don't - // have to wait for the rest of the cleanup operation to - // finish. If it's still going on that's OK. If we run out of - // regions, the region allocation code will check the - // secondary_free_list and potentially wait if more free regions - // are coming (see new_region_try_secondary_free_list()). + // If the secondary_free_list is not empty, append it to the + // free_list. No need to wait for the cleanup operation to finish; + // the region allocation code will check the secondary_free_list + // and wait if necessary. If the G1StressConcRegionFreeing flag is + // set, skip this step so that the region allocation code has to + // get entries from the secondary_free_list. if (!G1StressConcRegionFreeing) { - append_secondary_free_list_if_not_empty(); + append_secondary_free_list_if_not_empty_with_lock(); } increment_gc_time_stamp(); @@ -5199,7 +5216,7 @@ size_t rs_lengths = 0; while (cur != NULL) { - assert(!is_on_free_list(cur), "sanity"); + assert(!is_on_master_free_list(cur), "sanity"); if (non_young) { if (cur->is_young()) { @@ -5543,13 +5560,10 @@ return; } - { - MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag); - // Make sure we append the secondary_free_list on the free_list so - // that all free regions we will come across can be safely - // attributed to the free_list. - append_secondary_free_list(); - } + // Make sure we append the secondary_free_list on the free_list so + // that all free regions we will come across can be safely + // attributed to the free_list. + append_secondary_free_list_if_not_empty_with_lock(); // Finally, make sure that the region accounting in the lists is // consistent with what we see in the heap.
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -56,7 +56,6 @@ class ConcurrentMark; class ConcurrentMarkThread; class ConcurrentG1Refine; -class ConcurrentZFThread; typedef OverflowTaskQueue<StarTask> RefToScanQueue; typedef GenericTaskQueueSet<RefToScanQueue> RefToScanQueueSet; @@ -64,12 +63,6 @@ typedef int RegionIdx_t; // needs to hold [ 0..max_regions() ) typedef int CardIdx_t; // needs to hold [ 0..CardsPerRegion ) -enum G1GCThreadGroups { - G1CRGroup = 0, - G1ZFGroup = 1, - G1CMGroup = 2 -}; - enum GCAllocPurpose { GCAllocForTenured, GCAllocForSurvived, @@ -294,9 +287,9 @@ // These are macros so that, if the assert fires, we get the correct // line number, file, etc. -#define heap_locking_asserts_err_msg(__extra_message) \ +#define heap_locking_asserts_err_msg(_extra_message_) \ err_msg("%s : Heap_lock locked: %s, at safepoint: %s, is VM thread: %s", \ - (__extra_message), \ + (_extra_message_), \ BOOL_TO_STR(Heap_lock->owned_by_self()), \ BOOL_TO_STR(SafepointSynchronize::is_at_safepoint()), \ BOOL_TO_STR(Thread::current()->is_VM_thread())) @@ -307,11 +300,11 @@ heap_locking_asserts_err_msg("should be holding the Heap_lock")); \ } while (0) -#define assert_heap_locked_or_at_safepoint(__should_be_vm_thread) \ +#define assert_heap_locked_or_at_safepoint(_should_be_vm_thread_) \ do { \ assert(Heap_lock->owned_by_self() || \ (SafepointSynchronize::is_at_safepoint() && \ - ((__should_be_vm_thread) == Thread::current()->is_VM_thread())), \ + ((_should_be_vm_thread_) == Thread::current()->is_VM_thread())), \ heap_locking_asserts_err_msg("should be holding the Heap_lock or " \ "should be at a safepoint")); \ } while (0) @@ -338,10 +331,10 @@ "should not be at a safepoint")); \ } while (0) -#define assert_at_safepoint(__should_be_vm_thread) \ +#define assert_at_safepoint(_should_be_vm_thread_) \ do { \ assert(SafepointSynchronize::is_at_safepoint() && \ - ((__should_be_vm_thread) == Thread::current()->is_VM_thread()), \ + ((_should_be_vm_thread_) == Thread::current()->is_VM_thread()), \ heap_locking_asserts_err_msg("should be at a safepoint")); \ } while (0) @@ -371,35 +364,40 @@ // will check whether there's anything available in the // secondary_free_list and/or wait for more regions to appear in that // list, if _free_regions_coming is set. - HeapRegion* new_region_try_secondary_free_list(size_t word_size); + HeapRegion* new_region_try_secondary_free_list(); - // It will try to allocate a single non-humongous HeapRegion - // sufficient for an allocation of the given word_size. If - // do_expand is true, it will attempt to expand the heap if - // necessary to satisfy the allocation request. Note that word_size - // is only used to make sure that we expand sufficiently but, given - // that the allocation request is assumed not to be humongous, - // having word_size is not strictly necessary (expanding by a single - // region will always be sufficient). But let's keep that parameter - // in case we need it in the future. + // Try to allocate a single non-humongous HeapRegion sufficient for + // an allocation of the given word_size. If do_expand is true, + // attempt to expand the heap if necessary to satisfy the allocation + // request. HeapRegion* new_region_work(size_t word_size, bool do_expand); - // It will try to allocate a new region to be used for allocation by - // mutator threads. It will not try to expand the heap if not region - // is available. + // Try to allocate a new region to be used for allocation by a + // mutator thread. Attempt to expand the heap if no region is + // available. HeapRegion* new_alloc_region(size_t word_size) { return new_region_work(word_size, false /* do_expand */); } - // It will try to allocate a new region to be used for allocation by - // a GC thread. It will try to expand the heap if no region is - // available. + // Try to allocate a new region to be used for allocation by a GC + // thread. Attempt to expand the heap if no region is available. HeapRegion* new_gc_alloc_region(int purpose, size_t word_size); + // Attempt to satisfy a humongous allocation request of the given + // size by finding a contiguous set of free regions of num_regions + // length and remove them from the master free list. Return the + // index of the first region or -1 if the search was unsuccessful. int humongous_obj_allocate_find_first(size_t num_regions, size_t word_size); - // Attempt to allocate an object of the given (very large) "word_size". - // Returns "NULL" on failure. + // Initialize a contiguous set of free regions of length num_regions + // and starting at index first so that they appear as a single + // humongous region. + HeapWord* humongous_obj_allocate_initialize_regions(int first, + size_t num_regions, + size_t word_size); + + // Attempt to allocate a humongous object of the given size. Return + // NULL if unsuccessful. HeapWord* humongous_obj_allocate(size_t word_size); // The following two methods, allocate_new_tlab() and @@ -776,7 +774,7 @@ // Invoke "save_marks" on all heap regions. void save_marks(); - // It frees a non-humongous region by initializing its contents and + // Frees a non-humongous region by initializing its contents and // adding it to the free list that's passed as a parameter (this is // usually a local list which will be appended to the master free // list later). The used bytes of freed regions are accumulated in @@ -787,13 +785,13 @@ FreeRegionList* free_list, bool par); - // It frees a humongous region by collapsing it into individual - // regions and calling free_region() for each of them. The freed - // regions will be added to the free list that's passed as a parameter - // (this is usually a local list which will be appended to the - // master free list later). The used bytes of freed regions are - // accumulated in pre_used. If par is true, the region's RSet will - // not be freed up. The assumption is that this will be done later. + // Frees a humongous region by collapsing it into individual regions + // and calling free_region() for each of them. The freed regions + // will be added to the free list that's passed as a parameter (this + // is usually a local list which will be appended to the master free + // list later). The used bytes of freed regions are accumulated in + // pre_used. If par is true, the region's RSet will not be freed + // up. The assumption is that this will be done later. void free_humongous_region(HeapRegion* hr, size_t* pre_used, FreeRegionList* free_list, @@ -1046,13 +1044,13 @@ #endif // HEAP_REGION_SET_FORCE_VERIFY #ifdef ASSERT - bool is_on_free_list(HeapRegion* hr) { + bool is_on_master_free_list(HeapRegion* hr) { return hr->containing_set() == &_free_list; } - bool is_on_humongous_set(HeapRegion* hr) { + bool is_in_humongous_set(HeapRegion* hr) { return hr->containing_set() == &_humongous_set; -} + } #endif // ASSERT // Wrapper for the region list operations that can be called from @@ -1066,7 +1064,9 @@ _free_list.add_as_tail(&_secondary_free_list); } - void append_secondary_free_list_if_not_empty() { + void append_secondary_free_list_if_not_empty_with_lock() { + // If the secondary free list looks empty there's no reason to + // take the lock and then try to append it. if (!_secondary_free_list.is_empty()) { MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag); append_secondary_free_list();
--- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -81,6 +81,57 @@ // </NEW PREDICTION> +// Help class for avoiding interleaved logging +class LineBuffer: public StackObj { + +private: + static const int BUFFER_LEN = 1024; + static const int INDENT_CHARS = 3; + char _buffer[BUFFER_LEN]; + int _indent_level; + int _cur; + + void vappend(const char* format, va_list ap) { + int res = vsnprintf(&_buffer[_cur], BUFFER_LEN - _cur, format, ap); + if (res != -1) { + _cur += res; + } else { + DEBUG_ONLY(warning("buffer too small in LineBuffer");) + _buffer[BUFFER_LEN -1] = 0; + _cur = BUFFER_LEN; // vsnprintf above should not add to _buffer if we are called again + } + } + +public: + explicit LineBuffer(int indent_level): _indent_level(indent_level), _cur(0) { + for (; (_cur < BUFFER_LEN && _cur < (_indent_level * INDENT_CHARS)); _cur++) { + _buffer[_cur] = ' '; + } + } + +#ifndef PRODUCT + ~LineBuffer() { + assert(_cur == _indent_level * INDENT_CHARS, "pending data in buffer - append_and_print_cr() not called?"); + } +#endif + + void append(const char* format, ...) { + va_list ap; + va_start(ap, format); + vappend(format, ap); + va_end(ap); + } + + void append_and_print_cr(const char* format, ...) { + va_list ap; + va_start(ap, format); + vappend(format, ap); + va_end(ap); + gclog_or_tty->print_cr("%s", _buffer); + _cur = _indent_level * INDENT_CHARS; + } +}; + G1CollectorPolicy::G1CollectorPolicy() : _parallel_gc_threads(G1CollectedHeap::use_parallel_gc_threads() ? ParallelGCThreads : 1), @@ -1016,10 +1067,8 @@ bool summary) { double min = data[0], max = data[0]; double total = 0.0; - int j; - for (j = 0; j < level; ++j) - gclog_or_tty->print(" "); - gclog_or_tty->print("[%s (ms):", str); + LineBuffer buf(level); + buf.append("[%s (ms):", str); for (uint i = 0; i < ParallelGCThreads; ++i) { double val = data[i]; if (val < min) @@ -1027,18 +1076,16 @@ if (val > max) max = val; total += val; - gclog_or_tty->print(" %3.1lf", val); + buf.append(" %3.1lf", val); } if (summary) { - gclog_or_tty->print_cr(""); + buf.append_and_print_cr(""); double avg = total / (double) ParallelGCThreads; - gclog_or_tty->print(" "); - for (j = 0; j < level; ++j) - gclog_or_tty->print(" "); - gclog_or_tty->print("Avg: %5.1lf, Min: %5.1lf, Max: %5.1lf", + buf.append(" "); + buf.append("Avg: %5.1lf, Min: %5.1lf, Max: %5.1lf", avg, min, max); } - gclog_or_tty->print_cr("]"); + buf.append_and_print_cr("]"); } void G1CollectorPolicy::print_par_sizes(int level, @@ -1047,10 +1094,8 @@ bool summary) { double min = data[0], max = data[0]; double total = 0.0; - int j; - for (j = 0; j < level; ++j) - gclog_or_tty->print(" "); - gclog_or_tty->print("[%s :", str); + LineBuffer buf(level); + buf.append("[%s :", str); for (uint i = 0; i < ParallelGCThreads; ++i) { double val = data[i]; if (val < min) @@ -1058,34 +1103,28 @@ if (val > max) max = val; total += val; - gclog_or_tty->print(" %d", (int) val); + buf.append(" %d", (int) val); } if (summary) { - gclog_or_tty->print_cr(""); + buf.append_and_print_cr(""); double avg = total / (double) ParallelGCThreads; - gclog_or_tty->print(" "); - for (j = 0; j < level; ++j) - gclog_or_tty->print(" "); - gclog_or_tty->print("Sum: %d, Avg: %d, Min: %d, Max: %d", + buf.append(" "); + buf.append("Sum: %d, Avg: %d, Min: %d, Max: %d", (int)total, (int)avg, (int)min, (int)max); } - gclog_or_tty->print_cr("]"); + buf.append_and_print_cr("]"); } void G1CollectorPolicy::print_stats (int level, const char* str, double value) { - for (int j = 0; j < level; ++j) - gclog_or_tty->print(" "); - gclog_or_tty->print_cr("[%s: %5.1lf ms]", str, value); + LineBuffer(level).append_and_print_cr("[%s: %5.1lf ms]", str, value); } void G1CollectorPolicy::print_stats (int level, const char* str, int value) { - for (int j = 0; j < level; ++j) - gclog_or_tty->print(" "); - gclog_or_tty->print_cr("[%s: %d]", str, value); + LineBuffer(level).append_and_print_cr("[%s: %d]", str, value); } double G1CollectorPolicy::avg_value (double* data) { @@ -2060,17 +2099,11 @@ _g1->collection_set_iterate(&cs_closure); } -static void print_indent(int level) { - for (int j = 0; j < level+1; ++j) - gclog_or_tty->print(" "); -} - void G1CollectorPolicy::print_summary (int level, const char* str, NumberSeq* seq) const { double sum = seq->sum(); - print_indent(level); - gclog_or_tty->print_cr("%-24s = %8.2lf s (avg = %8.2lf ms)", + LineBuffer(level + 1).append_and_print_cr("%-24s = %8.2lf s (avg = %8.2lf ms)", str, sum / 1000.0, seq->avg()); } @@ -2078,8 +2111,7 @@ const char* str, NumberSeq* seq) const { print_summary(level, str, seq); - print_indent(level + 5); - gclog_or_tty->print_cr("(num = %5d, std dev = %8.2lf ms, max = %8.2lf ms)", + LineBuffer(level + 6).append_and_print_cr("(num = %5d, std dev = %8.2lf ms, max = %8.2lf ms)", seq->num(), seq->sd(), seq->maximum()); } @@ -2087,6 +2119,7 @@ NumberSeq* other_times_ms, NumberSeq* calc_other_times_ms) const { bool should_print = false; + LineBuffer buf(level + 2); double max_sum = MAX2(fabs(other_times_ms->sum()), fabs(calc_other_times_ms->sum())); @@ -2095,8 +2128,7 @@ double sum_ratio = max_sum / min_sum; if (sum_ratio > 1.1) { should_print = true; - print_indent(level + 1); - gclog_or_tty->print_cr("## CALCULATED OTHER SUM DOESN'T MATCH RECORDED ###"); + buf.append_and_print_cr("## CALCULATED OTHER SUM DOESN'T MATCH RECORDED ###"); } double max_avg = MAX2(fabs(other_times_ms->avg()), @@ -2106,30 +2138,25 @@ double avg_ratio = max_avg / min_avg; if (avg_ratio > 1.1) { should_print = true; - print_indent(level + 1); - gclog_or_tty->print_cr("## CALCULATED OTHER AVG DOESN'T MATCH RECORDED ###"); + buf.append_and_print_cr("## CALCULATED OTHER AVG DOESN'T MATCH RECORDED ###"); } if (other_times_ms->sum() < -0.01) { - print_indent(level + 1); - gclog_or_tty->print_cr("## RECORDED OTHER SUM IS NEGATIVE ###"); + buf.append_and_print_cr("## RECORDED OTHER SUM IS NEGATIVE ###"); } if (other_times_ms->avg() < -0.01) { - print_indent(level + 1); - gclog_or_tty->print_cr("## RECORDED OTHER AVG IS NEGATIVE ###"); + buf.append_and_print_cr("## RECORDED OTHER AVG IS NEGATIVE ###"); } if (calc_other_times_ms->sum() < -0.01) { should_print = true; - print_indent(level + 1); - gclog_or_tty->print_cr("## CALCULATED OTHER SUM IS NEGATIVE ###"); + buf.append_and_print_cr("## CALCULATED OTHER SUM IS NEGATIVE ###"); } if (calc_other_times_ms->avg() < -0.01) { should_print = true; - print_indent(level + 1); - gclog_or_tty->print_cr("## CALCULATED OTHER AVG IS NEGATIVE ###"); + buf.append_and_print_cr("## CALCULATED OTHER AVG IS NEGATIVE ###"); } if (should_print) @@ -2210,10 +2237,9 @@ } } } else { - print_indent(0); - gclog_or_tty->print_cr("none"); + LineBuffer(1).append_and_print_cr("none"); } - gclog_or_tty->print_cr(""); + LineBuffer(0).append_and_print_cr(""); } void G1CollectorPolicy::print_tracing_info() const { @@ -2532,7 +2558,7 @@ jint regions_added = parKnownGarbageCl.marked_regions_added(); _hrSorted->incNumMarkedHeapRegions(regions_added); if (G1PrintParCleanupStats) { - gclog_or_tty->print(" Thread %d called %d times, added %d regions to list.\n", + gclog_or_tty->print_cr(" Thread %d called %d times, added %d regions to list.", i, parKnownGarbageCl.invokes(), regions_added); } }
--- a/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -185,22 +185,22 @@ G1CollectedHeap* _g1h; ModRefBarrierSet* _mrbs; CompactPoint _cp; - size_t _pre_used; - FreeRegionList _free_list; HumongousRegionSet _humongous_proxy_set; void free_humongous_region(HeapRegion* hr) { HeapWord* end = hr->end(); + size_t dummy_pre_used; + FreeRegionList dummy_free_list("Dummy Free List for G1MarkSweep"); + assert(hr->startsHumongous(), "Only the start of a humongous region should be freed."); - _g1h->free_humongous_region(hr, &_pre_used, &_free_list, + _g1h->free_humongous_region(hr, &dummy_pre_used, &dummy_free_list, &_humongous_proxy_set, false /* par */); - // Do we also need to do this for the continues humongous regions - // we just collapsed? hr->prepare_for_compaction(&_cp); // Also clear the part of the card table that will be unused after // compaction. _mrbs->clear(MemRegion(hr->compaction_top(), end)); + dummy_free_list.remove_all(); } public: @@ -208,8 +208,6 @@ : _g1h(G1CollectedHeap::heap()), _mrbs(G1CollectedHeap::heap()->mr_bs()), _cp(NULL, cs, cs->initialize_threshold()), - _pre_used(0), - _free_list("Local Free List for G1MarkSweep"), _humongous_proxy_set("G1MarkSweep Humongous Proxy Set") { } void update_sets() { @@ -219,7 +217,6 @@ NULL, /* free_list */ &_humongous_proxy_set, false /* par */); - _free_list.remove_all(); } bool doHeapRegion(HeapRegion* hr) {
--- a/src/share/vm/gc_implementation/g1/g1RemSet.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -86,28 +86,6 @@ bool idempotent() { return true; } }; -class IntoCSRegionClosure: public HeapRegionClosure { - IntoCSOopClosure _blk; - G1CollectedHeap* _g1; -public: - IntoCSRegionClosure(G1CollectedHeap* g1, OopsInHeapRegionClosure* blk) : - _g1(g1), _blk(g1, blk) {} - bool doHeapRegion(HeapRegion* r) { - if (!r->in_collection_set()) { - _blk.set_region(r); - if (r->isHumongous()) { - if (r->startsHumongous()) { - oop obj = oop(r->bottom()); - obj->oop_iterate(&_blk); - } - } else { - r->oop_before_save_marks_iterate(&_blk); - } - } - return false; - } -}; - class VerifyRSCleanCardOopClosure: public OopClosure { G1CollectedHeap* _g1; public: @@ -329,7 +307,7 @@ // is during RSet updating within an evacuation pause. // In this case worker_i should be the id of a GC worker thread. assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause"); - assert(worker_i < (int) DirtyCardQueueSet::num_par_ids(), "should be a GC worker"); + assert(worker_i < (int) (ParallelGCThreads == 0 ? 1 : ParallelGCThreads), "should be a GC worker"); if (_g1rs->concurrentRefineOneCard(card_ptr, worker_i, true)) { // 'card_ptr' contains references that point into the collection
--- a/src/share/vm/gc_implementation/g1/heapRegion.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/g1/heapRegion.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -53,8 +53,8 @@ class HeapRegionSetBase; #define HR_FORMAT "%d:["PTR_FORMAT","PTR_FORMAT","PTR_FORMAT"]" -#define HR_FORMAT_PARAMS(__hr) (__hr)->hrs_index(), (__hr)->bottom(), \ - (__hr)->top(), (__hr)->end() +#define HR_FORMAT_PARAMS(_hr_) (_hr_)->hrs_index(), (_hr_)->bottom(), \ + (_hr_)->top(), (_hr_)->end() // A dirty card to oop closure for heap regions. It // knows how to get the G1 heap and how to use the bitmap @@ -518,13 +518,13 @@ containing_set, _containing_set)); _containing_set = containing_set; -} + } HeapRegionSetBase* containing_set() { return _containing_set; } #else // ASSERT void set_containing_set(HeapRegionSetBase* containing_set) { } - // containing_set() is only used in asserts so there's not reason + // containing_set() is only used in asserts so there's no reason // to provide a dummy version of it. #endif // ASSERT @@ -535,14 +535,15 @@ bool pending_removal() { return _pending_removal; } void set_pending_removal(bool pending_removal) { - // We can only set pending_removal to true, if it's false and the - // region belongs to a set. - assert(!pending_removal || - (!_pending_removal && containing_set() != NULL), "pre-condition"); - // We can only set pending_removal to false, if it's true and the - // region does not belong to a set. - assert( pending_removal || - ( _pending_removal && containing_set() == NULL), "pre-condition"); + if (pending_removal) { + assert(!_pending_removal && containing_set() != NULL, + "can only set pending removal to true if it's false and " + "the region belongs to a region set"); + } else { + assert( _pending_removal && containing_set() == NULL, + "can only set pending removal to false if it's true and " + "the region does not belong to a region set"); + } _pending_removal = pending_removal; }
--- a/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -165,7 +165,7 @@ assert(num_so_far <= num, "post-condition"); if (num_so_far == num) { - // we find enough space for the humongous object + // we found enough space for the humongous object assert(from <= first && first < _regions.length(), "post-condition"); assert(first < curr && (curr - first) == (int) num, "post-condition"); for (int i = first; i < first + (int) num; ++i) {
--- a/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -76,7 +76,8 @@ // that are available for allocation. size_t free_suffix(); - // Finds a contiguous set of empty regions of length num. + // Find a contiguous set of empty regions of length num and return + // the index of the first region or -1 if the search was unsuccessful. int find_contiguous(size_t num); // Apply the "doHeapRegion" method of "blk" to all regions in "this",
--- a/src/share/vm/gc_implementation/g1/heapRegionSet.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/g1/heapRegionSet.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -42,7 +42,7 @@ return region_num; } -void HeapRegionSetBase::fill_in_ext_msg(hrl_ext_msg* msg, const char* message) { +void HeapRegionSetBase::fill_in_ext_msg(hrs_ext_msg* msg, const char* message) { msg->append("[%s] %s " "ln: "SIZE_FORMAT" rn: "SIZE_FORMAT" " "cy: "SIZE_FORMAT" ud: "SIZE_FORMAT, @@ -109,30 +109,30 @@ // for the verification calls. If we do verification without the // appropriate locks and the set changes underneath our feet // verification might fail and send us on a wild goose chase. - hrl_assert_mt_safety_ok(this); + hrs_assert_mt_safety_ok(this); guarantee(( is_empty() && length() == 0 && region_num() == 0 && total_used_bytes() == 0 && total_capacity_bytes() == 0) || (!is_empty() && length() >= 0 && region_num() >= 0 && total_used_bytes() >= 0 && total_capacity_bytes() >= 0), - hrl_ext_msg(this, "invariant")); + hrs_ext_msg(this, "invariant")); guarantee((!regions_humongous() && region_num() == length()) || ( regions_humongous() && region_num() >= length()), - hrl_ext_msg(this, "invariant")); + hrs_ext_msg(this, "invariant")); guarantee(!regions_empty() || total_used_bytes() == 0, - hrl_ext_msg(this, "invariant")); + hrs_ext_msg(this, "invariant")); guarantee(total_used_bytes() <= total_capacity_bytes(), - hrl_ext_msg(this, "invariant")); + hrs_ext_msg(this, "invariant")); } void HeapRegionSetBase::verify_start() { // See comment in verify() about MT safety and verification. - hrl_assert_mt_safety_ok(this); + hrs_assert_mt_safety_ok(this); assert(!_verify_in_progress, - hrl_ext_msg(this, "verification should not be in progress")); + hrs_ext_msg(this, "verification should not be in progress")); // Do the basic verification first before we do the checks over the regions. HeapRegionSetBase::verify(); @@ -146,11 +146,11 @@ void HeapRegionSetBase::verify_next_region(HeapRegion* hr) { // See comment in verify() about MT safety and verification. - hrl_assert_mt_safety_ok(this); + hrs_assert_mt_safety_ok(this); assert(_verify_in_progress, - hrl_ext_msg(this, "verification should be in progress")); + hrs_ext_msg(this, "verification should be in progress")); - guarantee(verify_region(hr, this), hrl_ext_msg(this, "region verification")); + guarantee(verify_region(hr, this), hrs_ext_msg(this, "region verification")); _calc_length += 1; if (!hr->isHumongous()) { @@ -164,28 +164,28 @@ void HeapRegionSetBase::verify_end() { // See comment in verify() about MT safety and verification. - hrl_assert_mt_safety_ok(this); + hrs_assert_mt_safety_ok(this); assert(_verify_in_progress, - hrl_ext_msg(this, "verification should be in progress")); + hrs_ext_msg(this, "verification should be in progress")); guarantee(length() == _calc_length, - hrl_err_msg("[%s] length: "SIZE_FORMAT" should be == " + hrs_err_msg("[%s] length: "SIZE_FORMAT" should be == " "calc length: "SIZE_FORMAT, name(), length(), _calc_length)); guarantee(region_num() == _calc_region_num, - hrl_err_msg("[%s] region num: "SIZE_FORMAT" should be == " + hrs_err_msg("[%s] region num: "SIZE_FORMAT" should be == " "calc region num: "SIZE_FORMAT, name(), region_num(), _calc_region_num)); guarantee(total_capacity_bytes() == _calc_total_capacity_bytes, - hrl_err_msg("[%s] capacity bytes: "SIZE_FORMAT" should be == " + hrs_err_msg("[%s] capacity bytes: "SIZE_FORMAT" should be == " "calc capacity bytes: "SIZE_FORMAT, name(), total_capacity_bytes(), _calc_total_capacity_bytes)); guarantee(total_used_bytes() == _calc_total_used_bytes, - hrl_err_msg("[%s] used bytes: "SIZE_FORMAT" should be == " + hrs_err_msg("[%s] used bytes: "SIZE_FORMAT" should be == " "calc used bytes: "SIZE_FORMAT, name(), total_used_bytes(), _calc_total_used_bytes)); @@ -221,9 +221,9 @@ //////////////////// HeapRegionSet //////////////////// void HeapRegionSet::update_from_proxy(HeapRegionSet* proxy_set) { - hrl_assert_mt_safety_ok(this); - hrl_assert_mt_safety_ok(proxy_set); - hrl_assert_sets_match(this, proxy_set); + hrs_assert_mt_safety_ok(this); + hrs_assert_mt_safety_ok(proxy_set); + hrs_assert_sets_match(this, proxy_set); verify_optional(); proxy_set->verify_optional(); @@ -231,19 +231,19 @@ if (proxy_set->is_empty()) return; assert(proxy_set->length() <= _length, - hrl_err_msg("[%s] proxy set length: "SIZE_FORMAT" " + hrs_err_msg("[%s] proxy set length: "SIZE_FORMAT" " "should be <= length: "SIZE_FORMAT, name(), proxy_set->length(), _length)); _length -= proxy_set->length(); assert(proxy_set->region_num() <= _region_num, - hrl_err_msg("[%s] proxy set region num: "SIZE_FORMAT" " + hrs_err_msg("[%s] proxy set region num: "SIZE_FORMAT" " "should be <= region num: "SIZE_FORMAT, name(), proxy_set->region_num(), _region_num)); _region_num -= proxy_set->region_num(); assert(proxy_set->total_used_bytes() <= _total_used_bytes, - hrl_err_msg("[%s] proxy set used bytes: "SIZE_FORMAT" " + hrs_err_msg("[%s] proxy set used bytes: "SIZE_FORMAT" " "should be <= used bytes: "SIZE_FORMAT, name(), proxy_set->total_used_bytes(), _total_used_bytes)); @@ -257,13 +257,13 @@ //////////////////// HeapRegionLinkedList //////////////////// -void HeapRegionLinkedList::fill_in_ext_msg_extra(hrl_ext_msg* msg) { +void HeapRegionLinkedList::fill_in_ext_msg_extra(hrs_ext_msg* msg) { msg->append(" hd: "PTR_FORMAT" tl: "PTR_FORMAT, head(), tail()); } void HeapRegionLinkedList::add_as_tail(HeapRegionLinkedList* from_list) { - hrl_assert_mt_safety_ok(this); - hrl_assert_mt_safety_ok(from_list); + hrs_assert_mt_safety_ok(this); + hrs_assert_mt_safety_ok(from_list); verify_optional(); from_list->verify_optional(); @@ -283,10 +283,10 @@ #endif // ASSERT if (_tail != NULL) { - assert(length() > 0 && _head != NULL, hrl_ext_msg(this, "invariant")); + assert(length() > 0 && _head != NULL, hrs_ext_msg(this, "invariant")); _tail->set_next(from_list->_head); } else { - assert(length() == 0 && _head == NULL, hrl_ext_msg(this, "invariant")); + assert(length() == 0 && _head == NULL, hrs_ext_msg(this, "invariant")); _head = from_list->_head; } _tail = from_list->_tail; @@ -301,12 +301,12 @@ } void HeapRegionLinkedList::remove_all() { - hrl_assert_mt_safety_ok(this); + hrs_assert_mt_safety_ok(this); verify_optional(); HeapRegion* curr = _head; while (curr != NULL) { - hrl_assert_region_ok(this, curr, this); + hrs_assert_region_ok(this, curr, this); HeapRegion* next = curr->next(); curr->set_next(NULL); @@ -319,9 +319,9 @@ } void HeapRegionLinkedList::remove_all_pending(size_t target_count) { - hrl_assert_mt_safety_ok(this); - assert(target_count > 1, hrl_ext_msg(this, "pre-condition")); - assert(!is_empty(), hrl_ext_msg(this, "pre-condition")); + hrs_assert_mt_safety_ok(this); + assert(target_count > 1, hrs_ext_msg(this, "pre-condition")); + assert(!is_empty(), hrs_ext_msg(this, "pre-condition")); verify_optional(); DEBUG_ONLY(size_t old_length = length();) @@ -330,27 +330,27 @@ HeapRegion* prev = NULL; size_t count = 0; while (curr != NULL) { - hrl_assert_region_ok(this, curr, this); + hrs_assert_region_ok(this, curr, this); HeapRegion* next = curr->next(); if (curr->pending_removal()) { assert(count < target_count, - hrl_err_msg("[%s] should not come across more regions " + hrs_err_msg("[%s] should not come across more regions " "pending for removal than target_count: "SIZE_FORMAT, name(), target_count)); if (prev == NULL) { - assert(_head == curr, hrl_ext_msg(this, "invariant")); + assert(_head == curr, hrs_ext_msg(this, "invariant")); _head = next; } else { - assert(_head != curr, hrl_ext_msg(this, "invariant")); + assert(_head != curr, hrs_ext_msg(this, "invariant")); prev->set_next(next); } if (next == NULL) { - assert(_tail == curr, hrl_ext_msg(this, "invariant")); + assert(_tail == curr, hrs_ext_msg(this, "invariant")); _tail = prev; } else { - assert(_tail != curr, hrl_ext_msg(this, "invariant")); + assert(_tail != curr, hrs_ext_msg(this, "invariant")); } curr->set_next(NULL); @@ -371,10 +371,10 @@ } assert(count == target_count, - hrl_err_msg("[%s] count: "SIZE_FORMAT" should be == " + hrs_err_msg("[%s] count: "SIZE_FORMAT" should be == " "target_count: "SIZE_FORMAT, name(), count, target_count)); assert(length() + target_count == old_length, - hrl_err_msg("[%s] new length should be consistent " + hrs_err_msg("[%s] new length should be consistent " "new length: "SIZE_FORMAT" old length: "SIZE_FORMAT" " "target_count: "SIZE_FORMAT, name(), length(), old_length, target_count)); @@ -385,7 +385,7 @@ void HeapRegionLinkedList::verify() { // See comment in HeapRegionSetBase::verify() about MT safety and // verification. - hrl_assert_mt_safety_ok(this); + hrs_assert_mt_safety_ok(this); // This will also do the basic verification too. verify_start(); @@ -399,7 +399,7 @@ count += 1; guarantee(count < _unrealistically_long_length, - hrl_err_msg("[%s] the calculated length: "SIZE_FORMAT" " + hrs_err_msg("[%s] the calculated length: "SIZE_FORMAT" " "seems very long, is there maybe a cycle? " "curr: "PTR_FORMAT" prev0: "PTR_FORMAT" " "prev1: "PTR_FORMAT" length: "SIZE_FORMAT, @@ -410,7 +410,7 @@ curr = curr->next(); } - guarantee(_tail == prev0, hrl_ext_msg(this, "post-condition")); + guarantee(_tail == prev0, hrs_ext_msg(this, "post-condition")); verify_end(); }
--- a/src/share/vm/gc_implementation/g1/heapRegionSet.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/g1/heapRegionSet.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -28,8 +28,8 @@ #include "gc_implementation/g1/heapRegion.hpp" // Large buffer for some cases where the output might be larger than normal. -#define HRL_ERR_MSG_BUFSZ 512 -typedef FormatBuffer<HRL_ERR_MSG_BUFSZ> hrl_err_msg; +#define HRS_ERR_MSG_BUFSZ 512 +typedef FormatBuffer<HRS_ERR_MSG_BUFSZ> hrs_err_msg; // Set verification will be forced either if someone defines // HEAP_REGION_SET_FORCE_VERIFY to be 1, or in builds in which @@ -45,10 +45,10 @@ // (e.g., length, region num, used bytes sum) plus any shared // functionality (e.g., verification). -class hrl_ext_msg; +class hrs_ext_msg; class HeapRegionSetBase VALUE_OBJ_CLASS_SPEC { - friend class hrl_ext_msg; + friend class hrs_ext_msg; protected: static size_t calculate_region_num(HeapRegion* hr); @@ -104,10 +104,10 @@ virtual bool check_mt_safety() { return true; } // fill_in_ext_msg() writes the the values of the set's attributes - // in the custom err_msg (hrl_ext_msg). fill_in_ext_msg_extra() + // in the custom err_msg (hrs_ext_msg). fill_in_ext_msg_extra() // allows subclasses to append further information. - virtual void fill_in_ext_msg_extra(hrl_ext_msg* msg) { } - void fill_in_ext_msg(hrl_ext_msg* msg, const char* message); + virtual void fill_in_ext_msg_extra(hrs_ext_msg* msg) { } + void fill_in_ext_msg(hrs_ext_msg* msg, const char* message); // It updates the fields of the set to reflect hr being added to // the set. @@ -170,9 +170,9 @@ // the fields of the associated set. This can be very helpful in // diagnosing failures. -class hrl_ext_msg : public hrl_err_msg { +class hrs_ext_msg : public hrs_err_msg { public: - hrl_ext_msg(HeapRegionSetBase* set, const char* message) : hrl_err_msg("") { + hrs_ext_msg(HeapRegionSetBase* set, const char* message) : hrs_err_msg("") { set->fill_in_ext_msg(this, message); } }; @@ -180,25 +180,25 @@ // These two macros are provided for convenience, to keep the uses of // these two asserts a bit more concise. -#define hrl_assert_mt_safety_ok(_set_) \ +#define hrs_assert_mt_safety_ok(_set_) \ do { \ - assert((_set_)->check_mt_safety(), hrl_ext_msg((_set_), "MT safety")); \ + assert((_set_)->check_mt_safety(), hrs_ext_msg((_set_), "MT safety")); \ } while (0) -#define hrl_assert_region_ok(_set_, _hr_, _expected_) \ +#define hrs_assert_region_ok(_set_, _hr_, _expected_) \ do { \ assert((_set_)->verify_region((_hr_), (_expected_)), \ - hrl_ext_msg((_set_), "region verification")); \ + hrs_ext_msg((_set_), "region verification")); \ } while (0) //////////////////// HeapRegionSet //////////////////// -#define hrl_assert_sets_match(_set1_, _set2_) \ +#define hrs_assert_sets_match(_set1_, _set2_) \ do { \ assert(((_set1_)->regions_humongous() == \ (_set2_)->regions_humongous()) && \ ((_set1_)->regions_empty() == (_set2_)->regions_empty()), \ - hrl_err_msg("the contents of set %s and set %s should match", \ + hrs_err_msg("the contents of set %s and set %s should match", \ (_set1_)->name(), (_set2_)->name())); \ } while (0) @@ -267,7 +267,7 @@ HeapRegion* tail() { return _tail; } protected: - virtual void fill_in_ext_msg_extra(hrl_ext_msg* msg); + virtual void fill_in_ext_msg_extra(hrs_ext_msg* msg); // See the comment for HeapRegionSetBase::clear() virtual void clear(); @@ -309,10 +309,10 @@ virtual void print_on(outputStream* out, bool print_contents = false); }; -//////////////////// HeapRegionLinkedList //////////////////// +//////////////////// HeapRegionLinkedListIterator //////////////////// -// Iterator class that provides a convenient way to iterator over the -// regions in a HeapRegionLinkedList instance. +// Iterator class that provides a convenient way to iterate over the +// regions of a HeapRegionLinkedList instance. class HeapRegionLinkedListIterator : public StackObj { private:
--- a/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -42,8 +42,8 @@ } inline void HeapRegionSetBase::add_internal(HeapRegion* hr) { - hrl_assert_region_ok(this, hr, NULL); - assert(hr->next() == NULL, hrl_ext_msg(this, "should not already be linked")); + hrs_assert_region_ok(this, hr, NULL); + assert(hr->next() == NULL, hrs_ext_msg(this, "should not already be linked")); update_for_addition(hr); hr->set_containing_set(this); @@ -51,7 +51,7 @@ inline void HeapRegionSetBase::update_for_removal(HeapRegion* hr) { // Assumes the caller has already verified the region. - assert(_length > 0, hrl_ext_msg(this, "pre-condition")); + assert(_length > 0, hrs_ext_msg(this, "pre-condition")); _length -= 1; size_t region_num_diff; @@ -61,22 +61,22 @@ region_num_diff = calculate_region_num(hr); } assert(region_num_diff <= _region_num, - hrl_err_msg("[%s] region's region num: "SIZE_FORMAT" " + hrs_err_msg("[%s] region's region num: "SIZE_FORMAT" " "should be <= region num: "SIZE_FORMAT, name(), region_num_diff, _region_num)); _region_num -= region_num_diff; size_t used_bytes = hr->used(); assert(used_bytes <= _total_used_bytes, - hrl_err_msg("[%s] region's used bytes: "SIZE_FORMAT" " + hrs_err_msg("[%s] region's used bytes: "SIZE_FORMAT" " "should be <= used bytes: "SIZE_FORMAT, name(), used_bytes, _total_used_bytes)); _total_used_bytes -= used_bytes; } inline void HeapRegionSetBase::remove_internal(HeapRegion* hr) { - hrl_assert_region_ok(this, hr, this); - assert(hr->next() == NULL, hrl_ext_msg(this, "should already be unlinked")); + hrs_assert_region_ok(this, hr, this); + assert(hr->next() == NULL, hrs_ext_msg(this, "should already be unlinked")); hr->set_containing_set(NULL); update_for_removal(hr); @@ -85,13 +85,13 @@ //////////////////// HeapRegionSet //////////////////// inline void HeapRegionSet::add(HeapRegion* hr) { - hrl_assert_mt_safety_ok(this); + hrs_assert_mt_safety_ok(this); // add_internal() will verify the region. add_internal(hr); } inline void HeapRegionSet::remove(HeapRegion* hr) { - hrl_assert_mt_safety_ok(this); + hrs_assert_mt_safety_ok(this); // remove_internal() will verify the region. remove_internal(hr); } @@ -101,8 +101,8 @@ // No need to fo the MT safety check here given that this method // does not update the contents of the set but instead accumulates // the changes in proxy_set which is assumed to be thread-local. - hrl_assert_sets_match(this, proxy_set); - hrl_assert_region_ok(this, hr, this); + hrs_assert_sets_match(this, proxy_set); + hrs_assert_region_ok(this, hr, this); hr->set_containing_set(NULL); proxy_set->update_for_addition(hr); @@ -111,10 +111,10 @@ //////////////////// HeapRegionLinkedList //////////////////// inline void HeapRegionLinkedList::add_as_tail(HeapRegion* hr) { - hrl_assert_mt_safety_ok(this); + hrs_assert_mt_safety_ok(this); assert((length() == 0 && _head == NULL && _tail == NULL) || (length() > 0 && _head != NULL && _tail != NULL), - hrl_ext_msg(this, "invariant")); + hrs_ext_msg(this, "invariant")); // add_internal() will verify the region. add_internal(hr); @@ -128,10 +128,10 @@ } inline HeapRegion* HeapRegionLinkedList::remove_head() { - hrl_assert_mt_safety_ok(this); - assert(!is_empty(), hrl_ext_msg(this, "the list should not be empty")); + hrs_assert_mt_safety_ok(this); + assert(!is_empty(), hrs_ext_msg(this, "the list should not be empty")); assert(length() > 0 && _head != NULL && _tail != NULL, - hrl_ext_msg(this, "invariant")); + hrs_ext_msg(this, "invariant")); // We need to unlink it first. HeapRegion* hr = _head; @@ -147,7 +147,7 @@ } inline HeapRegion* HeapRegionLinkedList::remove_head_or_null() { - hrl_assert_mt_safety_ok(this); + hrs_assert_mt_safety_ok(this); if (!is_empty()) { return remove_head();
--- a/src/share/vm/gc_implementation/g1/heapRegionSets.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/g1/heapRegionSets.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -52,7 +52,7 @@ FreeList_lock->owned_by_self())) || (!SafepointSynchronize::is_at_safepoint() && Heap_lock->owned_by_self()), - hrl_ext_msg(this, "master free list MT safety protocol")); + hrs_ext_msg(this, "master free list MT safety protocol")); return FreeRegionList::check_mt_safety(); } @@ -65,7 +65,7 @@ // while holding the SecondaryFreeList_lock. guarantee(SecondaryFreeList_lock->owned_by_self(), - hrl_ext_msg(this, "secondary free list MT safety protocol")); + hrs_ext_msg(this, "secondary free list MT safety protocol")); return FreeRegionList::check_mt_safety(); } @@ -81,7 +81,7 @@ return HeapRegionSet::verify_region_extra(hr); } -//////////////////// HumongousRegionSet //////////////////// +//////////////////// MasterHumongousRegionSet //////////////////// bool MasterHumongousRegionSet::check_mt_safety() { // Master Humongous Set MT safety protocol: @@ -97,6 +97,6 @@ OldSets_lock->owned_by_self())) || (!SafepointSynchronize::is_at_safepoint() && Heap_lock->owned_by_self()), - hrl_ext_msg(this, "master humongous set MT safety protocol")); + hrs_ext_msg(this, "master humongous set MT safety protocol")); return HumongousRegionSet::check_mt_safety(); }
--- a/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, 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 @@ -1530,13 +1530,15 @@ { if (_ref_processor == NULL) { // Allocate and initialize a reference processor - _ref_processor = ReferenceProcessor::create_ref_processor( - _reserved, // span - refs_discovery_is_atomic(), // atomic_discovery - refs_discovery_is_mt(), // mt_discovery - NULL, // is_alive_non_header - ParallelGCThreads, - ParallelRefProcEnabled); + _ref_processor = + new ReferenceProcessor(_reserved, // span + ParallelRefProcEnabled && (ParallelGCThreads > 1), // mt processing + (int) ParallelGCThreads, // mt processing degree + refs_discovery_is_mt(), // mt discovery + (int) ParallelGCThreads, // mt discovery degree + refs_discovery_is_atomic(), // atomic_discovery + NULL, // is_alive_non_header + false); // write barrier for next field updates } }
--- a/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, 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,9 +58,7 @@ void PSMarkSweep::initialize() { MemRegion mr = Universe::heap()->reserved_region(); - _ref_processor = new ReferenceProcessor(mr, - true, // atomic_discovery - false); // mt_discovery + _ref_processor = new ReferenceProcessor(mr); // a vanilla ref proc _counters = new CollectorCounters("PSMarkSweep", 1); }
--- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2011, 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 @@ -827,13 +827,15 @@ assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); MemRegion mr = heap->reserved_region(); - _ref_processor = ReferenceProcessor::create_ref_processor( - mr, // span - true, // atomic_discovery - true, // mt_discovery - &_is_alive_closure, - ParallelGCThreads, - ParallelRefProcEnabled); + _ref_processor = + new ReferenceProcessor(mr, // span + ParallelRefProcEnabled && (ParallelGCThreads > 1), // mt processing + (int) ParallelGCThreads, // mt processing degree + true, // mt discovery + (int) ParallelGCThreads, // mt discovery degree + true, // atomic_discovery + &_is_alive_closure, // non-header is alive closure + false); // write barrier for next field updates _counters = new CollectorCounters("PSParallelCompact", 1); // Initialize static fields in ParCompactionManager.
--- a/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -411,7 +411,7 @@ template <class T> void PSPromotionManager::process_array_chunk_work( oop obj, int start, int end) { - assert(start < end, "invariant"); + assert(start <= end, "invariant"); T* const base = (T*)objArrayOop(obj)->base(); T* p = base + start; T* const chunk_end = base + end;
--- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2011, 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 "classfile/symbolTable.hpp" #include "gc_implementation/parallelScavenge/cardTableExtension.hpp" #include "gc_implementation/parallelScavenge/gcTaskManager.hpp" #include "gc_implementation/parallelScavenge/generationSizer.hpp" @@ -439,6 +440,14 @@ reference_processor()->enqueue_discovered_references(NULL); } + if (!JavaObjectsInPerm) { + // Unlink any dead interned Strings + StringTable::unlink(&_is_alive_closure); + // Process the remaining live ones + PSScavengeRootsClosure root_closure(promotion_manager); + StringTable::oops_do(&root_closure); + } + // Finally, flush the promotion_manager's labs, and deallocate its stacks. PSPromotionManager::post_scavenge(); @@ -796,13 +805,15 @@ // Initialize ref handling object for scavenging. MemRegion mr = young_gen->reserved(); - _ref_processor = ReferenceProcessor::create_ref_processor( - mr, // span - true, // atomic_discovery - true, // mt_discovery - NULL, // is_alive_non_header - ParallelGCThreads, - ParallelRefProcEnabled); + _ref_processor = + new ReferenceProcessor(mr, // span + ParallelRefProcEnabled && (ParallelGCThreads > 1), // mt processing + (int) ParallelGCThreads, // mt processing degree + true, // mt discovery + (int) ParallelGCThreads, // mt discovery degree + true, // atomic_discovery + NULL, // header provides liveness info + false); // next field updates do not need write barrier // Cache the cardtable BarrierSet* bs = Universe::heap()->barrier_set();
--- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -86,4 +86,21 @@ } } +class PSScavengeRootsClosure: public OopClosure { + private: + PSPromotionManager* _promotion_manager; + + protected: + template <class T> void do_oop_work(T *p) { + if (PSScavenge::should_scavenge(p)) { + // We never card mark roots, maybe call a func without test? + PSScavenge::copy_and_push_safe_barrier(_promotion_manager, p); + } + } + public: + PSScavengeRootsClosure(PSPromotionManager* pm) : _promotion_manager(pm) { } + void do_oop(oop* p) { PSScavengeRootsClosure::do_oop_work(p); } + void do_oop(narrowOop* p) { PSScavengeRootsClosure::do_oop_work(p); } +}; + #endif // SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSSCAVENGE_INLINE_HPP
--- a/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -30,7 +30,7 @@ #include "gc_implementation/parallelScavenge/psMarkSweep.hpp" #include "gc_implementation/parallelScavenge/psPromotionManager.hpp" #include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" -#include "gc_implementation/parallelScavenge/psScavenge.hpp" +#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" #include "gc_implementation/parallelScavenge/psTasks.hpp" #include "memory/iterator.hpp" #include "memory/universe.hpp" @@ -46,24 +46,6 @@ // ScavengeRootsTask // -// Define before use -class PSScavengeRootsClosure: public OopClosure { - private: - PSPromotionManager* _promotion_manager; - - protected: - template <class T> void do_oop_work(T *p) { - if (PSScavenge::should_scavenge(p)) { - // We never card mark roots, maybe call a func without test? - PSScavenge::copy_and_push_safe_barrier(_promotion_manager, p); - } - } - public: - PSScavengeRootsClosure(PSPromotionManager* pm) : _promotion_manager(pm) { } - void do_oop(oop* p) { PSScavengeRootsClosure::do_oop_work(p); } - void do_oop(narrowOop* p) { PSScavengeRootsClosure::do_oop_work(p); } -}; - void ScavengeRootsTask::do_it(GCTaskManager* manager, uint which) { assert(Universe::heap()->is_gc_active(), "called outside gc");
--- a/src/share/vm/interpreter/bytecodeInterpreter.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/interpreter/bytecodeInterpreter.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -656,7 +656,7 @@ // oop rcvr = locals[0].j.r; oop rcvr; if (METHOD->is_static()) { - rcvr = METHOD->constants()->pool_holder()->klass_part()->java_mirror(); + rcvr = METHOD->constants()->pool_holder()->java_mirror(); } else { rcvr = LOCALS_OBJECT(0); VERIFY_OOP(rcvr); @@ -2111,8 +2111,8 @@ break; case JVM_CONSTANT_Class: - VERIFY_OOP(constants->resolved_klass_at(index)->klass_part()->java_mirror()); - SET_STACK_OBJECT(constants->resolved_klass_at(index)->klass_part()->java_mirror(), 0); + VERIFY_OOP(constants->resolved_klass_at(index)->java_mirror()); + SET_STACK_OBJECT(constants->resolved_klass_at(index)->java_mirror(), 0); break; case JVM_CONSTANT_UnresolvedString:
--- a/src/share/vm/interpreter/interpreterRuntime.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/interpreter/interpreterRuntime.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -118,7 +118,7 @@ if (tag.is_unresolved_klass() || tag.is_klass()) { klassOop klass = pool->klass_at(index, CHECK); - oop java_class = klass->klass_part()->java_mirror(); + oop java_class = klass->java_mirror(); thread->set_vm_result(java_class); } else { #ifdef ASSERT @@ -983,7 +983,8 @@ ConstantPoolCacheEntry *cp_entry)) // check the access_flags for the field in the klass - instanceKlass* ik = instanceKlass::cast((klassOop)cp_entry->f1()); + + instanceKlass* ik = instanceKlass::cast(java_lang_Class::as_klassOop(cp_entry->f1())); typeArrayOop fields = ik->fields(); int index = cp_entry->field_index(); assert(index < fields->length(), "holders field index is out of range"); @@ -1009,7 +1010,7 @@ // non-static field accessors have an object, but we need a handle h_obj = Handle(thread, obj); } - instanceKlassHandle h_cp_entry_f1(thread, (klassOop)cp_entry->f1()); + instanceKlassHandle h_cp_entry_f1(thread, java_lang_Class::as_klassOop(cp_entry->f1())); jfieldID fid = jfieldIDWorkaround::to_jfieldID(h_cp_entry_f1, cp_entry->f2(), is_static); JvmtiExport::post_field_access(thread, method(thread), bcp(thread), h_cp_entry_f1, h_obj, fid); IRT_END @@ -1017,7 +1018,7 @@ IRT_ENTRY(void, InterpreterRuntime::post_field_modification(JavaThread *thread, oopDesc* obj, ConstantPoolCacheEntry *cp_entry, jvalue *value)) - klassOop k = (klassOop)cp_entry->f1(); + klassOop k = java_lang_Class::as_klassOop(cp_entry->f1()); // check the access_flags for the field in the klass instanceKlass* ik = instanceKlass::cast(k);
--- a/src/share/vm/interpreter/linkResolver.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/interpreter/linkResolver.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -176,7 +176,7 @@ void LinkResolver::lookup_method_in_klasses(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) { methodOop result_oop = klass->uncached_lookup_method(name, signature); - if (EnableMethodHandles && result_oop != NULL) { + if (EnableInvokeDynamic && result_oop != NULL) { switch (result_oop->intrinsic_id()) { case vmIntrinsics::_invokeExact: case vmIntrinsics::_invokeGeneric: @@ -214,7 +214,7 @@ KlassHandle klass, Symbol* name, Symbol* signature, KlassHandle current_klass, TRAPS) { - if (EnableMethodHandles && + if (EnableInvokeDynamic && klass() == SystemDictionary::MethodHandle_klass() && methodOopDesc::is_method_handle_invoke_name(name)) { if (!THREAD->is_Compiler_thread() && !MethodHandles::enabled()) {
--- a/src/share/vm/memory/collectorPolicy.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/memory/collectorPolicy.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, 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 @@ -293,10 +293,11 @@ // Determine maximum size of gen0 size_t max_new_size = 0; - if (FLAG_IS_CMDLINE(MaxNewSize)) { + if (FLAG_IS_CMDLINE(MaxNewSize) || FLAG_IS_ERGO(MaxNewSize)) { if (MaxNewSize < min_alignment()) { max_new_size = min_alignment(); - } else if (MaxNewSize >= max_heap_byte_size()) { + } + if (MaxNewSize >= max_heap_byte_size()) { max_new_size = align_size_down(max_heap_byte_size() - min_alignment(), min_alignment()); warning("MaxNewSize (" SIZE_FORMAT "k) is equal to or " @@ -333,7 +334,7 @@ assert(max_new_size > 0, "All paths should set max_new_size"); // Given the maximum gen0 size, determine the initial and - // minimum sizes. + // minimum gen0 sizes. if (max_heap_byte_size() == min_heap_byte_size()) { // The maximum and minimum heap sizes are the same so @@ -396,7 +397,7 @@ } if (PrintGCDetails && Verbose) { - gclog_or_tty->print_cr("Minimum gen0 " SIZE_FORMAT " Initial gen0 " + gclog_or_tty->print_cr("1: Minimum gen0 " SIZE_FORMAT " Initial gen0 " SIZE_FORMAT " Maximum gen0 " SIZE_FORMAT, min_gen0_size(), initial_gen0_size(), max_gen0_size()); } @@ -448,7 +449,7 @@ // At this point the minimum, initial and maximum sizes // of the overall heap and of gen0 have been determined. // The maximum gen1 size can be determined from the maximum gen0 - // and maximum heap size since not explicit flags exits + // and maximum heap size since no explicit flags exits // for setting the gen1 maximum. _max_gen1_size = max_heap_byte_size() - _max_gen0_size; _max_gen1_size = @@ -494,13 +495,13 @@ "generation sizes: using maximum heap = " SIZE_FORMAT " -XX:OldSize flag is being ignored", max_heap_byte_size()); - } + } // If there is an inconsistency between the OldSize and the minimum and/or // initial size of gen0, since OldSize was explicitly set, OldSize wins. if (adjust_gen0_sizes(&_min_gen0_size, &_min_gen1_size, min_heap_byte_size(), OldSize)) { if (PrintGCDetails && Verbose) { - gclog_or_tty->print_cr("Minimum gen0 " SIZE_FORMAT " Initial gen0 " + gclog_or_tty->print_cr("2: Minimum gen0 " SIZE_FORMAT " Initial gen0 " SIZE_FORMAT " Maximum gen0 " SIZE_FORMAT, min_gen0_size(), initial_gen0_size(), max_gen0_size()); } @@ -509,7 +510,7 @@ if (adjust_gen0_sizes(&_initial_gen0_size, &_initial_gen1_size, initial_heap_byte_size(), OldSize)) { if (PrintGCDetails && Verbose) { - gclog_or_tty->print_cr("Minimum gen0 " SIZE_FORMAT " Initial gen0 " + gclog_or_tty->print_cr("3: Minimum gen0 " SIZE_FORMAT " Initial gen0 " SIZE_FORMAT " Maximum gen0 " SIZE_FORMAT, min_gen0_size(), initial_gen0_size(), max_gen0_size()); }
--- a/src/share/vm/memory/compactingPermGenGen.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/memory/compactingPermGenGen.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, 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 @@ -105,7 +105,7 @@ public: enum { - vtbl_list_size = 16, // number of entries in the shared space vtable list. + vtbl_list_size = 17, // number of entries in the shared space vtable list. num_virtuals = 200 // number of virtual methods in Klass (or // subclass) objects, or greater. };
--- a/src/share/vm/memory/dump.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/memory/dump.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,16 +80,7 @@ oop obj = *p; if (obj->klass() == SystemDictionary::String_klass()) { - int hash; - typeArrayOop value = java_lang_String::value(obj); - int length = java_lang_String::length(obj); - if (length == 0) { - hash = 0; - } else { - int offset = java_lang_String::offset(obj); - jchar* s = value->char_at_addr(offset); - hash = StringTable::hash_string(s, length); - } + int hash = java_lang_String::hash_string(obj); obj->int_field_put(hash_offset, hash); } } @@ -1561,6 +1552,7 @@ // thread because it requires object allocation. LinkClassesClosure lcc(Thread::current()); object_iterate(&lcc); + ensure_parsability(false); // arg is actually don't care tty->print_cr("done. "); // Create and dump the shared spaces.
--- a/src/share/vm/memory/generation.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/memory/generation.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -83,14 +83,11 @@ } // By default we get a single threaded default reference processor; -// generations needing multi-threaded refs discovery override this method. +// generations needing multi-threaded refs processing or discovery override this method. void Generation::ref_processor_init() { assert(_ref_processor == NULL, "a reference processor already exists"); assert(!_reserved.is_empty(), "empty generation?"); - _ref_processor = - new ReferenceProcessor(_reserved, // span - refs_discovery_is_atomic(), // atomic_discovery - refs_discovery_is_mt()); // mt_discovery + _ref_processor = new ReferenceProcessor(_reserved); // a vanilla reference processor if (_ref_processor == NULL) { vm_exit_during_initialization("Could not allocate ReferenceProcessor object"); }
--- a/src/share/vm/memory/oopFactory.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/memory/oopFactory.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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,12 +117,12 @@ } -klassOop oopFactory::new_instanceKlass(int vtable_len, int itable_len, +klassOop oopFactory::new_instanceKlass(Symbol* name, int vtable_len, int itable_len, int static_field_size, unsigned int nonstatic_oop_map_count, ReferenceType rt, TRAPS) { instanceKlassKlass* ikk = instanceKlassKlass::cast(Universe::instanceKlassKlassObj()); - return ikk->allocate_instance_klass(vtable_len, itable_len, static_field_size, nonstatic_oop_map_count, rt, CHECK_NULL); + return ikk->allocate_instance_klass(name, vtable_len, itable_len, static_field_size, nonstatic_oop_map_count, rt, CHECK_NULL); }
--- a/src/share/vm/memory/oopFactory.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/memory/oopFactory.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -72,7 +72,8 @@ TRAPS); // Instance classes - static klassOop new_instanceKlass(int vtable_len, int itable_len, + static klassOop new_instanceKlass(Symbol* name, + int vtable_len, int itable_len, int static_field_size, unsigned int nonstatic_oop_map_count, ReferenceType rt, TRAPS);
--- a/src/share/vm/memory/referenceProcessor.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/memory/referenceProcessor.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, 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 @@ -102,40 +102,17 @@ "Unrecongnized RefDiscoveryPolicy"); } -ReferenceProcessor* -ReferenceProcessor::create_ref_processor(MemRegion span, - bool atomic_discovery, - bool mt_discovery, - BoolObjectClosure* is_alive_non_header, - int parallel_gc_threads, - bool mt_processing, - bool dl_needs_barrier) { - int mt_degree = 1; - if (parallel_gc_threads > 1) { - mt_degree = parallel_gc_threads; - } - ReferenceProcessor* rp = - new ReferenceProcessor(span, atomic_discovery, - mt_discovery, mt_degree, - mt_processing && (parallel_gc_threads > 0), - dl_needs_barrier); - if (rp == NULL) { - vm_exit_during_initialization("Could not allocate ReferenceProcessor object"); - } - rp->set_is_alive_non_header(is_alive_non_header); - rp->setup_policy(false /* default soft ref policy */); - return rp; -} - ReferenceProcessor::ReferenceProcessor(MemRegion span, - bool atomic_discovery, + bool mt_processing, + int mt_processing_degree, bool mt_discovery, - int mt_degree, - bool mt_processing, + int mt_discovery_degree, + bool atomic_discovery, + BoolObjectClosure* is_alive_non_header, bool discovered_list_needs_barrier) : _discovering_refs(false), _enqueuing_is_done(false), - _is_alive_non_header(NULL), + _is_alive_non_header(is_alive_non_header), _discovered_list_needs_barrier(discovered_list_needs_barrier), _bs(NULL), _processing_is_mt(mt_processing), @@ -144,8 +121,8 @@ _span = span; _discovery_is_atomic = atomic_discovery; _discovery_is_mt = mt_discovery; - _num_q = mt_degree; - _max_num_q = mt_degree; + _num_q = MAX2(1, mt_processing_degree); + _max_num_q = MAX2(_num_q, mt_discovery_degree); _discoveredSoftRefs = NEW_C_HEAP_ARRAY(DiscoveredList, _max_num_q * subclasses_of_ref); if (_discoveredSoftRefs == NULL) { vm_exit_during_initialization("Could not allocated RefProc Array"); @@ -163,6 +140,7 @@ if (discovered_list_needs_barrier) { _bs = Universe::heap()->barrier_set(); } + setup_policy(false /* default soft ref policy */); } #ifndef PRODUCT @@ -405,15 +383,14 @@ { } virtual void work(unsigned int work_id) { - assert(work_id < (unsigned int)_ref_processor.num_q(), "Index out-of-bounds"); + assert(work_id < (unsigned int)_ref_processor.max_num_q(), "Index out-of-bounds"); // Simplest first cut: static partitioning. int index = work_id; // The increment on "index" must correspond to the maximum number of queues // (n_queues) with which that ReferenceProcessor was created. That // is because of the "clever" way the discovered references lists were - // allocated and are indexed into. That number is ParallelGCThreads - // currently. Assert that. - assert(_n_queues == (int) ParallelGCThreads, "Different number not expected"); + // allocated and are indexed into. + assert(_n_queues == (int) _ref_processor.max_num_q(), "Different number not expected"); for (int j = 0; j < subclasses_of_ref; j++, index += _n_queues) { @@ -672,7 +649,7 @@ } } NOT_PRODUCT( - if (PrintGCDetails && TraceReferenceGC) { + if (PrintGCDetails && TraceReferenceGC && (iter.processed() > 0)) { gclog_or_tty->print_cr(" Dropped %d active Refs out of %d " "Refs in discovered list " INTPTR_FORMAT, iter.removed(), iter.processed(), (address)refs_list.head()); @@ -711,7 +688,7 @@ // Now close the newly reachable set complete_gc->do_void(); NOT_PRODUCT( - if (PrintGCDetails && TraceReferenceGC) { + if (PrintGCDetails && TraceReferenceGC && (iter.processed() > 0)) { gclog_or_tty->print_cr(" Dropped %d active Refs out of %d " "Refs in discovered list " INTPTR_FORMAT, iter.removed(), iter.processed(), (address)refs_list.head()); @@ -951,7 +928,7 @@ } if (PrintReferenceGC && PrintGCDetails) { size_t total = 0; - for (int i = 0; i < _num_q; ++i) { + for (int i = 0; i < _max_num_q; ++i) { total += refs_lists[i].length(); } gclog_or_tty->print(", %u refs", total); @@ -967,7 +944,7 @@ RefProcPhase1Task phase1(*this, refs_lists, policy, true /*marks_oops_alive*/); task_executor->execute(phase1); } else { - for (int i = 0; i < _num_q; i++) { + for (int i = 0; i < _max_num_q; i++) { process_phase1(refs_lists[i], policy, is_alive, keep_alive, complete_gc); } @@ -983,7 +960,7 @@ RefProcPhase2Task phase2(*this, refs_lists, !discovery_is_atomic() /*marks_oops_alive*/); task_executor->execute(phase2); } else { - for (int i = 0; i < _num_q; i++) { + for (int i = 0; i < _max_num_q; i++) { process_phase2(refs_lists[i], is_alive, keep_alive, complete_gc); } } @@ -994,7 +971,7 @@ RefProcPhase3Task phase3(*this, refs_lists, clear_referent, true /*marks_oops_alive*/); task_executor->execute(phase3); } else { - for (int i = 0; i < _num_q; i++) { + for (int i = 0; i < _max_num_q; i++) { process_phase3(refs_lists[i], clear_referent, is_alive, keep_alive, complete_gc); } @@ -1008,7 +985,7 @@ // for (int j = 0; j < _num_q; j++) { // int index = i * _max_num_q + j; for (int i = 0; i < _max_num_q * subclasses_of_ref; i++) { - if (TraceReferenceGC && PrintGCDetails && ((i % _num_q) == 0)) { + if (TraceReferenceGC && PrintGCDetails && ((i % _max_num_q) == 0)) { gclog_or_tty->print_cr( "\nScrubbing %s discovered list of Null referents", list_name(i)); @@ -1350,7 +1327,7 @@ { TraceTime tt("Preclean WeakReferences", PrintGCDetails && PrintReferenceGC, false, gclog_or_tty); - for (int i = 0; i < _num_q; i++) { + for (int i = 0; i < _max_num_q; i++) { if (yield->should_return()) { return; } @@ -1363,7 +1340,7 @@ { TraceTime tt("Preclean FinalReferences", PrintGCDetails && PrintReferenceGC, false, gclog_or_tty); - for (int i = 0; i < _num_q; i++) { + for (int i = 0; i < _max_num_q; i++) { if (yield->should_return()) { return; } @@ -1376,7 +1353,7 @@ { TraceTime tt("Preclean PhantomReferences", PrintGCDetails && PrintReferenceGC, false, gclog_or_tty); - for (int i = 0; i < _num_q; i++) { + for (int i = 0; i < _max_num_q; i++) { if (yield->should_return()) { return; } @@ -1433,7 +1410,7 @@ complete_gc->do_void(); NOT_PRODUCT( - if (PrintGCDetails && PrintReferenceGC) { + if (PrintGCDetails && PrintReferenceGC && (iter.processed() > 0)) { gclog_or_tty->print_cr(" Dropped %d Refs out of %d " "Refs in discovered list " INTPTR_FORMAT, iter.removed(), iter.processed(), (address)refs_list.head());
--- a/src/share/vm/memory/referenceProcessor.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/memory/referenceProcessor.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, 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 @@ -71,7 +71,7 @@ bool _enqueuing_is_done; // true if all weak references enqueued bool _processing_is_mt; // true during phases when // reference processing is MT. - int _next_id; // round-robin counter in + int _next_id; // round-robin mod _num_q counter in // support of work distribution // For collectors that do not keep GC marking information @@ -103,7 +103,8 @@ public: int num_q() { return _num_q; } - void set_mt_degree(int v) { _num_q = v; } + int max_num_q() { return _max_num_q; } + void set_active_mt_degree(int v) { _num_q = v; } DiscoveredList* discovered_soft_refs() { return _discoveredSoftRefs; } static oop sentinel_ref() { return _sentinelRef; } static oop* adr_sentinel_ref() { return &_sentinelRef; } @@ -216,6 +217,7 @@ VoidClosure* complete_gc, YieldClosure* yield); + // round-robin mod _num_q (not: _not_ mode _max_num_q) int next_id() { int id = _next_id; if (++_next_id == _num_q) { @@ -256,23 +258,15 @@ _max_num_q(0), _processing_is_mt(false), _next_id(0) - {} - - ReferenceProcessor(MemRegion span, bool atomic_discovery, - bool mt_discovery, - int mt_degree = 1, - bool mt_processing = false, - bool discovered_list_needs_barrier = false); + { } - // Allocates and initializes a reference processor. - static ReferenceProcessor* create_ref_processor( - MemRegion span, - bool atomic_discovery, - bool mt_discovery, - BoolObjectClosure* is_alive_non_header = NULL, - int parallel_gc_threads = 1, - bool mt_processing = false, - bool discovered_list_needs_barrier = false); + // Default parameters give you a vanilla reference processor. + ReferenceProcessor(MemRegion span, + bool mt_processing = false, int mt_processing_degree = 1, + bool mt_discovery = false, int mt_discovery_degree = 1, + bool atomic_discovery = true, + BoolObjectClosure* is_alive_non_header = NULL, + bool discovered_list_needs_barrier = false); // RefDiscoveryPolicy values enum DiscoveryPolicy { @@ -397,20 +391,20 @@ // A utility class to temporarily change the MT'ness of // reference discovery for the given ReferenceProcessor // in the scope that contains it. -class ReferenceProcessorMTMutator: StackObj { +class ReferenceProcessorMTDiscoveryMutator: StackObj { private: ReferenceProcessor* _rp; bool _saved_mt; public: - ReferenceProcessorMTMutator(ReferenceProcessor* rp, - bool mt): + ReferenceProcessorMTDiscoveryMutator(ReferenceProcessor* rp, + bool mt): _rp(rp) { _saved_mt = _rp->discovery_is_mt(); _rp->set_mt_discovery(mt); } - ~ReferenceProcessorMTMutator() { + ~ReferenceProcessorMTDiscoveryMutator() { _rp->set_mt_discovery(_saved_mt); } };
--- a/src/share/vm/memory/sharedHeap.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/memory/sharedHeap.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -171,11 +171,13 @@ } if (!_process_strong_tasks->is_task_claimed(SH_PS_StringTable_oops_do)) { - if (so & SO_Strings) { - StringTable::oops_do(roots); - } - // Verify if the string table contents are in the perm gen - NOT_PRODUCT(StringTable::oops_do(&assert_is_perm_closure)); + if (so & SO_Strings || (!collecting_perm_gen && !JavaObjectsInPerm)) { + StringTable::oops_do(roots); + } + if (JavaObjectsInPerm) { + // Verify the string table contents are in the perm gen + NOT_PRODUCT(StringTable::oops_do(&assert_is_perm_closure)); + } } if (!_process_strong_tasks->is_task_claimed(SH_PS_CodeCache_oops_do)) {
--- a/src/share/vm/memory/universe.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/memory/universe.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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,6 +51,7 @@ #include "oops/cpCacheKlass.hpp" #include "oops/cpCacheOop.hpp" #include "oops/instanceKlass.hpp" +#include "oops/instanceMirrorKlass.hpp" #include "oops/instanceKlassKlass.hpp" #include "oops/instanceRefKlass.hpp" #include "oops/klassKlass.hpp" @@ -521,6 +522,7 @@ { objArrayKlassKlass o; add_vtable(list, &n, &o, count); } { instanceKlassKlass o; add_vtable(list, &n, &o, count); } { instanceKlass o; add_vtable(list, &n, &o, count); } + { instanceMirrorKlass o; add_vtable(list, &n, &o, count); } { instanceRefKlass o; add_vtable(list, &n, &o, count); } { typeArrayKlassKlass o; add_vtable(list, &n, &o, count); } { typeArrayKlass o; add_vtable(list, &n, &o, count); } @@ -547,7 +549,7 @@ KlassHandle k(THREAD, klassOop(obj)); // We will never reach the CATCH below since Exceptions::_throw will cause // the VM to exit if an exception is thrown during initialization - java_lang_Class::create_mirror(k, CATCH); + java_lang_Class::fixup_mirror(k, CATCH); // This call unconditionally creates a new mirror for k, // and links in k's component_mirror field if k is an array. // If k is an objArray, k's element type must already have @@ -605,6 +607,10 @@ // walk over permanent objects created so far (mostly classes) and fixup their mirrors. Note // that the number of objects allocated at this point is very small. assert(SystemDictionary::Class_klass_loaded(), "java.lang.Class should be loaded"); + + // Cache the start of the static fields + instanceMirrorKlass::init_offset_of_static_fields(); + FixupMirrorClosure blk; Universe::heap()->permanent_object_iterate(&blk); } @@ -1313,6 +1319,8 @@ JNIHandles::verify(); if (!silent) gclog_or_tty->print("C-heap "); os::check_heap(); + if (!silent) gclog_or_tty->print("code cache "); + CodeCache::verify_oops(); if (!silent) gclog_or_tty->print_cr("]"); _verify_in_progress = false;
--- a/src/share/vm/oops/arrayKlassKlass.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/oops/arrayKlassKlass.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -28,6 +28,13 @@ #include "oops/arrayKlassKlass.hpp" #include "oops/oop.inline.hpp" #include "runtime/handles.inline.hpp" +#ifndef SERIALGC +#include "gc_implementation/parNew/parOopClosures.inline.hpp" +#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" +#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" +#include "memory/cardTableRS.hpp" +#include "oops/oop.pcgc.inline.hpp" +#endif klassOop arrayKlassKlass::create_klass(TRAPS) { @@ -104,9 +111,12 @@ int arrayKlassKlass::oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr) { assert(obj->is_klass(), "must be klass"); arrayKlass* ak = arrayKlass::cast(klassOop(obj)); - blk->do_oop(ak->adr_component_mirror()); - blk->do_oop(ak->adr_lower_dimension()); - blk->do_oop(ak->adr_higher_dimension()); + oop* addr = ak->adr_component_mirror(); + if (mr.contains(addr)) blk->do_oop(addr); + addr = ak->adr_lower_dimension(); + if (mr.contains(addr)) blk->do_oop(addr); + addr = ak->adr_higher_dimension(); + if (mr.contains(addr)) blk->do_oop(addr); ak->vtable()->oop_oop_iterate_m(blk, mr); return klassKlass::oop_oop_iterate_m(obj, blk, mr); } @@ -114,6 +124,12 @@ #ifndef SERIALGC void arrayKlassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { assert(obj->blueprint()->oop_is_arrayKlass(),"must be an array klass"); + arrayKlass* ak = arrayKlass::cast(klassOop(obj)); + oop* p = ak->adr_component_mirror(); + if (PSScavenge::should_scavenge(p)) { + pm->claim_or_forward_depth(p); + } + klassKlass::oop_push_contents(pm, obj); } int arrayKlassKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) {
--- a/src/share/vm/oops/constantPoolKlass.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/oops/constantPoolKlass.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -285,10 +285,11 @@ void constantPoolKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { assert(obj->is_constantPool(), "should be constant pool"); constantPoolOop cp = (constantPoolOop) obj; - if (AnonymousClasses && cp->has_pseudo_string() && cp->tags() != NULL) { - oop* base = (oop*)cp->base(); - for (int i = 0; i < cp->length(); ++i, ++base) { + if (cp->tags() != NULL && + (!JavaObjectsInPerm || (EnableInvokeDynamic && cp->has_pseudo_string()))) { + for (int i = 1; i < cp->length(); ++i) { if (cp->tag_at(i).is_string()) { + oop* base = cp->obj_at_addr_raw(i); if (PSScavenge::should_scavenge(base)) { pm->claim_or_forward_depth(base); } @@ -460,7 +461,8 @@ if (cp->tag_at(i).is_string()) { if (!cp->has_pseudo_string()) { if (entry.is_oop()) { - guarantee(entry.get_oop()->is_perm(), "should be in permspace"); + guarantee(!JavaObjectsInPerm || entry.get_oop()->is_perm(), + "should be in permspace"); guarantee(entry.get_oop()->is_instance(), "should be instance"); } } else {
--- a/src/share/vm/oops/constantPoolOop.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/oops/constantPoolOop.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -481,7 +481,7 @@ { klassOop resolved = klass_at_impl(this_oop, index, CHECK_NULL); // ldc wants the java mirror. - result_oop = resolved->klass_part()->java_mirror(); + result_oop = resolved->java_mirror(); break; }
--- a/src/share/vm/oops/constantPoolOop.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/oops/constantPoolOop.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -429,7 +429,7 @@ // A "pseudo-string" is an non-string oop that has found is way into // a String entry. - // Under AnonymousClasses this can happen if the user patches a live + // Under EnableInvokeDynamic this can happen if the user patches a live // object into a CONSTANT_String entry of an anonymous class. // Method oops internally created for method handles may also // use pseudo-strings to link themselves to related metaobjects. @@ -442,7 +442,7 @@ } void pseudo_string_at_put(int which, oop x) { - assert(AnonymousClasses, ""); + assert(EnableInvokeDynamic, ""); set_pseudo_string(); // mark header assert(tag_at(which).is_string() || tag_at(which).is_unresolved_string(), "Corrupted constant pool"); string_at_put(which, x); // this works just fine
--- a/src/share/vm/oops/cpCacheKlass.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/oops/cpCacheKlass.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -168,22 +168,18 @@ void constantPoolCacheKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { assert(obj->is_constantPoolCache(), "should be constant pool"); - if (EnableInvokeDynamic) { + if (ScavengeRootsInCode) { constantPoolCacheOop cache = (constantPoolCacheOop)obj; // during a scavenge, it is safe to inspect my pool, since it is perm constantPoolOop pool = cache->constant_pool(); assert(pool->is_constantPool(), "should be constant pool"); - if (pool->has_invokedynamic()) { - for (int i = 0; i < cache->length(); i++) { - ConstantPoolCacheEntry* e = cache->entry_at(i); - oop* p = (oop*)&e->_f1; - if (e->is_secondary_entry()) { - if (PSScavenge::should_scavenge(p)) - pm->claim_or_forward_depth(p); - assert(!(e->is_vfinal() && PSScavenge::should_scavenge((oop*)&e->_f2)), - "no live oops here"); - } - } + for (int i = 0; i < cache->length(); i++) { + ConstantPoolCacheEntry* e = cache->entry_at(i); + oop* p = (oop*)&e->_f1; + if (PSScavenge::should_scavenge(p)) + pm->claim_or_forward_depth(p); + assert(!(e->is_vfinal() && PSScavenge::should_scavenge((oop*)&e->_f2)), + "no live oops here"); } } }
--- a/src/share/vm/oops/cpCacheOop.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/oops/cpCacheOop.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -133,7 +133,7 @@ TosState field_type, bool is_final, bool is_volatile) { - set_f1(field_holder()); + set_f1(field_holder()->java_mirror()); set_f2(field_offset); // The field index is used by jvm/ti and is the index into fields() array // in holder instanceKlass. This is scaled by instanceKlass::next_offset.
--- a/src/share/vm/oops/instanceKlass.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/oops/instanceKlass.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -37,6 +37,7 @@ #include "memory/oopFactory.hpp" #include "memory/permGen.hpp" #include "oops/instanceKlass.hpp" +#include "oops/instanceMirrorKlass.hpp" #include "oops/instanceOop.hpp" #include "oops/methodOop.hpp" #include "oops/objArrayKlassKlass.hpp" @@ -649,6 +650,7 @@ } instanceOop instanceKlass::allocate_instance(TRAPS) { + assert(!oop_is_instanceMirror(), "wrong allocation path"); bool has_finalizer_flag = has_finalizer(); // Query before possible GC int size = size_helper(); // Query before forming handle. @@ -669,6 +671,7 @@ // instances so simply disallow finalizable perm objects. This can // be relaxed if a need for it is found. assert(!has_finalizer(), "perm objects not allowed to have finalizers"); + assert(!oop_is_instanceMirror(), "wrong allocation path"); int size = size_helper(); // Query before forming handle. KlassHandle h_k(THREAD, as_klassOop()); instanceOop i = (instanceOop) @@ -898,6 +901,7 @@ } } + void instanceKlass::do_local_static_fields(FieldClosure* cl) { fieldDescriptor fd; int length = fields()->length(); @@ -1609,36 +1613,6 @@ // The following macros call specialized macros, passing either oop or // narrowOop as the specialization type. These test the UseCompressedOops // flag. -#define InstanceKlass_OOP_ITERATE(start_p, count, \ - do_oop, assert_fn) \ -{ \ - if (UseCompressedOops) { \ - InstanceKlass_SPECIALIZED_OOP_ITERATE(narrowOop, \ - start_p, count, \ - do_oop, assert_fn) \ - } else { \ - InstanceKlass_SPECIALIZED_OOP_ITERATE(oop, \ - start_p, count, \ - do_oop, assert_fn) \ - } \ -} - -#define InstanceKlass_BOUNDED_OOP_ITERATE(start_p, count, low, high, \ - do_oop, assert_fn) \ -{ \ - if (UseCompressedOops) { \ - InstanceKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(narrowOop, \ - start_p, count, \ - low, high, \ - do_oop, assert_fn) \ - } else { \ - InstanceKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(oop, \ - start_p, count, \ - low, high, \ - do_oop, assert_fn) \ - } \ -} - #define InstanceKlass_OOP_MAP_ITERATE(obj, do_oop, assert_fn) \ { \ /* Compute oopmap block range. The common case \ @@ -1711,38 +1685,6 @@ } \ } -void instanceKlass::follow_static_fields() { - InstanceKlass_OOP_ITERATE( \ - start_of_static_fields(), static_oop_field_size(), \ - MarkSweep::mark_and_push(p), \ - assert_is_in_closed_subset) -} - -#ifndef SERIALGC -void instanceKlass::follow_static_fields(ParCompactionManager* cm) { - InstanceKlass_OOP_ITERATE( \ - start_of_static_fields(), static_oop_field_size(), \ - PSParallelCompact::mark_and_push(cm, p), \ - assert_is_in) -} -#endif // SERIALGC - -void instanceKlass::adjust_static_fields() { - InstanceKlass_OOP_ITERATE( \ - start_of_static_fields(), static_oop_field_size(), \ - MarkSweep::adjust_pointer(p), \ - assert_nothing) -} - -#ifndef SERIALGC -void instanceKlass::update_static_fields() { - InstanceKlass_OOP_ITERATE( \ - start_of_static_fields(), static_oop_field_size(), \ - PSParallelCompact::adjust_pointer(p), \ - assert_nothing) -} -#endif // SERIALGC - void instanceKlass::oop_follow_contents(oop obj) { assert(obj != NULL, "can't follow the content of NULL object"); obj->follow_header(); @@ -1829,22 +1771,6 @@ ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) #endif // !SERIALGC -void instanceKlass::iterate_static_fields(OopClosure* closure) { - InstanceKlass_OOP_ITERATE( \ - start_of_static_fields(), static_oop_field_size(), \ - closure->do_oop(p), \ - assert_is_in_reserved) -} - -void instanceKlass::iterate_static_fields(OopClosure* closure, - MemRegion mr) { - InstanceKlass_BOUNDED_OOP_ITERATE( \ - start_of_static_fields(), static_oop_field_size(), \ - mr.start(), mr.end(), \ - (closure)->do_oop_v(p), \ - assert_is_in_closed_subset) -} - int instanceKlass::oop_adjust_pointers(oop obj) { int size = size_helper(); InstanceKlass_OOP_MAP_ITERATE( \ @@ -1873,21 +1799,6 @@ return size_helper(); } -void instanceKlass::push_static_fields(PSPromotionManager* pm) { - InstanceKlass_OOP_ITERATE( \ - start_of_static_fields(), static_oop_field_size(), \ - if (PSScavenge::should_scavenge(p)) { \ - pm->claim_or_forward_depth(p); \ - }, \ - assert_nothing ) -} - -void instanceKlass::copy_static_fields(ParCompactionManager* cm) { - InstanceKlass_OOP_ITERATE( \ - start_of_static_fields(), static_oop_field_size(), \ - PSParallelCompact::adjust_pointer(p), \ - assert_is_in) -} #endif // SERIALGC // This klass is alive but the implementor link is not followed/updated. @@ -2002,6 +1913,11 @@ if (_source_debug_extension != NULL) _source_debug_extension->increment_refcount(); } +address instanceKlass::static_field_addr(int offset) { + return (address)(offset + instanceMirrorKlass::offset_of_static_fields() + (intptr_t)java_mirror()); +} + + const char* instanceKlass::signature_name() const { const char* src = (const char*) (name()->as_C_string()); const int src_length = (int)strlen(src); @@ -2369,7 +2285,7 @@ void FieldPrinter::do_field(fieldDescriptor* fd) { _st->print(BULLET); - if (fd->is_static() || (_obj == NULL)) { + if (_obj == NULL) { fd->print_on(_st); _st->cr(); } else { @@ -2399,8 +2315,8 @@ } st->print_cr(BULLET"---- fields (total size %d words):", oop_size(obj)); - FieldPrinter print_nonstatic_field(st, obj); - do_nonstatic_fields(&print_nonstatic_field); + FieldPrinter print_field(st, obj); + do_nonstatic_fields(&print_field); if (as_klassOop() == SystemDictionary::Class_klass()) { st->print(BULLET"signature: "); @@ -2418,6 +2334,12 @@ st->print(BULLET"fake entry for array: "); array_klass->print_value_on(st); st->cr(); + st->print_cr(BULLET"fake entry for oop_size: %d", java_lang_Class::oop_size(obj)); + st->print_cr(BULLET"fake entry for static_oop_field_count: %d", java_lang_Class::static_oop_field_count(obj)); + klassOop real_klass = java_lang_Class::as_klassOop(obj); + if (real_klass != NULL && real_klass->klass_part()->oop_is_instance()) { + instanceKlass::cast(real_klass)->do_local_static_fields(&print_field); + } } else if (as_klassOop() == SystemDictionary::MethodType_klass()) { st->print(BULLET"signature: "); java_lang_invoke_MethodType::print_signature(obj, st); @@ -2560,7 +2482,7 @@ void JNIid::verify(klassOop holder) { - int first_field_offset = instanceKlass::cast(holder)->offset_of_static_fields(); + int first_field_offset = instanceMirrorKlass::offset_of_static_fields(); int end_field_offset; end_field_offset = first_field_offset + (instanceKlass::cast(holder)->static_field_size() * wordSize);
--- a/src/share/vm/oops/instanceKlass.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/oops/instanceKlass.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -75,8 +75,6 @@ // [Java vtable length ] // [oop map cache (stack maps) ] // [EMBEDDED Java vtable ] size in words = vtable_len -// [EMBEDDED static oop fields ] size in words = static_oop_fields_size -// [ static non-oop fields ] size in words = static_field_size - static_oop_fields_size // [EMBEDDED nonstatic oop-map blocks] size in words = nonstatic_oop_map_size // // The embedded nonstatic oop-map blocks are short pairs (offset, length) indicating @@ -184,7 +182,7 @@ // Protection domain. oop _protection_domain; // Host class, which grants its access privileges to this class also. - // This is only non-null for an anonymous class (AnonymousClasses enabled). + // This is only non-null for an anonymous class (JSR 292 enabled). // The host class is either named, or a previously loaded anonymous class. klassOop _host_klass; // Class signers. @@ -230,7 +228,7 @@ // (including inherited fields but after header_size()). int _nonstatic_field_size; int _static_field_size; // number words used by static fields (oop and non-oop) in this klass - int _static_oop_field_size;// number of static oop fields in this klass + int _static_oop_field_count;// number of static oop fields in this klass int _nonstatic_oop_map_size;// size in words of nonstatic oop map blocks bool _is_marked_dependent; // used for marking during flushing and deoptimization bool _rewritten; // methods rewritten. @@ -281,8 +279,8 @@ int static_field_size() const { return _static_field_size; } void set_static_field_size(int size) { _static_field_size = size; } - int static_oop_field_size() const { return _static_oop_field_size; } - void set_static_oop_field_size(int size) { _static_oop_field_size = size; } + int static_oop_field_count() const { return _static_oop_field_count; } + void set_static_oop_field_count(int size) { _static_oop_field_count = size; } // Java vtable int vtable_length() const { return _vtable_len; } @@ -660,6 +658,7 @@ // Casting from klassOop static instanceKlass* cast(klassOop k) { + assert(k->is_klass(), "must be"); Klass* kp = k->klass_part(); assert(kp->null_vtbl() || kp->oop_is_instance_slow(), "cast to instanceKlass"); return (instanceKlass*) kp; @@ -667,7 +666,7 @@ // Sizing (in words) static int header_size() { return align_object_offset(oopDesc::header_size() + sizeof(instanceKlass)/HeapWordSize); } - int object_size() const { return object_size(align_object_offset(vtable_length()) + align_object_offset(itable_length()) + static_field_size() + nonstatic_oop_map_size()); } + int object_size() const { return object_size(align_object_offset(vtable_length()) + align_object_offset(itable_length()) + nonstatic_oop_map_size()); } static int vtable_start_offset() { return header_size(); } static int vtable_length_offset() { return oopDesc::header_size() + offset_of(instanceKlass, _vtable_len) / HeapWordSize; } static int object_size(int extra) { return align_object_size(header_size() + extra); } @@ -676,20 +675,12 @@ intptr_t* start_of_itable() const { return start_of_vtable() + align_object_offset(vtable_length()); } int itable_offset_in_words() const { return start_of_itable() - (intptr_t*)as_klassOop(); } - // Static field offset is an offset into the Heap, should be converted by - // based on UseCompressedOop for traversal - HeapWord* start_of_static_fields() const { - return (HeapWord*)(start_of_itable() + align_object_offset(itable_length())); - } - intptr_t* end_of_itable() const { return start_of_itable() + itable_length(); } - int offset_of_static_fields() const { - return (intptr_t)start_of_static_fields() - (intptr_t)as_klassOop(); - } + address static_field_addr(int offset); OopMapBlock* start_of_nonstatic_oop_maps() const { - return (OopMapBlock*) (start_of_static_fields() + static_field_size()); + return (OopMapBlock*)(start_of_itable() + align_object_offset(itable_length())); } // Allocation profiling support @@ -719,8 +710,6 @@ // Garbage collection void oop_follow_contents(oop obj); - void follow_static_fields(); - void adjust_static_fields(); int oop_adjust_pointers(oop obj); bool object_is_parsable() const { return _init_state != unparsable_by_gc; } // Value of _init_state must be zero (unparsable_by_gc) when klass field is set. @@ -732,16 +721,6 @@ // Parallel Scavenge and Parallel Old PARALLEL_GC_DECLS -#ifndef SERIALGC - // Parallel Scavenge - void push_static_fields(PSPromotionManager* pm); - - // Parallel Old - void follow_static_fields(ParCompactionManager* cm); - void copy_static_fields(ParCompactionManager* cm); - void update_static_fields(); -#endif // SERIALGC - // Naming const char* signature_name() const; @@ -770,9 +749,6 @@ ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) #endif // !SERIALGC - void iterate_static_fields(OopClosure* closure); - void iterate_static_fields(OopClosure* closure, MemRegion mr); - private: // initialization state #ifdef ASSERT @@ -926,6 +902,10 @@ // Identifier lookup JNIid* find(int offset); + bool find_local_field(fieldDescriptor* fd) { + return instanceKlass::cast(holder())->find_local_field_from_offset(offset(), true, fd); + } + // Garbage collection support oop* holder_addr() { return (oop*)&_holder; } void oops_do(OopClosure* f);
--- a/src/share/vm/oops/instanceKlassKlass.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/oops/instanceKlassKlass.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -31,6 +31,7 @@ #include "memory/gcLocker.hpp" #include "oops/constantPoolOop.hpp" #include "oops/instanceKlass.hpp" +#include "oops/instanceMirrorKlass.hpp" #include "oops/instanceKlassKlass.hpp" #include "oops/instanceRefKlass.hpp" #include "oops/objArrayKlassKlass.hpp" @@ -86,7 +87,6 @@ assert(klassOop(obj)->klass_part()->oop_is_instance_slow(), "must be instance klass"); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); - ik->follow_static_fields(); { HandleMark hm; ik->vtable()->oop_follow_contents(); @@ -127,7 +127,6 @@ assert(klassOop(obj)->klass_part()->oop_is_instance_slow(), "must be instance klass"); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); - ik->follow_static_fields(cm); ik->vtable()->oop_follow_contents(cm); ik->itable()->oop_follow_contents(cm); @@ -168,7 +167,6 @@ // Don't call size() or oop_size() since that is a virtual call. int size = ik->object_size(); - ik->iterate_static_fields(blk); ik->vtable()->oop_oop_iterate(blk); ik->itable()->oop_oop_iterate(blk); @@ -209,7 +207,6 @@ // Don't call size() or oop_size() since that is a virtual call. int size = ik->object_size(); - ik->iterate_static_fields(blk, mr); ik->vtable()->oop_oop_iterate_m(blk, mr); ik->itable()->oop_oop_iterate_m(blk, mr); @@ -266,7 +263,6 @@ assert(klassOop(obj)->klass_part()->oop_is_instance_slow(), "must be instance klass"); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); - ik->adjust_static_fields(); ik->vtable()->oop_adjust_pointers(); ik->itable()->oop_adjust_pointers(); @@ -300,7 +296,6 @@ #ifndef SERIALGC void instanceKlassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { instanceKlass* ik = instanceKlass::cast(klassOop(obj)); - ik->push_static_fields(pm); oop* loader_addr = ik->adr_class_loader(); if (PSScavenge::should_scavenge(loader_addr)) { @@ -336,7 +331,6 @@ "must be instance klass"); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); - ik->update_static_fields(); ik->vtable()->oop_update_pointers(cm); ik->itable()->oop_update_pointers(cm); @@ -356,22 +350,28 @@ #endif // SERIALGC klassOop -instanceKlassKlass::allocate_instance_klass(int vtable_len, int itable_len, +instanceKlassKlass::allocate_instance_klass(Symbol* name, int vtable_len, int itable_len, int static_field_size, unsigned nonstatic_oop_map_count, ReferenceType rt, TRAPS) { const int nonstatic_oop_map_size = instanceKlass::nonstatic_oop_map_size(nonstatic_oop_map_count); - int size = instanceKlass::object_size(align_object_offset(vtable_len) + align_object_offset(itable_len) + static_field_size + nonstatic_oop_map_size); + int size = instanceKlass::object_size(align_object_offset(vtable_len) + align_object_offset(itable_len) + nonstatic_oop_map_size); // Allocation KlassHandle h_this_klass(THREAD, as_klassOop()); KlassHandle k; if (rt == REF_NONE) { - // regular klass - instanceKlass o; - k = base_create_klass(h_this_klass, size, o.vtbl_value(), CHECK_NULL); + if (name != vmSymbols::java_lang_Class()) { + // regular klass + instanceKlass o; + k = base_create_klass(h_this_klass, size, o.vtbl_value(), CHECK_NULL); + } else { + // Class + instanceMirrorKlass o; + k = base_create_klass(h_this_klass, size, o.vtbl_value(), CHECK_NULL); + } } else { // reference klass instanceRefKlass o; @@ -408,7 +408,7 @@ ik->set_source_debug_extension(NULL); ik->set_array_name(NULL); ik->set_inner_classes(NULL); - ik->set_static_oop_field_size(0); + ik->set_static_oop_field_count(0); ik->set_nonstatic_field_size(0); ik->set_is_marked_dependent(false); ik->set_init_state(instanceKlass::allocated); @@ -442,9 +442,6 @@ // To get verify to work - must be set to partial loaded before first GC point. k()->set_partially_loaded(); } - - // GC can happen here - java_lang_Class::create_mirror(k, CHECK_NULL); // Allocate mirror return k(); } @@ -566,13 +563,6 @@ FieldPrinter print_nonstatic_field(st); ik->do_nonstatic_fields(&print_nonstatic_field); - st->print(BULLET"static oop maps: "); - if (ik->static_oop_field_size() > 0) { - int first_offset = ik->offset_of_static_fields(); - st->print("%d-%d", first_offset, first_offset + ik->static_oop_field_size() - 1); - } - st->cr(); - st->print(BULLET"non-static oop maps: "); OopMapBlock* map = ik->start_of_nonstatic_oop_maps(); OopMapBlock* end_map = map + ik->nonstatic_oop_map_count(); @@ -630,7 +620,6 @@ // Verify static fields VerifyFieldClosure blk; - ik->iterate_static_fields(&blk); // Verify vtables if (ik->is_linked()) {
--- a/src/share/vm/oops/instanceKlassKlass.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/oops/instanceKlassKlass.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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,7 +41,8 @@ // Allocation DEFINE_ALLOCATE_PERMANENT(instanceKlassKlass); static klassOop create_klass(TRAPS); - klassOop allocate_instance_klass(int vtable_len, + klassOop allocate_instance_klass(Symbol* name, + int vtable_len, int itable_len, int static_field_size, unsigned int nonstatic_oop_map_count,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/oops/instanceMirrorKlass.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2011, 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/oopFactory.hpp" +#include "memory/permGen.hpp" +#include "oops/instanceKlass.hpp" +#include "oops/instanceMirrorKlass.hpp" +#include "oops/instanceOop.hpp" +#include "oops/oop.inline.hpp" +#include "oops/symbol.hpp" +#include "runtime/handles.inline.hpp" +#ifndef SERIALGC +#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/heapRegionSeq.inline.hpp" +#include "gc_implementation/parNew/parOopClosures.inline.hpp" +#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" +#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" +#include "oops/oop.pcgc.inline.hpp" +#endif + +int instanceMirrorKlass::_offset_of_static_fields = 0; + +#ifdef ASSERT +template <class T> 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 <class T> 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 <class T> 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 <class T> void assert_nothing(T *p) {} + +#else +template <class T> void assert_is_in(T *p) {} +template <class T> void assert_is_in_closed_subset(T *p) {} +template <class T> void assert_is_in_reserved(T *p) {} +template <class T> 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); + 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) +} + +#ifndef SERIALGC +void instanceMirrorKlass::oop_follow_contents(ParCompactionManager* cm, + oop obj) { + instanceKlass::oop_follow_contents(cm, obj); + 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 // SERIALGC + +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 */ \ + SpecializationStats::record_iterate_call##nv_suffix(SpecializationStats::irk); \ + \ + instanceKlass::oop_oop_iterate##nv_suffix(obj, closure); \ + \ + if (UseCompressedOops) { \ + InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE_DEFN(narrowOop, nv_suffix); \ + } else { \ + InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE_DEFN(oop, nv_suffix); \ + } \ +} + +#ifndef SERIALGC +#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 */ \ + SpecializationStats::record_iterate_call##nv_suffix(SpecializationStats::irk); \ + \ + 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 // !SERIALGC + + +#define InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ + \ +int instanceMirrorKlass:: \ +oop_oop_iterate##nv_suffix##_m(oop obj, \ + OopClosureType* closure, \ + MemRegion mr) { \ + SpecializationStats::record_iterate_call##nv_suffix(SpecializationStats::irk); \ + \ + instanceKlass::oop_oop_iterate##nv_suffix##_m(obj, closure, mr); \ + 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) +#ifndef SERIALGC +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 // SERIALGC +ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m) +ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m) + +#ifndef SERIALGC +void instanceMirrorKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { + 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) { + 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 oop_size(obj); +} +#endif // SERIALGC + +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()); + } + return size_helper(); +} + +instanceOop instanceMirrorKlass::allocate_instance(KlassHandle k, TRAPS) { + // Query before forming handle. + int size = instance_size(k); + KlassHandle h_k(THREAD, as_klassOop()); + instanceOop i; + + if (JavaObjectsInPerm) { + i = (instanceOop) CollectedHeap::permanent_obj_allocate(h_k, size, CHECK_NULL); + } else { + assert(ScavengeRootsInCode > 0, "must be"); + i = (instanceOop) CollectedHeap::obj_allocate(h_k, size, CHECK_NULL); + } + + return i; +} + +int instanceMirrorKlass::oop_size(oop obj) const { + return java_lang_Class::oop_size(obj); +} + +int instanceMirrorKlass::compute_static_oop_field_count(oop obj) { + klassOop k = java_lang_Class::as_klassOop(obj); + if (k != NULL && k->klass_part()->oop_is_instance()) { + return instanceKlass::cast(k)->static_oop_field_count(); + } + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/oops/instanceMirrorKlass.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2011, 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_HPP +#define SHARE_VM_OOPS_INSTANCEMIRRORKLASS_HPP + +#include "oops/instanceKlass.hpp" + +// An instanceMirrorKlass is a specialized instanceKlass for +// java.lang.Class instances. These instances are special because +// they contain the static fields of the class in addition to the +// normal fields of Class. This means they are variable sized +// instances and need special logic for computing their size and for +// iteration of their oops. + + +class instanceMirrorKlass: public instanceKlass { + friend class VMStructs; + + private: + static int _offset_of_static_fields; + + public: + // Type testing + bool oop_is_instanceMirror() const { return true; } + + // Casting from klassOop + static instanceMirrorKlass* cast(klassOop k) { + assert(k->klass_part()->oop_is_instanceMirror(), "cast to instanceMirrorKlass"); + return (instanceMirrorKlass*) k->klass_part(); + } + + // Returns the size of the instance including the extra static fields. + virtual int oop_size(oop obj) const; + + // Static field offset is an offset into the Heap, should be converted by + // based on UseCompressedOop for traversal + static HeapWord* start_of_static_fields(oop obj) { + return (HeapWord*)((intptr_t)obj + offset_of_static_fields()); + } + + static void init_offset_of_static_fields() { + // Cache the offset of the static fields in the Class instance + assert(_offset_of_static_fields == 0, "once"); + _offset_of_static_fields = instanceMirrorKlass::cast(SystemDictionary::Class_klass())->size_helper() << LogHeapWordSize; + } + + static int offset_of_static_fields() { + return _offset_of_static_fields; + } + + int compute_static_oop_field_count(oop obj); + + // Given a Klass return the size of the instance + int instance_size(KlassHandle k); + + // allocation + DEFINE_ALLOCATE_PERMANENT(instanceMirrorKlass); + instanceOop allocate_instance(KlassHandle k, TRAPS); + + // Garbage collection + int oop_adjust_pointers(oop obj); + void oop_follow_contents(oop obj); + + // Parallel Scavenge and Parallel Old + PARALLEL_GC_DECLS + + int oop_oop_iterate(oop obj, OopClosure* blk) { + return oop_oop_iterate_v(obj, blk); + } + int oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr) { + return oop_oop_iterate_v_m(obj, blk, mr); + } + +#define InstanceMirrorKlass_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(InstanceMirrorKlass_OOP_OOP_ITERATE_DECL) + ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_DECL) + +#ifndef SERIALGC +#define InstanceMirrorKlass_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(InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) + ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) +#endif // !SERIALGC +}; + +#endif // SHARE_VM_OOPS_INSTANCEMIRRORKLASS_HPP
--- a/src/share/vm/oops/klass.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/oops/klass.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -500,7 +500,7 @@ if (oop_is_instance()) { instanceKlass* ik = (instanceKlass*) this; if (ik->is_anonymous()) { - assert(AnonymousClasses, ""); + assert(EnableInvokeDynamic, ""); intptr_t hash = ik->java_mirror()->identity_hash(); char hash_buf[40]; sprintf(hash_buf, "/" UINTX_FORMAT, (uintx)hash);
--- a/src/share/vm/oops/klass.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/oops/klass.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -577,6 +577,7 @@ public: // type testing operations virtual bool oop_is_instance_slow() const { return false; } + virtual bool oop_is_instanceMirror() const { return false; } virtual bool oop_is_instanceRef() const { return false; } virtual bool oop_is_array() const { return false; } virtual bool oop_is_objArray_slow() const { return false; } @@ -811,4 +812,8 @@ #endif }; + +inline oop klassOopDesc::java_mirror() const { return klass_part()->java_mirror(); } + + #endif // SHARE_VM_OOPS_KLASS_HPP
--- a/src/share/vm/oops/klassKlass.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/oops/klassKlass.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -41,6 +41,10 @@ #include "oops/typeArrayKlass.hpp" #include "runtime/handles.inline.hpp" #ifndef SERIALGC +#include "gc_implementation/parNew/parOopClosures.inline.hpp" +#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" +#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" +#include "memory/cardTableRS.hpp" #include "oops/oop.pcgc.inline.hpp" #endif @@ -175,6 +179,12 @@ #ifndef SERIALGC void klassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { + Klass* k = Klass::cast(klassOop(obj)); + + oop* p = k->adr_java_mirror(); + if (PSScavenge::should_scavenge(p)) { + pm->claim_or_forward_depth(p); + } } int klassKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { @@ -233,7 +243,7 @@ if (k->java_mirror() != NULL || (k->oop_is_instance() && instanceKlass::cast(klassOop(obj))->is_loaded())) { guarantee(k->java_mirror() != NULL, "should be allocated"); - guarantee(k->java_mirror()->is_perm(), "should be in permspace"); + guarantee(k->java_mirror()->is_perm() || !JavaObjectsInPerm, "should be in permspace"); guarantee(k->java_mirror()->is_instance(), "should be instance"); } }
--- a/src/share/vm/oops/klassOop.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/oops/klassOop.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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,7 +45,73 @@ static int klass_part_offset_in_bytes() { return sizeof(klassOopDesc); } // returns the Klass part containing dispatching behavior - Klass* klass_part() { return (Klass*)((address)this + klass_part_offset_in_bytes()); } + Klass* klass_part() const { return (Klass*)((address)this + klass_part_offset_in_bytes()); } + + // Convenience wrapper + inline oop java_mirror() const; + + private: + // These have no implementation since klassOop should never be accessed in this fashion + oop obj_field(int offset) const; + void obj_field_put(int offset, oop value); + void obj_field_raw_put(int offset, oop value); + + jbyte byte_field(int offset) const; + void byte_field_put(int offset, jbyte contents); + + jchar char_field(int offset) const; + void char_field_put(int offset, jchar contents); + + jboolean bool_field(int offset) const; + void bool_field_put(int offset, jboolean contents); + + jint int_field(int offset) const; + void int_field_put(int offset, jint contents); + + jshort short_field(int offset) const; + void short_field_put(int offset, jshort contents); + + jlong long_field(int offset) const; + void long_field_put(int offset, jlong contents); + + jfloat float_field(int offset) const; + void float_field_put(int offset, jfloat contents); + + jdouble double_field(int offset) const; + void double_field_put(int offset, jdouble contents); + + address address_field(int offset) const; + void address_field_put(int offset, address contents); + + oop obj_field_acquire(int offset) const; + void release_obj_field_put(int offset, oop value); + + jbyte byte_field_acquire(int offset) const; + void release_byte_field_put(int offset, jbyte contents); + + jchar char_field_acquire(int offset) const; + void release_char_field_put(int offset, jchar contents); + + jboolean bool_field_acquire(int offset) const; + void release_bool_field_put(int offset, jboolean contents); + + jint int_field_acquire(int offset) const; + void release_int_field_put(int offset, jint contents); + + jshort short_field_acquire(int offset) const; + void release_short_field_put(int offset, jshort contents); + + jlong long_field_acquire(int offset) const; + void release_long_field_put(int offset, jlong contents); + + jfloat float_field_acquire(int offset) const; + void release_float_field_put(int offset, jfloat contents); + + jdouble double_field_acquire(int offset) const; + void release_double_field_put(int offset, jdouble contents); + + address address_field_acquire(int offset) const; + void release_address_field_put(int offset, address contents); }; #endif // SHARE_VM_OOPS_KLASSOOP_HPP
--- a/src/share/vm/oops/klassVtable.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/oops/klassVtable.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1095,7 +1095,7 @@ itableOffsetEntry* ioe = (itableOffsetEntry*)klass->start_of_itable(); itableMethodEntry* ime = (itableMethodEntry*)(ioe + nof_interfaces); intptr_t* end = klass->end_of_itable(); - assert((oop*)(ime + nof_methods) <= (oop*)klass->start_of_static_fields(), "wrong offset calculation (1)"); + assert((oop*)(ime + nof_methods) <= (oop*)klass->start_of_nonstatic_oop_maps(), "wrong offset calculation (1)"); assert((oop*)(end) == (oop*)(ime + nof_methods), "wrong offset calculation (2)"); // Visit all interfaces and initialize itable offset table
--- a/src/share/vm/oops/methodOop.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/oops/methodOop.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -607,7 +607,7 @@ // method handles want to be able to push a few extra values (e.g., a bound receiver), and // invokedynamic sometimes needs to push a bootstrap method, call site, and arglist, // all without checking for a stack overflow - static int extra_stack_entries() { return (EnableMethodHandles ? (int)MethodHandlePushLimit : 0) + (EnableInvokeDynamic ? 3 : 0); } + static int extra_stack_entries() { return EnableInvokeDynamic ? (int) MethodHandlePushLimit + 3 : 0; } static int extra_stack_words(); // = extra_stack_entries() * Interpreter::stackElementSize() // RedefineClasses() support:
--- a/src/share/vm/oops/objArrayKlassKlass.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/oops/objArrayKlassKlass.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -31,6 +31,13 @@ #include "oops/objArrayKlassKlass.hpp" #include "oops/oop.inline.hpp" #include "oops/oop.inline2.hpp" +#ifndef SERIALGC +#include "gc_implementation/parNew/parOopClosures.inline.hpp" +#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" +#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" +#include "memory/cardTableRS.hpp" +#include "oops/oop.pcgc.inline.hpp" +#endif klassOop objArrayKlassKlass::create_klass(TRAPS) { objArrayKlassKlass o; @@ -236,12 +243,23 @@ addr = oak->bottom_klass_addr(); if (mr.contains(addr)) blk->do_oop(addr); - return arrayKlassKlass::oop_oop_iterate(obj, blk); + return arrayKlassKlass::oop_oop_iterate_m(obj, blk, mr); } #ifndef SERIALGC void objArrayKlassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { assert(obj->blueprint()->oop_is_objArrayKlass(),"must be an obj array klass"); + objArrayKlass* oak = objArrayKlass::cast((klassOop)obj); + oop* p = oak->element_klass_addr(); + if (PSScavenge::should_scavenge(p)) { + pm->claim_or_forward_depth(p); + } + p = oak->bottom_klass_addr(); + if (PSScavenge::should_scavenge(p)) { + pm->claim_or_forward_depth(p); + } + + arrayKlassKlass::oop_push_contents(pm, obj); } int objArrayKlassKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { @@ -287,7 +305,7 @@ // Verification void objArrayKlassKlass::oop_verify_on(oop obj, outputStream* st) { - klassKlass::oop_verify_on(obj, st); + arrayKlassKlass::oop_verify_on(obj, st); objArrayKlass* oak = objArrayKlass::cast((klassOop)obj); guarantee(oak->element_klass()->is_perm(), "should be in permspace"); guarantee(oak->element_klass()->is_klass(), "should be klass");
--- a/src/share/vm/oops/oop.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/oops/oop.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -129,6 +129,7 @@ // type test operations (inlined in oop.inline.h) bool is_instance() const; + bool is_instanceMirror() const; bool is_instanceRef() const; bool is_array() const; bool is_objArray() const;
--- a/src/share/vm/oops/oop.inline.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/oops/oop.inline.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -141,6 +141,7 @@ inline bool oopDesc::is_a(klassOop k) const { return blueprint()->is_subtype_of(k); } inline bool oopDesc::is_instance() const { return blueprint()->oop_is_instance(); } +inline bool oopDesc::is_instanceMirror() const { return blueprint()->oop_is_instanceMirror(); } inline bool oopDesc::is_instanceRef() const { return blueprint()->oop_is_instanceRef(); } inline bool oopDesc::is_array() const { return blueprint()->oop_is_array(); } inline bool oopDesc::is_objArray() const { return blueprint()->oop_is_objArray(); } @@ -399,7 +400,7 @@ inline int oopDesc::size_given_klass(Klass* klass) { int lh = klass->layout_helper(); - int s = lh >> LogHeapWordSize; // deliver size scaled by wordSize + int s; // lh is now a value computed at class initialization that may hint // at the size. For instances, this is positive and equal to the @@ -412,7 +413,13 @@ // alive or dead. So the speed here is equal in importance to the // speed of allocation. - if (lh <= Klass::_lh_neutral_value) { + if (lh > Klass::_lh_neutral_value) { + if (!Klass::layout_helper_needs_slow_path(lh)) { + s = lh >> LogHeapWordSize; // deliver size scaled by wordSize + } else { + s = klass->oop_size(this); + } + } else if (lh <= Klass::_lh_neutral_value) { // The most common case is instances; fall through if so. if (lh < Klass::_lh_neutral_value) { // Second most common case is arrays. We have to fetch the
--- a/src/share/vm/oops/oopsHierarchy.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/oops/oopsHierarchy.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -174,6 +174,7 @@ class Klass; class instanceKlass; +class instanceMirrorKlass; class instanceRefKlass; class methodKlass; class constMethodKlass;
--- a/src/share/vm/opto/bytecodeInfo.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/bytecodeInfo.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" +#include "compiler/compileBroker.hpp" #include "compiler/compileLog.hpp" #include "interpreter/linkResolver.hpp" #include "oops/objArrayKlass.hpp" @@ -75,13 +76,6 @@ assert(!UseOldInlining, "do not use for old stuff"); } - - -static void print_indent(int depth) { - tty->print(" "); - for (int i = depth; i != 0; --i) tty->print(" "); -} - static bool is_init_with_ea(ciMethod* callee_method, ciMethod* caller_method, Compile* C) { // True when EA is ON and a java constructor is called or @@ -100,7 +94,7 @@ if(callee_method->should_inline()) { *wci_result = *(WarmCallInfo::always_hot()); if (PrintInlining && Verbose) { - print_indent(inline_depth()); + CompileTask::print_inline_indent(inline_depth()); tty->print_cr("Inlined method is hot: "); } return NULL; @@ -116,7 +110,7 @@ size < InlineThrowMaxSize ) { wci_result->set_profit(wci_result->profit() * 100); if (PrintInlining && Verbose) { - print_indent(inline_depth()); + CompileTask::print_inline_indent(inline_depth()); tty->print_cr("Inlined method with many throws (throws=%d):", callee_method->interpreter_throwout_count()); } return NULL; @@ -138,9 +132,9 @@ max_size = C->freq_inline_size(); if (size <= max_size && TraceFrequencyInlining) { - print_indent(inline_depth()); + CompileTask::print_inline_indent(inline_depth()); tty->print_cr("Inlined frequent method (freq=%d count=%d):", freq, call_site_count); - print_indent(inline_depth()); + CompileTask::print_inline_indent(inline_depth()); callee_method->print(); tty->cr(); } @@ -315,8 +309,25 @@ if( inline_depth() > MaxInlineLevel ) { return "inlining too deep"; } - if( method() == callee_method && - inline_depth() > MaxRecursiveInlineLevel ) { + + // We need to detect recursive inlining of method handle targets: if + // the current method is a method handle adapter and one of the + // callers is the same method as the callee, we bail out if + // MaxRecursiveInlineLevel is hit. + if (method()->is_method_handle_adapter()) { + JVMState* jvms = caller_jvms(); + int inline_level = 0; + while (jvms != NULL && jvms->has_method()) { + if (jvms->method() == callee_method) { + inline_level++; + if (inline_level > MaxRecursiveInlineLevel) + return "recursively inlining too deep"; + } + jvms = jvms->caller(); + } + } + + if (method() == callee_method && inline_depth() > MaxRecursiveInlineLevel) { return "recursively inlining too deep"; } @@ -368,18 +379,14 @@ #ifndef PRODUCT //------------------------------print_inlining--------------------------------- // Really, the failure_msg can be a success message also. -void InlineTree::print_inlining(ciMethod *callee_method, int caller_bci, const char *failure_msg) const { - print_indent(inline_depth()); - tty->print("@ %d ", caller_bci); - if( callee_method ) callee_method->print_short_name(); - else tty->print(" callee not monotonic or profiled"); - tty->print(" %s", (failure_msg ? failure_msg : "inline")); - if( Verbose && callee_method ) { +void InlineTree::print_inlining(ciMethod* callee_method, int caller_bci, const char* failure_msg) const { + CompileTask::print_inlining(callee_method, inline_depth(), caller_bci, failure_msg ? failure_msg : "inline"); + if (callee_method == NULL) tty->print(" callee not monotonic or profiled"); + if (Verbose && callee_method) { const InlineTree *top = this; while( top->caller_tree() != NULL ) { top = top->caller_tree(); } tty->print(" bcs: %d+%d invoked: %d", top->count_inline_bcs(), callee_method->code_size(), callee_method->interpreter_invocation_count()); } - tty->cr(); } #endif
--- a/src/share/vm/opto/c2_globals.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/c2_globals.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -180,6 +180,9 @@ develop(bool, TraceLoopPredicate, false, \ "Trace generation of loop predicates") \ \ + develop(bool, TraceLoopOpts, false, \ + "Trace executed loop optimizations") \ + \ product(bool, OptimizeFill, false, \ "convert fill/copy loops into intrinsic") \ \
--- a/src/share/vm/opto/chaitin.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/chaitin.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -673,7 +673,7 @@ case Op_RegD: lrg.set_num_regs(2); // Define platform specific register pressure -#ifdef SPARC +#if defined(SPARC) || defined(ARM) lrg.set_reg_pressure(2); #elif defined(IA32) if( ireg == Op_RegL ) {
--- a/src/share/vm/opto/compile.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/compile.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -1202,11 +1202,15 @@ // Oop pointers need some flattening const TypeInstPtr *to = tj->isa_instptr(); if( to && _AliasLevel >= 2 && to != TypeOopPtr::BOTTOM ) { + ciInstanceKlass *k = to->klass()->as_instance_klass(); if( ptr == TypePtr::Constant ) { - // No constant oop pointers (such as Strings); they alias with - // unknown strings. - assert(!is_known_inst, "not scalarizable allocation"); - tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,offset); + if (to->klass() != ciEnv::current()->Class_klass() || + offset < k->size_helper() * wordSize) { + // No constant oop pointers (such as Strings); they alias with + // unknown strings. + assert(!is_known_inst, "not scalarizable allocation"); + tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,offset); + } } else if( is_known_inst ) { tj = to; // Keep NotNull and klass_is_exact for instance type } else if( ptr == TypePtr::NotNull || to->klass_is_exact() ) { @@ -1216,7 +1220,6 @@ tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,offset); } // Canonicalize the holder of this field - ciInstanceKlass *k = to->klass()->as_instance_klass(); if (offset >= 0 && offset < instanceOopDesc::base_offset_in_bytes()) { // First handle header references such as a LoadKlassNode, even if the // object's klass is unloaded at compile time (4965979). @@ -1224,9 +1227,13 @@ tj = to = TypeInstPtr::make(TypePtr::BotPTR, env()->Object_klass(), false, NULL, offset); } } else if (offset < 0 || offset >= k->size_helper() * wordSize) { - to = NULL; - tj = TypeOopPtr::BOTTOM; - offset = tj->offset(); + // Static fields are in the space above the normal instance + // fields in the java.lang.Class instance. + if (to->klass() != ciEnv::current()->Class_klass()) { + to = NULL; + tj = TypeOopPtr::BOTTOM; + offset = tj->offset(); + } } else { ciInstanceKlass *canonical_holder = k->get_canonical_holder(offset); if (!k->equals(canonical_holder) || tj->offset() != offset) { @@ -1399,7 +1406,7 @@ //--------------------------------find_alias_type------------------------------ -Compile::AliasType* Compile::find_alias_type(const TypePtr* adr_type, bool no_create) { +Compile::AliasType* Compile::find_alias_type(const TypePtr* adr_type, bool no_create, ciField* original_field) { if (_AliasLevel == 0) return alias_type(AliasIdxBot); @@ -1464,22 +1471,28 @@ // but the base pointer type is not distinctive enough to identify // references into JavaThread.) - // Check for final instance fields. + // Check for final fields. const TypeInstPtr* tinst = flat->isa_instptr(); if (tinst && tinst->offset() >= instanceOopDesc::base_offset_in_bytes()) { - ciInstanceKlass *k = tinst->klass()->as_instance_klass(); - ciField* field = k->get_field_by_offset(tinst->offset(), false); + ciField* field; + if (tinst->const_oop() != NULL && + tinst->klass() == ciEnv::current()->Class_klass() && + tinst->offset() >= (tinst->klass()->as_instance_klass()->size_helper() * wordSize)) { + // static field + ciInstanceKlass* k = tinst->const_oop()->as_instance()->java_lang_Class_klass()->as_instance_klass(); + field = k->get_field_by_offset(tinst->offset(), true); + } else { + ciInstanceKlass *k = tinst->klass()->as_instance_klass(); + field = k->get_field_by_offset(tinst->offset(), false); + } + assert(field == NULL || + original_field == NULL || + (field->holder() == original_field->holder() && + field->offset() == original_field->offset() && + field->is_static() == original_field->is_static()), "wrong field?"); // Set field() and is_rewritable() attributes. if (field != NULL) alias_type(idx)->set_field(field); } - const TypeKlassPtr* tklass = flat->isa_klassptr(); - // Check for final static fields. - if (tklass && tklass->klass()->is_instance_klass()) { - ciInstanceKlass *k = tklass->klass()->as_instance_klass(); - ciField* field = k->get_field_by_offset(tklass->offset(), true); - // Set field() and is_rewritable() attributes. - if (field != NULL) alias_type(idx)->set_field(field); - } } // Fill the cache for next time. @@ -1502,10 +1515,10 @@ Compile::AliasType* Compile::alias_type(ciField* field) { const TypeOopPtr* t; if (field->is_static()) - t = TypeKlassPtr::make(field->holder()); + t = TypeInstPtr::make(field->holder()->java_mirror()); else t = TypeOopPtr::make_from_klass_raw(field->holder()); - AliasType* atp = alias_type(t->add_offset(field->offset_in_bytes())); + AliasType* atp = alias_type(t->add_offset(field->offset_in_bytes()), field); assert(field->is_final() == !atp->is_rewritable(), "must get the rewritable bits correct"); return atp; } @@ -1522,7 +1535,7 @@ if (adr_type == NULL) return true; if (adr_type == TypePtr::BOTTOM) return true; - return find_alias_type(adr_type, true) != NULL; + return find_alias_type(adr_type, true, NULL) != NULL; } //-----------------------------must_alias-------------------------------------- @@ -2531,6 +2544,36 @@ frc.inc_inner_loop_count(); } break; + case Op_LShiftI: + case Op_RShiftI: + case Op_URShiftI: + case Op_LShiftL: + case Op_RShiftL: + case Op_URShiftL: + if (Matcher::need_masked_shift_count) { + // The cpu's shift instructions don't restrict the count to the + // lower 5/6 bits. We need to do the masking ourselves. + Node* in2 = n->in(2); + juint mask = (n->bottom_type() == TypeInt::INT) ? (BitsPerInt - 1) : (BitsPerLong - 1); + const TypeInt* t = in2->find_int_type(); + if (t != NULL && t->is_con()) { + juint shift = t->get_con(); + if (shift > mask) { // Unsigned cmp + Compile* C = Compile::current(); + n->set_req(2, ConNode::make(C, TypeInt::make(shift & mask))); + } + } else { + if (t == NULL || t->_lo < 0 || t->_hi > (int)mask) { + Compile* C = Compile::current(); + Node* shift = new (C, 3) AndINode(in2, ConNode::make(C, TypeInt::make(mask))); + n->set_req(2, shift); + } + } + if (in2->outcnt() == 0) { // Remove dead node + in2->disconnect_inputs(NULL); + } + } + break; default: assert( !n->is_Call(), "" ); assert( !n->is_Mem(), "" );
--- a/src/share/vm/opto/compile.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/compile.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -596,7 +596,7 @@ } AliasType* alias_type(int idx) { assert(idx < num_alias_types(), "oob"); return _alias_types[idx]; } - AliasType* alias_type(const TypePtr* adr_type) { return find_alias_type(adr_type, false); } + AliasType* alias_type(const TypePtr* adr_type, ciField* field = NULL) { return find_alias_type(adr_type, false, field); } bool have_alias_type(const TypePtr* adr_type); AliasType* alias_type(ciField* field); @@ -835,7 +835,7 @@ void grow_alias_types(); AliasCacheEntry* probe_alias_cache(const TypePtr* adr_type); const TypePtr *flatten_alias_type(const TypePtr* adr_type) const; - AliasType* find_alias_type(const TypePtr* adr_type, bool no_create); + AliasType* find_alias_type(const TypePtr* adr_type, bool no_create, ciField* field); void verify_top(Node*) const PRODUCT_RETURN;
--- a/src/share/vm/opto/doCall.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/doCall.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2011, 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,6 +27,7 @@ #include "ci/ciCallSite.hpp" #include "ci/ciMethodHandle.hpp" #include "classfile/vmSymbols.hpp" +#include "compiler/compileBroker.hpp" #include "compiler/compileLog.hpp" #include "interpreter/linkResolver.hpp" #include "opto/addnode.hpp" @@ -43,17 +44,17 @@ #ifndef PRODUCT void trace_type_profile(ciMethod *method, int depth, int bci, ciMethod *prof_method, ciKlass *prof_klass, int site_count, int receiver_count) { if (TraceTypeProfile || PrintInlining || PrintOptoInlining) { - tty->print(" "); - for( int i = 0; i < depth; i++ ) tty->print(" "); - if (!PrintOpto) { - method->print_short_name(); - tty->print(" ->"); + if (!PrintInlining) { + if (!PrintOpto && !PrintCompilation) { + method->print_short_name(); + tty->cr(); + } + CompileTask::print_inlining(prof_method, depth, bci); } - tty->print(" @ %d ", bci); - prof_method->print_short_name(); - tty->print(" >>TypeProfile (%d/%d counts) = ", receiver_count, site_count); + CompileTask::print_inline_indent(depth); + tty->print(" \\-> TypeProfile (%d/%d counts) = ", receiver_count, site_count); prof_klass->name()->print_symbol(); - tty->print_cr(" (%d bytes)", prof_method->code_size()); + tty->cr(); } } #endif @@ -269,13 +270,13 @@ } if (miss_cg != NULL) { if (next_hit_cg != NULL) { - NOT_PRODUCT(trace_type_profile(jvms->method(), jvms->depth(), jvms->bci(), next_receiver_method, profile.receiver(1), site_count, profile.receiver_count(1))); + NOT_PRODUCT(trace_type_profile(jvms->method(), jvms->depth() - 1, jvms->bci(), next_receiver_method, profile.receiver(1), site_count, profile.receiver_count(1))); // We don't need to record dependency on a receiver here and below. // Whenever we inline, the dependency is added by Parse::Parse(). miss_cg = CallGenerator::for_predicted_call(profile.receiver(1), miss_cg, next_hit_cg, PROB_MAX); } if (miss_cg != NULL) { - NOT_PRODUCT(trace_type_profile(jvms->method(), jvms->depth(), jvms->bci(), receiver_method, profile.receiver(0), site_count, receiver_count)); + NOT_PRODUCT(trace_type_profile(jvms->method(), jvms->depth() - 1, jvms->bci(), receiver_method, profile.receiver(0), site_count, receiver_count)); cg = CallGenerator::for_predicted_call(profile.receiver(0), miss_cg, hit_cg, profile.receiver_prob(0)); if (cg != NULL) return cg; }
--- a/src/share/vm/opto/graphKit.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/graphKit.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -3338,6 +3338,49 @@ return NULL; } +//----------------------------- loop predicates --------------------------- + +//------------------------------add_predicate_impl---------------------------- +void GraphKit::add_predicate_impl(Deoptimization::DeoptReason reason, int nargs) { + // Too many traps seen? + if (too_many_traps(reason)) { +#ifdef ASSERT + if (TraceLoopPredicate) { + int tc = C->trap_count(reason); + tty->print("too many traps=%s tcount=%d in ", + Deoptimization::trap_reason_name(reason), tc); + method()->print(); // which method has too many predicate traps + tty->cr(); + } +#endif + // We cannot afford to take more traps here, + // do not generate predicate. + return; + } + + Node *cont = _gvn.intcon(1); + Node* opq = _gvn.transform(new (C, 2) Opaque1Node(C, cont)); + Node *bol = _gvn.transform(new (C, 2) Conv2BNode(opq)); + IfNode* iff = create_and_map_if(control(), bol, PROB_MAX, COUNT_UNKNOWN); + Node* iffalse = _gvn.transform(new (C, 1) IfFalseNode(iff)); + C->add_predicate_opaq(opq); + { + PreserveJVMState pjvms(this); + set_control(iffalse); + _sp += nargs; + uncommon_trap(reason, Deoptimization::Action_maybe_recompile); + } + Node* iftrue = _gvn.transform(new (C, 1) IfTrueNode(iff)); + set_control(iftrue); +} + +//------------------------------add_predicate--------------------------------- +void GraphKit::add_predicate(int nargs) { + if (UseLoopPredicate) { + add_predicate_impl(Deoptimization::Reason_predicate, nargs); + } +} + //----------------------------- store barriers ---------------------------- #define __ ideal.
--- a/src/share/vm/opto/graphKit.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/graphKit.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -793,6 +793,10 @@ if (!tst->is_Con()) record_for_igvn(iff); // Range-check and Null-check removal is later return iff; } + + // Insert a loop predicate into the graph + void add_predicate(int nargs = 0); + void add_predicate_impl(Deoptimization::DeoptReason reason, int nargs); }; // Helper class to support building of control flow branches. Upon
--- a/src/share/vm/opto/idealGraphPrinter.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/idealGraphPrinter.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2011, 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 @@ -599,11 +599,35 @@ if (caller != NULL) { stringStream bciStream; + ciMethod* last = NULL; + int last_bci; while(caller) { + if (caller->has_method()) { + last = caller->method(); + last_bci = caller->bci(); + } bciStream.print("%d ", caller->bci()); caller = caller->caller(); } print_prop("bci", bciStream.as_string()); + if (last != NULL && last->has_linenumber_table() && last_bci >= 0) { + print_prop("line", last->line_number_from_bci(last_bci)); + } + } + + if (node->debug_orig() != NULL) { + stringStream dorigStream; + Node* dorig = node->debug_orig(); + if (dorig) { + dorigStream.print("%d ", dorig->_idx); + Node* first = dorig; + dorig = first->debug_orig(); + while (dorig && dorig != first) { + dorigStream.print("%d ", dorig->_idx); + dorig = dorig->debug_orig(); + } + } + print_prop("debug_orig", dorigStream.as_string()); } if (_chaitin && _chaitin != (PhaseChaitin *)0xdeadbeef) { @@ -628,6 +652,17 @@ GrowableArray<Node *> nodeStack(Thread::current()->resource_area(), 0, 0, NULL); nodeStack.push(start); visited.test_set(start->_idx); + if (C->cfg() != NULL) { + // once we have a CFG there are some nodes that aren't really + // reachable but are in the CFG so add them here. + for (uint i = 0; i < C->cfg()->_blocks.size(); i++) { + Block *b = C->cfg()->_blocks[i]; + for (uint s = 0; s < b->_nodes.size(); s++) { + nodeStack.push(b->_nodes[s]); + } + } + } + while(nodeStack.length() > 0) { Node *n = nodeStack.pop(); @@ -686,16 +721,23 @@ end_head(); head(SUCCESSORS_ELEMENT); - for (uint s = 0; s < C->cfg()->_blocks[i]->_num_succs; s++) { + for (uint s = 0; s < b->_num_succs; s++) { begin_elem(SUCCESSOR_ELEMENT); print_attr(BLOCK_NAME_PROPERTY, b->_succs[s]->_pre_order); end_elem(); } tail(SUCCESSORS_ELEMENT); + head(NODES_ELEMENT); + for (uint s = 0; s < b->_nodes.size(); s++) { + begin_elem(NODE_ELEMENT); + print_attr(NODE_ID_PROPERTY, get_node_id(b->_nodes[s])); + end_elem(); + } + tail(NODES_ELEMENT); + tail(BLOCK_ELEMENT); } - tail(CONTROL_FLOW_ELEMENT); } tail(GRAPH_ELEMENT);
--- a/src/share/vm/opto/idealGraphPrinter.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/idealGraphPrinter.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2011, 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,15 +45,6 @@ { private: - enum State - { - Invalid, - Valid, - New - }; - -private: - static const char *INDENT; static const char *TOP_ELEMENT; static const char *GROUP_ELEMENT;
--- a/src/share/vm/opto/idealKit.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/idealKit.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -154,8 +154,18 @@ // // Pushes the loop top cvstate first, then the else (loop exit) cvstate // onto the stack. -void IdealKit::loop(IdealVariable& iv, Node* init, BoolTest::mask relop, Node* limit, float prob, float cnt) { +void IdealKit::loop(GraphKit* gkit, int nargs, IdealVariable& iv, Node* init, BoolTest::mask relop, Node* limit, float prob, float cnt) { assert((state() & (BlockS|LoopS|IfThenS|ElseS)), "bad state for new loop"); + + // Sync IdealKit and graphKit. + gkit->set_all_memory(this->merged_memory()); + gkit->set_control(this->ctrl()); + // Add loop predicate. + gkit->add_predicate(nargs); + // Update IdealKit memory. + this->set_all_memory(gkit->merged_memory()); + this->set_ctrl(gkit->control()); + set(iv, init); Node* head = make_label(1); bind(head);
--- a/src/share/vm/opto/idealKit.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/idealKit.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -29,6 +29,7 @@ #include "opto/cfgnode.hpp" #include "opto/connode.hpp" #include "opto/divnode.hpp" +#include "opto/graphKit.hpp" #include "opto/mulnode.hpp" #include "opto/phaseX.hpp" #include "opto/subnode.hpp" @@ -160,7 +161,7 @@ bool push_new_state = true); void else_(); void end_if(); - void loop(IdealVariable& iv, Node* init, BoolTest::mask cmp, Node* limit, + void loop(GraphKit* gkit, int nargs, IdealVariable& iv, Node* init, BoolTest::mask cmp, Node* limit, float prob = PROB_LIKELY(0.9), float cnt = COUNT_UNKNOWN); void end_loop(); Node* make_label(int goto_ct);
--- a/src/share/vm/opto/lcm.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/lcm.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -42,6 +42,9 @@ #ifdef TARGET_ARCH_MODEL_zero # include "adfiles/ad_zero.hpp" #endif +#ifdef TARGET_ARCH_MODEL_arm +# include "adfiles/ad_arm.hpp" +#endif // Optimization - Graph Style
--- a/src/share/vm/opto/library_call.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/library_call.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" +#include "compiler/compileBroker.hpp" #include "compiler/compileLog.hpp" #include "oops/objArrayKlass.hpp" #include "opto/addnode.hpp" @@ -388,11 +389,7 @@ #endif if (kit.try_to_inline()) { if (PrintIntrinsics || PrintInlining NOT_PRODUCT( || PrintOptoInlining) ) { - tty->print("Inlining intrinsic %s%s at bci:%d in", - vmIntrinsics::name_at(intrinsic_id()), - (is_virtual() ? " (virtual)" : ""), kit.bci()); - kit.caller()->print_short_name(tty); - tty->print_cr(" (%d bytes)", kit.caller()->code_size()); + CompileTask::print_inlining(kit.callee(), jvms->depth() - 1, kit.bci(), is_virtual() ? "(intrinsic, virtual)" : "(intrinsic)"); } C->gather_intrinsic_statistics(intrinsic_id(), is_virtual(), Compile::_intrinsic_worked); if (C->log()) { @@ -1101,6 +1098,8 @@ float likely = PROB_LIKELY(0.9); float unlikely = PROB_UNLIKELY(0.9); + const int nargs = 2; // number of arguments to push back for uncommon trap in predicate + const int value_offset = java_lang_String::value_offset_in_bytes(); const int count_offset = java_lang_String::count_offset_in_bytes(); const int offset_offset = java_lang_String::offset_offset_in_bytes(); @@ -1116,7 +1115,7 @@ Node* sourcea = basic_plus_adr(string_object, string_object, value_offset); Node* source = make_load(no_ctrl, sourcea, source_type, T_OBJECT, string_type->add_offset(value_offset)); - Node* target = _gvn.transform( makecon(TypeOopPtr::make_from_constant(target_array)) ); + Node* target = _gvn.transform( makecon(TypeOopPtr::make_from_constant(target_array, true)) ); jint target_length = target_array->length(); const TypeAry* target_array_type = TypeAry::make(TypeInt::CHAR, TypeInt::make(0, target_length, Type::WidenMin)); const TypeAryPtr* target_type = TypeAryPtr::make(TypePtr::BotPTR, target_array_type, target_array->klass(), true, Type::OffsetBot); @@ -1138,12 +1137,12 @@ Node* return_ = __ make_label(1); __ set(rtn,__ ConI(-1)); - __ loop(i, sourceOffset, BoolTest::lt, sourceEnd); { + __ loop(this, nargs, i, sourceOffset, BoolTest::lt, sourceEnd); { Node* i2 = __ AddI(__ value(i), targetCountLess1); // pin to prohibit loading of "next iteration" value which may SEGV (rare) Node* src = load_array_element(__ ctrl(), source, i2, TypeAryPtr::CHARS); __ if_then(src, BoolTest::eq, lastChar, unlikely); { - __ loop(j, zero, BoolTest::lt, targetCountLess1); { + __ loop(this, nargs, j, zero, BoolTest::lt, targetCountLess1); { Node* tpj = __ AddI(targetOffset, __ value(j)); Node* targ = load_array_element(no_ctrl, target, tpj, target_type); Node* ipj = __ AddI(__ value(i), __ value(j));
--- a/src/share/vm/opto/loopTransform.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/loopTransform.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -205,6 +205,8 @@ } phase->register_new_node(addx, phase->get_ctrl(x)); phase->_igvn.replace_node(n1, addx); + assert(phase->get_loop(phase->get_ctrl(n1)) == this, ""); + _body.yank(n1); return addx; } @@ -307,15 +309,21 @@ // iterations adjusted. Therefore, we need to declare this loop as // no longer a 'main' loop; it will need new pre and post loops before // we can do further RCE. +#ifndef PRODUCT + if (TraceLoopOpts) { + tty->print("Peel "); + loop->dump_head(); + } +#endif Node *h = loop->_head; - if( h->is_CountedLoop() ) { + if (h->is_CountedLoop()) { CountedLoopNode *cl = h->as_CountedLoop(); assert(cl->trip_count() > 0, "peeling a fully unrolled loop"); cl->set_trip_count(cl->trip_count() - 1); - if( cl->is_main_loop() ) { + if (cl->is_main_loop()) { cl->set_normal_loop(); #ifndef PRODUCT - if( PrintOpto && VerifyLoopOptimizations ) { + if (PrintOpto && VerifyLoopOptimizations) { tty->print("Peeling a 'main' loop; resetting to 'normal' "); loop->dump_head(); } @@ -388,16 +396,16 @@ // Return exact loop trip count, or 0 if not maximally unrolling bool IdealLoopTree::policy_maximally_unroll( PhaseIdealLoop *phase ) const { CountedLoopNode *cl = _head->as_CountedLoop(); - assert( cl->is_normal_loop(), "" ); + assert(cl->is_normal_loop(), ""); Node *init_n = cl->init_trip(); Node *limit_n = cl->limit(); // Non-constant bounds - if( init_n == NULL || !init_n->is_Con() || + if (init_n == NULL || !init_n->is_Con() || limit_n == NULL || !limit_n->is_Con() || // protect against stride not being a constant - !cl->stride_is_con() ) { + !cl->stride_is_con()) { return false; } int init = init_n->get_int(); @@ -420,7 +428,31 @@ uint unroll_limit = (uint)LoopUnrollLimit * 4; assert( (intx)unroll_limit == LoopUnrollLimit * 4, "LoopUnrollLimit must fit in 32bits"); cl->set_trip_count(trip_count); - if( trip_count <= unroll_limit && body_size <= unroll_limit ) { + if (trip_count > unroll_limit || body_size > unroll_limit) { + return false; + } + + // Currently we don't have policy to optimize one iteration loops. + // Maximally unrolling transformation is used for that: + // it is peeled and the original loop become non reachable (dead). + if (trip_count == 1) + return true; + + // Do not unroll a loop with String intrinsics code. + // String intrinsics are large and have loops. + for (uint k = 0; k < _body.size(); k++) { + Node* n = _body.at(k); + switch (n->Opcode()) { + case Op_StrComp: + case Op_StrEquals: + case Op_StrIndexOf: + case Op_AryEq: { + return false; + } + } // switch + } + + if (body_size <= unroll_limit) { uint new_body_size = body_size * trip_count; if (new_body_size <= unroll_limit && body_size == new_body_size / trip_count && @@ -440,13 +472,13 @@ bool IdealLoopTree::policy_unroll( PhaseIdealLoop *phase ) const { CountedLoopNode *cl = _head->as_CountedLoop(); - assert( cl->is_normal_loop() || cl->is_main_loop(), "" ); + assert(cl->is_normal_loop() || cl->is_main_loop(), ""); // protect against stride not being a constant - if( !cl->stride_is_con() ) return false; + if (!cl->stride_is_con()) return false; // protect against over-unrolling - if( cl->trip_count() <= 1 ) return false; + if (cl->trip_count() <= 1) return false; int future_unroll_ct = cl->unrolled_count() * 2; @@ -477,21 +509,21 @@ // Non-constant bounds. // Protect against over-unrolling when init or/and limit are not constant // (so that trip_count's init value is maxint) but iv range is known. - if( init_n == NULL || !init_n->is_Con() || - limit_n == NULL || !limit_n->is_Con() ) { + if (init_n == NULL || !init_n->is_Con() || + limit_n == NULL || !limit_n->is_Con()) { Node* phi = cl->phi(); - if( phi != NULL ) { + if (phi != NULL) { assert(phi->is_Phi() && phi->in(0) == _head, "Counted loop should have iv phi."); const TypeInt* iv_type = phase->_igvn.type(phi)->is_int(); int next_stride = cl->stride_con() * 2; // stride after this unroll - if( next_stride > 0 ) { - if( iv_type->_lo + next_stride <= iv_type->_lo || // overflow - iv_type->_lo + next_stride > iv_type->_hi ) { + if (next_stride > 0) { + if (iv_type->_lo + next_stride <= iv_type->_lo || // overflow + iv_type->_lo + next_stride > iv_type->_hi) { return false; // over-unrolling } - } else if( next_stride < 0 ) { - if( iv_type->_hi + next_stride >= iv_type->_hi || // overflow - iv_type->_hi + next_stride < iv_type->_lo ) { + } else if (next_stride < 0) { + if (iv_type->_hi + next_stride >= iv_type->_hi || // overflow + iv_type->_hi + next_stride < iv_type->_lo) { return false; // over-unrolling } } @@ -503,24 +535,33 @@ // Key test to unroll CaffeineMark's Logic test int xors_in_loop = 0; // Also count ModL, DivL and MulL which expand mightly - for( uint k = 0; k < _body.size(); k++ ) { - switch( _body.at(k)->Opcode() ) { - case Op_XorI: xors_in_loop++; break; // CaffeineMark's Logic test - case Op_ModL: body_size += 30; break; - case Op_DivL: body_size += 30; break; - case Op_MulL: body_size += 10; break; - } + for (uint k = 0; k < _body.size(); k++) { + Node* n = _body.at(k); + switch (n->Opcode()) { + case Op_XorI: xors_in_loop++; break; // CaffeineMark's Logic test + case Op_ModL: body_size += 30; break; + case Op_DivL: body_size += 30; break; + case Op_MulL: body_size += 10; break; + case Op_StrComp: + case Op_StrEquals: + case Op_StrIndexOf: + case Op_AryEq: { + // Do not unroll a loop with String intrinsics code. + // String intrinsics are large and have loops. + return false; + } + } // switch } // Check for being too big - if( body_size > (uint)LoopUnrollLimit ) { - if( xors_in_loop >= 4 && body_size < (uint)LoopUnrollLimit*4) return true; + if (body_size > (uint)LoopUnrollLimit) { + if (xors_in_loop >= 4 && body_size < (uint)LoopUnrollLimit*4) return true; // Normal case: loop too big return false; } // Check for stride being a small enough constant - if( abs(cl->stride_con()) > (1<<3) ) return false; + if (abs(cl->stride_con()) > (1<<3)) return false; // Unroll once! (Each trip will soon do double iterations) return true; @@ -645,6 +686,15 @@ // alignment. Useful to unroll loops that do no array accesses. void PhaseIdealLoop::insert_pre_post_loops( IdealLoopTree *loop, Node_List &old_new, bool peel_only ) { +#ifndef PRODUCT + if (TraceLoopOpts) { + if (peel_only) + tty->print("PeelMainPost "); + else + tty->print("PreMainPost "); + loop->dump_head(); + } +#endif C->set_major_progress(); // Find common pieces of the loop being guarded with pre & post loops @@ -897,16 +947,19 @@ //------------------------------do_unroll-------------------------------------- // Unroll the loop body one step - make each trip do 2 iterations. void PhaseIdealLoop::do_unroll( IdealLoopTree *loop, Node_List &old_new, bool adjust_min_trip ) { - assert( LoopUnrollLimit, "" ); + assert(LoopUnrollLimit, ""); + CountedLoopNode *loop_head = loop->_head->as_CountedLoop(); + CountedLoopEndNode *loop_end = loop_head->loopexit(); + assert(loop_end, ""); #ifndef PRODUCT - if( PrintOpto && VerifyLoopOptimizations ) { + if (PrintOpto && VerifyLoopOptimizations) { tty->print("Unrolling "); loop->dump_head(); + } else if (TraceLoopOpts) { + tty->print("Unroll %d ", loop_head->unrolled_count()*2); + loop->dump_head(); } #endif - CountedLoopNode *loop_head = loop->_head->as_CountedLoop(); - CountedLoopEndNode *loop_end = loop_head->loopexit(); - assert( loop_end, "" ); // Remember loop node count before unrolling to detect // if rounds of unroll,optimize are making progress @@ -915,7 +968,7 @@ Node *ctrl = loop_head->in(LoopNode::EntryControl); Node *limit = loop_head->limit(); Node *init = loop_head->init_trip(); - Node *strid = loop_head->stride(); + Node *stride = loop_head->stride(); Node *opaq = NULL; if( adjust_min_trip ) { // If not maximally unrolling, need adjustment @@ -955,13 +1008,13 @@ // odd iteration: (trip_cnt & ~1). Then back compute a new limit. Node *span = new (C, 3) SubINode( limit, init ); register_new_node( span, ctrl ); - Node *trip = new (C, 3) DivINode( 0, span, strid ); + Node *trip = new (C, 3) DivINode( 0, span, stride ); register_new_node( trip, ctrl ); Node *mtwo = _igvn.intcon(-2); set_ctrl(mtwo, C->root()); Node *rond = new (C, 3) AndINode( trip, mtwo ); register_new_node( rond, ctrl ); - Node *spn2 = new (C, 3) MulINode( rond, strid ); + Node *spn2 = new (C, 3) MulINode( rond, stride ); register_new_node( spn2, ctrl ); Node *lim2 = new (C, 3) AddINode( spn2, init ); register_new_node( lim2, ctrl ); @@ -1040,17 +1093,23 @@ void PhaseIdealLoop::do_maximally_unroll( IdealLoopTree *loop, Node_List &old_new ) { CountedLoopNode *cl = loop->_head->as_CountedLoop(); - assert( cl->trip_count() > 0, ""); + assert(cl->trip_count() > 0, ""); +#ifndef PRODUCT + if (TraceLoopOpts) { + tty->print("MaxUnroll %d ", cl->trip_count()); + loop->dump_head(); + } +#endif // If loop is tripping an odd number of times, peel odd iteration - if( (cl->trip_count() & 1) == 1 ) { - do_peeling( loop, old_new ); + if ((cl->trip_count() & 1) == 1) { + do_peeling(loop, old_new); } // Now its tripping an even number of times remaining. Double loop body. // Do not adjust pre-guards; they are not needed and do not exist. - if( cl->trip_count() > 0 ) { - do_unroll( loop, old_new, false ); + if (cl->trip_count() > 0) { + do_unroll(loop, old_new, false); } } @@ -1227,35 +1286,55 @@ // Eliminate range-checks and other trip-counter vs loop-invariant tests. void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { #ifndef PRODUCT - if( PrintOpto && VerifyLoopOptimizations ) { + if (PrintOpto && VerifyLoopOptimizations) { tty->print("Range Check Elimination "); loop->dump_head(); + } else if (TraceLoopOpts) { + tty->print("RangeCheck "); + loop->dump_head(); } #endif - assert( RangeCheckElimination, "" ); + assert(RangeCheckElimination, ""); CountedLoopNode *cl = loop->_head->as_CountedLoop(); - assert( cl->is_main_loop(), "" ); + assert(cl->is_main_loop(), ""); + + // protect against stride not being a constant + if (!cl->stride_is_con()) + return; // Find the trip counter; we are iteration splitting based on it Node *trip_counter = cl->phi(); // Find the main loop limit; we will trim it's iterations // to not ever trip end tests Node *main_limit = cl->limit(); + + // Need to find the main-loop zero-trip guard + Node *ctrl = cl->in(LoopNode::EntryControl); + assert(ctrl->Opcode() == Op_IfTrue || ctrl->Opcode() == Op_IfFalse, ""); + Node *iffm = ctrl->in(0); + assert(iffm->Opcode() == Op_If, ""); + Node *bolzm = iffm->in(1); + assert(bolzm->Opcode() == Op_Bool, ""); + Node *cmpzm = bolzm->in(1); + assert(cmpzm->is_Cmp(), ""); + Node *opqzm = cmpzm->in(2); + // Can not optimize a loop if pre-loop Opaque1 node is optimized + // away and then another round of loop opts attempted. + if (opqzm->Opcode() != Op_Opaque1) + return; + assert(opqzm->in(1) == main_limit, "do not understand situation"); + // Find the pre-loop limit; we will expand it's iterations to // not ever trip low tests. - Node *ctrl = cl->in(LoopNode::EntryControl); - assert( ctrl->Opcode() == Op_IfTrue || ctrl->Opcode() == Op_IfFalse, "" ); - Node *iffm = ctrl->in(0); - assert( iffm->Opcode() == Op_If, "" ); Node *p_f = iffm->in(0); - assert( p_f->Opcode() == Op_IfFalse, "" ); + assert(p_f->Opcode() == Op_IfFalse, ""); CountedLoopEndNode *pre_end = p_f->in(0)->as_CountedLoopEnd(); - assert( pre_end->loopnode()->is_pre_loop(), "" ); + assert(pre_end->loopnode()->is_pre_loop(), ""); Node *pre_opaq1 = pre_end->limit(); // Occasionally it's possible for a pre-loop Opaque1 node to be // optimized away and then another round of loop opts attempted. // We can not optimize this particular loop in that case. - if( pre_opaq1->Opcode() != Op_Opaque1 ) + if (pre_opaq1->Opcode() != Op_Opaque1) return; Opaque1Node *pre_opaq = (Opaque1Node*)pre_opaq1; Node *pre_limit = pre_opaq->in(1); @@ -1266,25 +1345,11 @@ // Ensure the original loop limit is available from the // pre-loop Opaque1 node. Node *orig_limit = pre_opaq->original_loop_limit(); - if( orig_limit == NULL || _igvn.type(orig_limit) == Type::TOP ) + if (orig_limit == NULL || _igvn.type(orig_limit) == Type::TOP) return; - // Need to find the main-loop zero-trip guard - Node *bolzm = iffm->in(1); - assert( bolzm->Opcode() == Op_Bool, "" ); - Node *cmpzm = bolzm->in(1); - assert( cmpzm->is_Cmp(), "" ); - Node *opqzm = cmpzm->in(2); - if( opqzm->Opcode() != Op_Opaque1 ) - return; - assert( opqzm->in(1) == main_limit, "do not understand situation" ); - // Must know if its a count-up or count-down loop - // protect against stride not being a constant - if ( !cl->stride_is_con() ) { - return; - } int stride_con = cl->stride_con(); Node *zero = _igvn.intcon(0); Node *one = _igvn.intcon(1); @@ -1566,17 +1631,17 @@ // have on the last iteration. This will break the loop. bool IdealLoopTree::policy_do_remove_empty_loop( PhaseIdealLoop *phase ) { // Minimum size must be empty loop - if( _body.size() > 7/*number of nodes in an empty loop*/ ) return false; + if (_body.size() > 7/*number of nodes in an empty loop*/) + return false; - if( !_head->is_CountedLoop() ) return false; // Dead loop + if (!_head->is_CountedLoop()) + return false; // Dead loop CountedLoopNode *cl = _head->as_CountedLoop(); - if( !cl->loopexit() ) return false; // Malformed loop - if( !phase->is_member(this,phase->get_ctrl(cl->loopexit()->in(CountedLoopEndNode::TestValue)) ) ) + if (!cl->loopexit()) + return false; // Malformed loop + if (!phase->is_member(this, phase->get_ctrl(cl->loopexit()->in(CountedLoopEndNode::TestValue)))) return false; // Infinite loop -#ifndef PRODUCT - if( PrintOpto ) - tty->print_cr("Removing empty loop"); -#endif + #ifdef ASSERT // Ensure only one phi which is the iv. Node* iv = NULL; @@ -1589,6 +1654,43 @@ } assert(iv == cl->phi(), "Wrong phi" ); #endif + + // main and post loops have explicitly created zero trip guard + bool needs_guard = !cl->is_main_loop() && !cl->is_post_loop(); + if (needs_guard) { + // Check for an obvious zero trip guard. + Node* inctrl = cl->in(LoopNode::EntryControl); + if (inctrl->Opcode() == Op_IfTrue) { + // The test should look like just the backedge of a CountedLoop + Node* iff = inctrl->in(0); + if (iff->is_If()) { + Node* bol = iff->in(1); + if (bol->is_Bool() && bol->as_Bool()->_test._test == cl->loopexit()->test_trip()) { + Node* cmp = bol->in(1); + if (cmp->is_Cmp() && cmp->in(1) == cl->init_trip() && cmp->in(2) == cl->limit()) { + needs_guard = false; + } + } + } + } + } + +#ifndef PRODUCT + if (PrintOpto) { + tty->print("Removing empty loop with%s zero trip guard", needs_guard ? "out" : ""); + this->dump_head(); + } else if (TraceLoopOpts) { + tty->print("Empty with%s zero trip guard ", needs_guard ? "out" : ""); + this->dump_head(); + } +#endif + + if (needs_guard) { + // Peel the loop to ensure there's a zero trip guard + Node_List old_new; + phase->do_peeling(this, old_new); + } + // Replace the phi at loop head with the final value of the last // iteration. Then the CountedLoopEnd will collapse (backedge never // taken) and all loop-invariant uses of the exit values will be correct. @@ -1720,7 +1822,7 @@ //------------------------------iteration_split-------------------------------- bool IdealLoopTree::iteration_split( PhaseIdealLoop *phase, Node_List &old_new ) { // Recursively iteration split nested loops - if( _child && !_child->iteration_split( phase, old_new )) + if (_child && !_child->iteration_split(phase, old_new)) return false; // Clean out prior deadwood @@ -1729,21 +1831,20 @@ // Look for loop-exit tests with my 50/50 guesses from the Parsing stage. // Replace with a 1-in-10 exit guess. - if( _parent /*not the root loop*/ && + if (_parent /*not the root loop*/ && !_irreducible && // Also ignore the occasional dead backedge - !tail()->is_top() ) { + !tail()->is_top()) { adjust_loop_exit_prob(phase); } - // Gate unrolling, RCE and peeling efforts. - if( !_child && // If not an inner loop, do not split + if (!_child && // If not an inner loop, do not split !_irreducible && _allow_optimizations && - !tail()->is_top() ) { // Also ignore the occasional dead backedge + !tail()->is_top()) { // Also ignore the occasional dead backedge if (!_has_call) { - if (!iteration_split_impl( phase, old_new )) { + if (!iteration_split_impl(phase, old_new)) { return false; } } else if (policy_unswitching(phase)) { @@ -1752,16 +1853,17 @@ } // Minor offset re-organization to remove loop-fallout uses of - // trip counter. - if( _head->is_CountedLoop() ) phase->reorg_offsets( this ); - if( _next && !_next->iteration_split( phase, old_new )) + // trip counter when there was no major reshaping. + phase->reorg_offsets(this); + + if (_next && !_next->iteration_split(phase, old_new)) return false; return true; } //-------------------------------is_uncommon_trap_proj---------------------------- // Return true if proj is the form of "proj->[region->..]call_uct" -bool PhaseIdealLoop::is_uncommon_trap_proj(ProjNode* proj, bool must_reason_predicate) { +bool PhaseIdealLoop::is_uncommon_trap_proj(ProjNode* proj, Deoptimization::DeoptReason reason) { int path_limit = 10; assert(proj, "invalid argument"); Node* out = proj; @@ -1772,8 +1874,8 @@ if (out->is_CallStaticJava()) { int req = out->as_CallStaticJava()->uncommon_trap_request(); if (req != 0) { - Deoptimization::DeoptReason reason = Deoptimization::trap_request_reason(req); - if (!must_reason_predicate || reason == Deoptimization::Reason_predicate){ + Deoptimization::DeoptReason trap_reason = Deoptimization::trap_request_reason(req); + if (trap_reason == reason || reason == Deoptimization::Reason_none) { return true; } } @@ -1790,15 +1892,15 @@ // other_proj->[region->..]call_uct" // // "must_reason_predicate" means the uct reason must be Reason_predicate -bool PhaseIdealLoop::is_uncommon_trap_if_pattern(ProjNode *proj, bool must_reason_predicate) { +bool PhaseIdealLoop::is_uncommon_trap_if_pattern(ProjNode *proj, Deoptimization::DeoptReason reason) { Node *in0 = proj->in(0); if (!in0->is_If()) return false; // Variation of a dead If node. if (in0->outcnt() < 2) return false; IfNode* iff = in0->as_If(); - // we need "If(Conv2B(Opaque1(...)))" pattern for must_reason_predicate - if (must_reason_predicate) { + // 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; @@ -1806,7 +1908,19 @@ } ProjNode* other_proj = iff->proj_out(1-proj->_con)->as_Proj(); - return is_uncommon_trap_proj(other_proj, must_reason_predicate); + return is_uncommon_trap_proj(other_proj, reason); +} + +//-------------------------------register_control------------------------- +void PhaseIdealLoop::register_control(Node* n, IdealLoopTree *loop, Node* pred) { + assert(n->is_CFG(), "must be control node"); + _igvn.register_new_node_with_optimizer(n); + loop->_body.push(n); + set_loop(n, loop); + // When called from beautify_loops() idom is not constructed yet. + if (_idom != NULL) { + set_idom(n, pred, dom_depth(pred)); + } } //------------------------------create_new_if_for_predicate------------------------ @@ -1843,8 +1957,10 @@ // // 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. -ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj) { - assert(is_uncommon_trap_if_pattern(cont_proj, true), "must be a uct if pattern!"); +// This code is also used to clone predicates to clonned loops. +ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry, + Deoptimization::DeoptReason reason) { + assert(is_uncommon_trap_if_pattern(cont_proj, reason), "must be a uct if pattern!"); IfNode* iff = cont_proj->in(0)->as_If(); ProjNode *uncommon_proj = iff->proj_out(1 - cont_proj->_con); @@ -1854,57 +1970,84 @@ if (!rgn->is_Region()) { // create a region to guard the call assert(rgn->is_Call(), "must be call uct"); CallNode* call = rgn->as_Call(); + IdealLoopTree* loop = get_loop(call); rgn = new (C, 1) RegionNode(1); - _igvn.set_type(rgn, rgn->bottom_type()); rgn->add_req(uncommon_proj); - set_idom(rgn, idom(uncommon_proj), dom_depth(uncommon_proj)+1); + register_control(rgn, loop, uncommon_proj); _igvn.hash_delete(call); call->set_req(0, rgn); + // When called from beautify_loops() idom is not constructed yet. + if (_idom != NULL) { + set_idom(call, rgn, dom_depth(rgn)); + } } + Node* entry = iff->in(0); + if (new_entry != NULL) { + // Clonning the predicate to new location. + entry = new_entry; + } // Create new_iff - uint iffdd = dom_depth(iff); - IdealLoopTree* lp = get_loop(iff); - IfNode *new_iff = new (C, 2) IfNode(iff->in(0), NULL, iff->_prob, iff->_fcnt); - register_node(new_iff, lp, idom(iff), iffdd); + IdealLoopTree* lp = get_loop(entry); + IfNode *new_iff = new (C, 2) IfNode(entry, NULL, iff->_prob, iff->_fcnt); + register_control(new_iff, lp, entry); Node *if_cont = new (C, 1) IfTrueNode(new_iff); Node *if_uct = new (C, 1) IfFalseNode(new_iff); if (cont_proj->is_IfFalse()) { // Swap Node* tmp = if_uct; if_uct = if_cont; if_cont = tmp; } - register_node(if_cont, lp, new_iff, iffdd); - register_node(if_uct, get_loop(rgn), new_iff, iffdd); - - // if_cont to iff - _igvn.hash_delete(iff); - iff->set_req(0, if_cont); - set_idom(iff, if_cont, dom_depth(iff)); + register_control(if_cont, lp, new_iff); + register_control(if_uct, get_loop(rgn), new_iff); // if_uct to rgn _igvn.hash_delete(rgn); rgn->add_req(if_uct); - Node* ridom = idom(rgn); - Node* nrdom = dom_lca(ridom, new_iff); - set_idom(rgn, nrdom, dom_depth(rgn)); - + // When called from beautify_loops() idom is not constructed yet. + if (_idom != NULL) { + Node* ridom = idom(rgn); + Node* nrdom = dom_lca(ridom, new_iff); + set_idom(rgn, nrdom, dom_depth(rgn)); + } // rgn must have no phis assert(!rgn->as_Region()->has_phi(), "region must have no phis"); + if (new_entry == NULL) { + // Attach if_cont to iff + _igvn.hash_delete(iff); + iff->set_req(0, if_cont); + if (_idom != NULL) { + set_idom(iff, if_cont, dom_depth(iff)); + } + } return if_cont->as_Proj(); } -//------------------------------find_predicate_insertion_point-------------------------- +//--------------------------find_predicate_insertion_point------------------- // Find a good location to insert a predicate -ProjNode* PhaseIdealLoop::find_predicate_insertion_point(Node* start_c) { - if (start_c == C->root() || !start_c->is_Proj()) +ProjNode* PhaseIdealLoop::find_predicate_insertion_point(Node* start_c, Deoptimization::DeoptReason reason) { + if (start_c == NULL || !start_c->is_Proj()) return NULL; - if (is_uncommon_trap_if_pattern(start_c->as_Proj(), true/*Reason_Predicate*/)) { + if (is_uncommon_trap_if_pattern(start_c->as_Proj(), reason)) { return start_c->as_Proj(); } return NULL; } +//--------------------------find_predicate------------------------------------ +// Find a predicate +Node* PhaseIdealLoop::find_predicate(Node* entry) { + Node* predicate = NULL; + if (UseLoopPredicate) { + predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate); + if (predicate != NULL) { // right pattern that can be used by loop predication + assert(entry->in(0)->in(1)->in(1)->Opcode()==Op_Opaque1, "must be"); + return entry; + } + } + return NULL; +} + //------------------------------Invariance----------------------------------- // Helper class for loop_predication_impl to compute invariance on the fly and // clone invariants. @@ -2151,6 +2294,11 @@ return false; } + if (loop->_head->unique_ctrl_out()->Opcode() == Op_NeverBranch) { + // do nothing for infinite loops + return false; + } + CountedLoopNode *cl = NULL; if (loop->_head->is_CountedLoop()) { cl = loop->_head->as_CountedLoop(); @@ -2158,40 +2306,22 @@ if (!cl->is_normal_loop()) return false; } - // Too many traps seen? - bool tmt = C->too_many_traps(C->method(), 0, Deoptimization::Reason_predicate); - int tc = C->trap_count(Deoptimization::Reason_predicate); - if (tmt || tc > 0) { - if (TraceLoopPredicate) { - tty->print_cr("too many predicate traps: %d", tc); - C->method()->print(); // which method has too many predicate traps - tty->print_cr(""); - } - return false; - } - LoopNode *lpn = loop->_head->as_Loop(); Node* entry = lpn->in(LoopNode::EntryControl); - ProjNode *predicate_proj = find_predicate_insertion_point(entry); - if (!predicate_proj){ + ProjNode *predicate_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate); + if (!predicate_proj) { #ifndef PRODUCT if (TraceLoopPredicate) { tty->print("missing predicate:"); loop->dump_head(); + lpn->dump(1); } #endif return false; } - ConNode* zero = _igvn.intcon(0); set_ctrl(zero, C->root()); - Node *cond_false = new (C, 2) Conv2BNode(zero); - register_new_node(cond_false, C->root()); - ConNode* one = _igvn.intcon(1); - set_ctrl(one, C->root()); - Node *cond_true = new (C, 2) Conv2BNode(one); - register_new_node(cond_true, C->root()); ResourceArea *area = Thread::current()->resource_area(); Invariance invar(area, loop); @@ -2218,7 +2348,7 @@ ProjNode* proj = if_proj_list.pop()->as_Proj(); IfNode* iff = proj->in(0)->as_If(); - if (!is_uncommon_trap_if_pattern(proj)) { + if (!is_uncommon_trap_if_pattern(proj, Deoptimization::Reason_none)) { if (loop->is_loop_exit(iff)) { // stop processing the remaining projs in the list because the execution of them // depends on the condition of "iff" (iff->in(1)). @@ -2242,7 +2372,8 @@ BoolNode* bol = test->as_Bool(); if (invar.is_invariant(bol)) { // Invariant test - new_predicate_proj = create_new_if_for_predicate(predicate_proj); + new_predicate_proj = create_new_if_for_predicate(predicate_proj, NULL, + Deoptimization::Reason_predicate); Node* ctrl = new_predicate_proj->in(0)->as_If()->in(0); BoolNode* new_predicate_bol = invar.clone(bol, ctrl)->as_Bool(); @@ -2256,8 +2387,15 @@ IfNode* new_predicate_iff = new_predicate_proj->in(0)->as_If(); _igvn.hash_delete(new_predicate_iff); new_predicate_iff->set_req(1, new_predicate_bol); - if (TraceLoopPredicate) tty->print_cr("invariant if%s: %d", negated ? " negated" : "", new_predicate_iff->_idx); - +#ifndef PRODUCT + if (TraceLoopPredicate) { + tty->print("Predicate invariant if%s: %d ", negated ? " negated" : "", new_predicate_iff->_idx); + loop->dump_head(); + } else if (TraceLoopOpts) { + tty->print("Predicate IC "); + loop->dump_head(); + } +#endif } else if (cl != NULL && loop->is_range_check_if(iff, this, invar)) { assert(proj->_con == predicate_proj->_con, "must match"); @@ -2281,8 +2419,8 @@ // lower_bound test will dominate the upper bound test and all // cloned or created nodes will use the lower bound test as // their declared control. - ProjNode* lower_bound_proj = create_new_if_for_predicate(predicate_proj); - ProjNode* upper_bound_proj = create_new_if_for_predicate(predicate_proj); + ProjNode* lower_bound_proj = create_new_if_for_predicate(predicate_proj, NULL, Deoptimization::Reason_predicate); + ProjNode* upper_bound_proj = create_new_if_for_predicate(predicate_proj, NULL, Deoptimization::Reason_predicate); assert(upper_bound_proj->in(0)->as_If()->in(0) == lower_bound_proj, "should dominate"); Node *ctrl = lower_bound_proj->in(0)->as_If()->in(0); @@ -2311,41 +2449,24 @@ // Fall through into rest of the clean up code which will move // any dependent nodes onto the upper bound test. new_predicate_proj = upper_bound_proj; + +#ifndef PRODUCT + if (TraceLoopOpts && !TraceLoopPredicate) { + tty->print("Predicate RC "); + loop->dump_head(); + } +#endif } else { - // The other proj of the "iff" is a uncommon trap projection, and we can assume - // the other proj will not be executed ("executed" means uct raised). + // Loop variant check (for example, range check in non-counted loop) + // with uncommon trap. continue; } - + assert(new_predicate_proj != NULL, "sanity"); // Success - attach condition (new_predicate_bol) to predicate if invar.map_ctrl(proj, new_predicate_proj); // so that invariance test can be appropriate - // Eliminate the old if in the loop body - _igvn.hash_delete(iff); - iff->set_req(1, proj->is_IfFalse() ? cond_false : cond_true); - - Node* ctrl = new_predicate_proj; // new control - ProjNode* dp = proj; // old control - assert(get_loop(dp) == loop, "guaranteed at the time of collecting proj"); - // Find nodes (depends only on the test) off the surviving projection; - // move them outside the loop with the control of proj_clone - for (DUIterator_Fast imax, i = dp->fast_outs(imax); i < imax; i++) { - Node* cd = dp->fast_out(i); // Control-dependent node - if (cd->depends_only_on_test()) { - assert(cd->in(0) == dp, ""); - _igvn.hash_delete(cd); - cd->set_req(0, ctrl); // ctrl, not NULL - set_early_ctrl(cd); - _igvn._worklist.push(cd); - IdealLoopTree *new_loop = get_loop(get_ctrl(cd)); - if (new_loop != loop) { - if (!loop->_child) loop->_body.yank(cd); - if (!new_loop->_child ) new_loop->_body.push(cd); - } - --i; - --imax; - } - } + // Eliminate the old If in the loop body + dominated_by( new_predicate_proj, iff, proj->_con != new_predicate_proj->_con ); hoisted = true; C->set_major_progress();
--- a/src/share/vm/opto/loopUnswitch.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/loopUnswitch.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -110,6 +110,13 @@ IfNode* unswitch_iff = find_unswitching_candidate((const IdealLoopTree *)loop); assert(unswitch_iff != NULL, "should be at least one"); +#ifndef PRODUCT + if (TraceLoopOpts) { + tty->print("Unswitch %d ", head->unswitch_count()+1); + loop->dump_head(); + } +#endif + // Need to revert back to normal loop if (head->is_CountedLoop() && !head->as_CountedLoop()->is_normal_loop()) { head->as_CountedLoop()->set_normal_loop();
--- a/src/share/vm/opto/loopnode.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/loopnode.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -56,12 +56,32 @@ // Dump special per-node info #ifndef PRODUCT void LoopNode::dump_spec(outputStream *st) const { - if( is_inner_loop () ) st->print( "inner " ); - if( is_partial_peel_loop () ) st->print( "partial_peel " ); - if( partial_peel_has_failed () ) st->print( "partial_peel_failed " ); + if (is_inner_loop()) st->print( "inner " ); + if (is_partial_peel_loop()) st->print( "partial_peel " ); + if (partial_peel_has_failed()) st->print( "partial_peel_failed " ); } #endif +//------------------------------is_valid_counted_loop------------------------- +bool LoopNode::is_valid_counted_loop() const { + if (is_CountedLoop()) { + CountedLoopNode* l = as_CountedLoop(); + CountedLoopEndNode* le = l->loopexit(); + if (le != NULL && + le->proj_out(1 /* true */) == l->in(LoopNode::LoopBackControl)) { + Node* phi = l->phi(); + Node* exit = le->proj_out(0 /* false */); + if (exit != NULL && exit->Opcode() == Op_IfFalse && + phi != NULL && phi->is_Phi() && + phi->in(LoopNode::LoopBackControl) == l->incr() && + le->loopnode() == l && le->stride_is_con()) { + return true; + } + } + } + return false; +} + //------------------------------get_early_ctrl--------------------------------- // Compute earliest legal control Node *PhaseIdealLoop::get_early_ctrl( Node *n ) { @@ -142,43 +162,44 @@ } //------------------------------is_counted_loop-------------------------------- -Node *PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) { +bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) { PhaseGVN *gvn = &_igvn; // Counted loop head must be a good RegionNode with only 3 not NULL // control input edges: Self, Entry, LoopBack. - if ( x->in(LoopNode::Self) == NULL || x->req() != 3 ) - return NULL; + if (x->in(LoopNode::Self) == NULL || x->req() != 3) + return false; Node *init_control = x->in(LoopNode::EntryControl); Node *back_control = x->in(LoopNode::LoopBackControl); - if( init_control == NULL || back_control == NULL ) // Partially dead - return NULL; + if (init_control == NULL || back_control == NULL) // Partially dead + return false; // Must also check for TOP when looking for a dead loop - if( init_control->is_top() || back_control->is_top() ) - return NULL; + if (init_control->is_top() || back_control->is_top()) + return false; // Allow funny placement of Safepoint - if( back_control->Opcode() == Op_SafePoint ) + if (back_control->Opcode() == Op_SafePoint) back_control = back_control->in(TypeFunc::Control); // Controlling test for loop Node *iftrue = back_control; uint iftrue_op = iftrue->Opcode(); - if( iftrue_op != Op_IfTrue && - iftrue_op != Op_IfFalse ) + if (iftrue_op != Op_IfTrue && + iftrue_op != Op_IfFalse) // I have a weird back-control. Probably the loop-exit test is in // the middle of the loop and I am looking at some trailing control-flow // merge point. To fix this I would have to partially peel the loop. - return NULL; // Obscure back-control + return false; // Obscure back-control // Get boolean guarding loop-back test Node *iff = iftrue->in(0); - if( get_loop(iff) != loop || !iff->in(1)->is_Bool() ) return NULL; + if (get_loop(iff) != loop || !iff->in(1)->is_Bool()) + return false; BoolNode *test = iff->in(1)->as_Bool(); BoolTest::mask bt = test->_test._test; float cl_prob = iff->as_If()->_prob; - if( iftrue_op == Op_IfFalse ) { + if (iftrue_op == Op_IfFalse) { bt = BoolTest(bt).negate(); cl_prob = 1.0 - cl_prob; } @@ -186,7 +207,7 @@ Node *cmp = test->in(1); int cmp_op = cmp->Opcode(); if( cmp_op != Op_CmpI ) - return NULL; // Avoid pointer & float compares + return false; // Avoid pointer & float compares // Find the trip-counter increment & limit. Limit must be loop invariant. Node *incr = cmp->in(1); @@ -196,55 +217,64 @@ // need 'loop()' test to tell if limit is loop invariant // --------- - if( !is_member( loop, get_ctrl(incr) ) ) { // Swapped trip counter and limit? - Node *tmp = incr; // Then reverse order into the CmpI + if (!is_member(loop, get_ctrl(incr))) { // Swapped trip counter and limit? + Node *tmp = incr; // Then reverse order into the CmpI incr = limit; limit = tmp; bt = BoolTest(bt).commute(); // And commute the exit test } - if( is_member( loop, get_ctrl(limit) ) ) // Limit must loop-invariant - return NULL; + if (is_member(loop, get_ctrl(limit))) // Limit must be loop-invariant + return false; + if (!is_member(loop, get_ctrl(incr))) // Trip counter must be loop-variant + return false; + Node* phi_incr = NULL; // Trip-counter increment must be commutative & associative. - uint incr_op = incr->Opcode(); - if( incr_op == Op_Phi && incr->req() == 3 ) { - incr = incr->in(2); // Assume incr is on backedge of Phi - incr_op = incr->Opcode(); + if (incr->is_Phi()) { + if (incr->as_Phi()->region() != x || incr->req() != 3) + return false; // Not simple trip counter expression + phi_incr = incr; + incr = phi_incr->in(LoopNode::LoopBackControl); // Assume incr is on backedge of Phi + if (!is_member(loop, get_ctrl(incr))) // Trip counter must be loop-variant + return false; } + Node* trunc1 = NULL; Node* trunc2 = NULL; const TypeInt* iv_trunc_t = NULL; if (!(incr = CountedLoopNode::match_incr_with_optional_truncation(incr, &trunc1, &trunc2, &iv_trunc_t))) { - return NULL; // Funny increment opcode + return false; // Funny increment opcode } + assert(incr->Opcode() == Op_AddI, "wrong increment code"); // Get merge point Node *xphi = incr->in(1); Node *stride = incr->in(2); - if( !stride->is_Con() ) { // Oops, swap these - if( !xphi->is_Con() ) // Is the other guy a constant? - return NULL; // Nope, unknown stride, bail out + if (!stride->is_Con()) { // Oops, swap these + if (!xphi->is_Con()) // Is the other guy a constant? + return false; // Nope, unknown stride, bail out Node *tmp = xphi; // 'incr' is commutative, so ok to swap xphi = stride; stride = tmp; } - //if( loop(xphi) != l) return NULL;// Merge point is in inner loop?? - if( !xphi->is_Phi() ) return NULL; // Too much math on the trip counter + // Stride must be constant + int stride_con = stride->get_int(); + assert(stride_con != 0, "missed some peephole opt"); + + if (!xphi->is_Phi()) + return false; // Too much math on the trip counter + if (phi_incr != NULL && phi_incr != xphi) + return false; PhiNode *phi = xphi->as_Phi(); - // Stride must be constant - const Type *stride_t = stride->bottom_type(); - int stride_con = stride_t->is_int()->get_con(); - assert( stride_con, "missed some peephole opt" ); - // Phi must be of loop header; backedge must wrap to increment - if( phi->region() != x ) return NULL; - if( trunc1 == NULL && phi->in(LoopNode::LoopBackControl) != incr || - trunc1 != NULL && phi->in(LoopNode::LoopBackControl) != trunc1 ) { - return NULL; + if (phi->region() != x) + return false; + if (trunc1 == NULL && phi->in(LoopNode::LoopBackControl) != incr || + trunc1 != NULL && phi->in(LoopNode::LoopBackControl) != trunc1) { + return false; } Node *init_trip = phi->in(LoopNode::EntryControl); - //if (!init_trip->is_Con()) return NULL; // avoid rolling over MAXINT/MININT // If iv trunc type is smaller than int, check for possible wrap. if (!TypeInt::INT->higher_equal(iv_trunc_t)) { @@ -267,12 +297,12 @@ if (stride_con > 0) { if (iv_trunc_t->_hi - phi_ft->_hi < stride_con || iv_trunc_t->_lo > phi_ft->_lo) { - return NULL; // truncation may occur + return false; // truncation may occur } } else if (stride_con < 0) { if (iv_trunc_t->_lo - phi_ft->_lo > stride_con || iv_trunc_t->_hi < phi_ft->_hi) { - return NULL; // truncation may occur + return false; // truncation may occur } } // No possibility of wrap so truncation can be discarded @@ -281,35 +311,45 @@ assert(trunc1 == NULL && trunc2 == NULL, "no truncation for int"); } + // If the condition is inverted and we will be rolling + // through MININT to MAXINT, then bail out. + if (bt == BoolTest::eq || // Bail out, but this loop trips at most twice! + // Odd stride + bt == BoolTest::ne && stride_con != 1 && stride_con != -1 || + // Count down loop rolls through MAXINT + (bt == BoolTest::le || bt == BoolTest::lt) && stride_con < 0 || + // Count up loop rolls through MININT + (bt == BoolTest::ge || bt == BoolTest::gt) && stride_con > 0 ) { + return false; // Bail out + } + + const TypeInt* init_t = gvn->type(init_trip)->is_int(); + const TypeInt* limit_t = gvn->type(limit)->is_int(); + + if (stride_con > 0) { + long init_p = (long)init_t->_lo + stride_con; + if (init_p > (long)max_jint || init_p > (long)limit_t->_hi) + return false; // cyclic loop or this loop trips only once + } else { + long init_p = (long)init_t->_hi + stride_con; + if (init_p < (long)min_jint || init_p < (long)limit_t->_lo) + return false; // cyclic loop or this loop trips only once + } + // ================================================= // ---- SUCCESS! Found A Trip-Counted Loop! ----- // - // Canonicalize the condition on the test. If we can exactly determine - // the trip-counter exit value, then set limit to that value and use - // a '!=' test. Otherwise use condition '<' for count-up loops and - // '>' for count-down loops. If the condition is inverted and we will - // be rolling through MININT to MAXINT, then bail out. - + assert(x->Opcode() == Op_Loop, "regular loops only"); C->print_method("Before CountedLoop", 3); - // Check for SafePoint on backedge and remove - Node *sfpt = x->in(LoopNode::LoopBackControl); - if( sfpt->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt)) { - lazy_replace( sfpt, iftrue ); - loop->_tail = iftrue; - } - - // If compare points to incr, we are ok. Otherwise the compare // can directly point to the phi; in this case adjust the compare so that // it points to the incr by adjusting the limit. - if( cmp->in(1) == phi || cmp->in(2) == phi ) + if (cmp->in(1) == phi || cmp->in(2) == phi) limit = gvn->transform(new (C, 3) AddINode(limit,stride)); // trip-count for +-tive stride should be: (limit - init_trip + stride - 1)/stride. // Final value for iterator should be: trip_count * stride + init_trip. - const Type *limit_t = limit->bottom_type(); - const Type *init_t = init_trip->bottom_type(); Node *one_p = gvn->intcon( 1); Node *one_m = gvn->intcon(-1); @@ -317,15 +357,15 @@ Node *hook = new (C, 6) Node(6); switch( bt ) { case BoolTest::eq: - return NULL; // Bail out, but this loop trips at most twice! + ShouldNotReachHere(); case BoolTest::ne: // Ahh, the case we desire - if( stride_con == 1 ) + if (stride_con == 1) trip_count = gvn->transform(new (C, 3) SubINode(limit,init_trip)); - else if( stride_con == -1 ) + else if (stride_con == -1) trip_count = gvn->transform(new (C, 3) SubINode(init_trip,limit)); else - return NULL; // Odd stride; must prove we hit limit exactly - set_subtree_ctrl( trip_count ); + ShouldNotReachHere(); + set_subtree_ctrl(trip_count); //_loop.map(trip_count->_idx,loop(limit)); break; case BoolTest::le: // Maybe convert to '<' case @@ -338,7 +378,8 @@ //_loop.map(limit->_idx,limit_loop); // Fall into next case case BoolTest::lt: { // Maybe convert to '!=' case - if( stride_con < 0 ) return NULL; // Count down loop rolls through MAXINT + if (stride_con < 0) // Count down loop rolls through MAXINT + ShouldNotReachHere(); Node *range = gvn->transform(new (C, 3) SubINode(limit,init_trip)); set_subtree_ctrl( range ); hook->init_req(0, range); @@ -367,7 +408,8 @@ //_loop.map(limit->_idx,limit_loop); // Fall into next case case BoolTest::gt: { // Maybe convert to '!=' case - if( stride_con > 0 ) return NULL; // count up loop rolls through MININT + if (stride_con > 0) // count up loop rolls through MININT + ShouldNotReachHere(); Node *range = gvn->transform(new (C, 3) SubINode(limit,init_trip)); set_subtree_ctrl( range ); hook->init_req(0, range); @@ -385,7 +427,7 @@ hook->init_req(3, trip_count); break; } - } + } // switch( bt ) Node *span = gvn->transform(new (C, 3) MulINode(trip_count,stride)); set_subtree_ctrl( span ); @@ -394,83 +436,82 @@ limit = gvn->transform(new (C, 3) AddINode(span,init_trip)); set_subtree_ctrl( limit ); + // Check for SafePoint on backedge and remove + Node *sfpt = x->in(LoopNode::LoopBackControl); + if (sfpt->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt)) { + lazy_replace( sfpt, iftrue ); + loop->_tail = iftrue; + } + // Build a canonical trip test. // Clone code, as old values may be in use. + Node* nphi = PhiNode::make(x, init_trip, TypeInt::INT); + nphi = _igvn.register_new_node_with_optimizer(nphi); + set_ctrl(nphi, get_ctrl(phi)); + incr = incr->clone(); - incr->set_req(1,phi); + incr->set_req(1,nphi); incr->set_req(2,stride); incr = _igvn.register_new_node_with_optimizer(incr); set_early_ctrl( incr ); - _igvn.hash_delete(phi); - phi->set_req_X( LoopNode::LoopBackControl, incr, &_igvn ); - // If phi type is more restrictive than Int, raise to - // Int to prevent (almost) infinite recursion in igvn - // which can only handle integer types for constants or minint..maxint. - if (!TypeInt::INT->higher_equal(phi->bottom_type())) { - Node* nphi = PhiNode::make(phi->in(0), phi->in(LoopNode::EntryControl), TypeInt::INT); - nphi->set_req(LoopNode::LoopBackControl, phi->in(LoopNode::LoopBackControl)); - nphi = _igvn.register_new_node_with_optimizer(nphi); - set_ctrl(nphi, get_ctrl(phi)); - _igvn.replace_node(phi, nphi); - phi = nphi->as_Phi(); - } + nphi->set_req(LoopNode::LoopBackControl, incr); + _igvn.replace_node(phi, nphi); + phi = nphi->as_Phi(); + cmp = cmp->clone(); cmp->set_req(1,incr); cmp->set_req(2,limit); cmp = _igvn.register_new_node_with_optimizer(cmp); set_ctrl(cmp, iff->in(0)); - Node *tmp = test->clone(); - assert( tmp->is_Bool(), "" ); - test = (BoolNode*)tmp; - (*(BoolTest*)&test->_test)._test = bt; //BoolTest::ne; + test = test->clone()->as_Bool(); + (*(BoolTest*)&test->_test)._test = bt; test->set_req(1,cmp); _igvn.register_new_node_with_optimizer(test); set_ctrl(test, iff->in(0)); - // If the exit test is dead, STOP! - if( test == NULL ) return NULL; - _igvn.hash_delete(iff); - iff->set_req_X( 1, test, &_igvn ); // Replace the old IfNode with a new LoopEndNode - Node *lex = _igvn.register_new_node_with_optimizer(new (C, 2) CountedLoopEndNode( iff->in(0), iff->in(1), cl_prob, iff->as_If()->_fcnt )); + Node *lex = _igvn.register_new_node_with_optimizer(new (C, 2) CountedLoopEndNode( iff->in(0), test, cl_prob, iff->as_If()->_fcnt )); IfNode *le = lex->as_If(); uint dd = dom_depth(iff); set_idom(le, le->in(0), dd); // Update dominance for loop exit set_loop(le, loop); // Get the loop-exit control - Node *if_f = iff->as_If()->proj_out(!(iftrue_op == Op_IfTrue)); + Node *iffalse = iff->as_If()->proj_out(!(iftrue_op == Op_IfTrue)); // Need to swap loop-exit and loop-back control? - if( iftrue_op == Op_IfFalse ) { + if (iftrue_op == Op_IfFalse) { Node *ift2=_igvn.register_new_node_with_optimizer(new (C, 1) IfTrueNode (le)); Node *iff2=_igvn.register_new_node_with_optimizer(new (C, 1) IfFalseNode(le)); loop->_tail = back_control = ift2; set_loop(ift2, loop); - set_loop(iff2, get_loop(if_f)); + set_loop(iff2, get_loop(iffalse)); // Lazy update of 'get_ctrl' mechanism. - lazy_replace_proj( if_f , iff2 ); - lazy_replace_proj( iftrue, ift2 ); + lazy_replace_proj( iffalse, iff2 ); + lazy_replace_proj( iftrue, ift2 ); // Swap names - if_f = iff2; - iftrue = ift2; + iffalse = iff2; + iftrue = ift2; } else { - _igvn.hash_delete(if_f ); + _igvn.hash_delete(iffalse); _igvn.hash_delete(iftrue); - if_f ->set_req_X( 0, le, &_igvn ); - iftrue->set_req_X( 0, le, &_igvn ); + iffalse->set_req_X( 0, le, &_igvn ); + iftrue ->set_req_X( 0, le, &_igvn ); } - set_idom(iftrue, le, dd+1); - set_idom(if_f, le, dd+1); + set_idom(iftrue, le, dd+1); + set_idom(iffalse, le, dd+1); + assert(iff->outcnt() == 0, "should be dead now"); + lazy_replace( iff, le ); // fix 'get_ctrl' // Now setup a new CountedLoopNode to replace the existing LoopNode CountedLoopNode *l = new (C, 3) CountedLoopNode(init_control, back_control); + l->set_unswitch_count(x->as_Loop()->unswitch_count()); // Preserve // The following assert is approximately true, and defines the intention // of can_be_counted_loop. It fails, however, because phase->type // is not yet initialized for this loop and its parts. @@ -491,10 +532,14 @@ // Free up intermediate goo _igvn.remove_dead_node(hook); +#ifdef ASSERT + assert(l->is_valid_counted_loop(), "counted loop shape is messed up"); + assert(l == loop->_head && l->phi() == phi && l->loopexit() == lex, "" ); +#endif + C->print_method("After CountedLoop", 3); - // Return trip counter - return trip_count; + return true; } @@ -1019,8 +1064,6 @@ // Cache parts in locals for easy PhaseIterGVN &igvn = phase->_igvn; - phase->C->print_method("Before beautify loops", 3); - igvn.hash_delete(_head); // Yank from hash before hacking edges // Check for multiple fall-in paths. Peel off a landing pad if need be. @@ -1256,17 +1299,98 @@ return true; } +//---------------------------replace_parallel_iv------------------------------- +// Replace parallel induction variable (parallel to trip counter) +void PhaseIdealLoop::replace_parallel_iv(IdealLoopTree *loop) { + assert(loop->_head->is_CountedLoop(), ""); + CountedLoopNode *cl = loop->_head->as_CountedLoop(); + Node *incr = cl->incr(); + if (incr == NULL) + return; // Dead loop? + Node *init = cl->init_trip(); + Node *phi = cl->phi(); + // protect against stride not being a constant + if (!cl->stride_is_con()) + return; + int stride_con = cl->stride_con(); + + PhaseGVN *gvn = &_igvn; + + // Visit all children, looking for Phis + for (DUIterator i = cl->outs(); cl->has_out(i); i++) { + Node *out = cl->out(i); + // Look for other phis (secondary IVs). Skip dead ones + if (!out->is_Phi() || out == phi || !has_node(out)) + continue; + PhiNode* phi2 = out->as_Phi(); + Node *incr2 = phi2->in( LoopNode::LoopBackControl ); + // Look for induction variables of the form: X += constant + if (phi2->region() != loop->_head || + incr2->req() != 3 || + incr2->in(1) != phi2 || + incr2 == incr || + incr2->Opcode() != Op_AddI || + !incr2->in(2)->is_Con()) + continue; + + // Check for parallel induction variable (parallel to trip counter) + // via an affine function. In particular, count-down loops with + // count-up array indices are common. We only RCE references off + // the trip-counter, so we need to convert all these to trip-counter + // expressions. + Node *init2 = phi2->in( LoopNode::EntryControl ); + int stride_con2 = incr2->in(2)->get_int(); + + // The general case here gets a little tricky. We want to find the + // GCD of all possible parallel IV's and make a new IV using this + // GCD for the loop. Then all possible IVs are simple multiples of + // the GCD. In practice, this will cover very few extra loops. + // Instead we require 'stride_con2' to be a multiple of 'stride_con', + // where +/-1 is the common case, but other integer multiples are + // also easy to handle. + int ratio_con = stride_con2/stride_con; + + if ((ratio_con * stride_con) == stride_con2) { // Check for exact + // Convert to using the trip counter. The parallel induction + // variable differs from the trip counter by a loop-invariant + // amount, the difference between their respective initial values. + // It is scaled by the 'ratio_con'. + // Perform local Ideal transformation since in most cases ratio == 1. + Node* ratio = _igvn.intcon(ratio_con); + set_ctrl(ratio, C->root()); + Node* hook = new (C, 3) Node(3); + Node* ratio_init = gvn->transform(new (C, 3) MulINode(init, ratio)); + hook->init_req(0, ratio_init); + Node* diff = gvn->transform(new (C, 3) SubINode(init2, ratio_init)); + hook->init_req(1, diff); + Node* ratio_idx = gvn->transform(new (C, 3) MulINode(phi, ratio)); + hook->init_req(2, ratio_idx); + Node* add = gvn->transform(new (C, 3) AddINode(ratio_idx, diff)); + set_subtree_ctrl(add); + _igvn.replace_node( phi2, add ); + // Free up intermediate goo + _igvn.remove_dead_node(hook); + // Sometimes an induction variable is unused + if (add->outcnt() == 0) { + _igvn.remove_dead_node(add); + } + --i; // deleted this phi; rescan starting with next position + continue; + } + } +} + //------------------------------counted_loop----------------------------------- // Convert to counted loops where possible void IdealLoopTree::counted_loop( PhaseIdealLoop *phase ) { // For grins, set the inner-loop flag here - if( !_child ) { - if( _head->is_Loop() ) _head->as_Loop()->set_inner_loop(); + if (!_child) { + if (_head->is_Loop()) _head->as_Loop()->set_inner_loop(); } - if( _head->is_CountedLoop() || - phase->is_counted_loop( _head, this ) ) { + if (_head->is_CountedLoop() || + phase->is_counted_loop(_head, this)) { _has_sfpt = 1; // Indicate we do not need a safepoint here // Look for a safepoint to remove @@ -1275,79 +1399,9 @@ phase->is_deleteable_safept(n)) phase->lazy_replace(n,n->in(TypeFunc::Control)); - CountedLoopNode *cl = _head->as_CountedLoop(); - Node *incr = cl->incr(); - if( !incr ) return; // Dead loop? - Node *init = cl->init_trip(); - Node *phi = cl->phi(); - // protect against stride not being a constant - if( !cl->stride_is_con() ) return; - int stride_con = cl->stride_con(); - // Look for induction variables - - // Visit all children, looking for Phis - for (DUIterator i = cl->outs(); cl->has_out(i); i++) { - Node *out = cl->out(i); - // Look for other phis (secondary IVs). Skip dead ones - if (!out->is_Phi() || out == phi || !phase->has_node(out)) continue; - PhiNode* phi2 = out->as_Phi(); - Node *incr2 = phi2->in( LoopNode::LoopBackControl ); - // Look for induction variables of the form: X += constant - if( phi2->region() != _head || - incr2->req() != 3 || - incr2->in(1) != phi2 || - incr2 == incr || - incr2->Opcode() != Op_AddI || - !incr2->in(2)->is_Con() ) - continue; - - // Check for parallel induction variable (parallel to trip counter) - // via an affine function. In particular, count-down loops with - // count-up array indices are common. We only RCE references off - // the trip-counter, so we need to convert all these to trip-counter - // expressions. - Node *init2 = phi2->in( LoopNode::EntryControl ); - int stride_con2 = incr2->in(2)->get_int(); + phase->replace_parallel_iv(this); - // The general case here gets a little tricky. We want to find the - // GCD of all possible parallel IV's and make a new IV using this - // GCD for the loop. Then all possible IVs are simple multiples of - // the GCD. In practice, this will cover very few extra loops. - // Instead we require 'stride_con2' to be a multiple of 'stride_con', - // where +/-1 is the common case, but other integer multiples are - // also easy to handle. - int ratio_con = stride_con2/stride_con; - - if( ratio_con * stride_con == stride_con2 ) { // Check for exact - // Convert to using the trip counter. The parallel induction - // variable differs from the trip counter by a loop-invariant - // amount, the difference between their respective initial values. - // It is scaled by the 'ratio_con'. - Compile* C = phase->C; - Node* ratio = phase->_igvn.intcon(ratio_con); - phase->set_ctrl(ratio, C->root()); - Node* ratio_init = new (C, 3) MulINode(init, ratio); - phase->_igvn.register_new_node_with_optimizer(ratio_init, init); - phase->set_early_ctrl(ratio_init); - Node* diff = new (C, 3) SubINode(init2, ratio_init); - phase->_igvn.register_new_node_with_optimizer(diff, init2); - phase->set_early_ctrl(diff); - Node* ratio_idx = new (C, 3) MulINode(phi, ratio); - phase->_igvn.register_new_node_with_optimizer(ratio_idx, phi); - phase->set_ctrl(ratio_idx, cl); - Node* add = new (C, 3) AddINode(ratio_idx, diff); - phase->_igvn.register_new_node_with_optimizer(add); - phase->set_ctrl(add, cl); - phase->_igvn.replace_node( phi2, add ); - // Sometimes an induction variable is unused - if (add->outcnt() == 0) { - phase->_igvn.remove_dead_node(add); - } - --i; // deleted this phi; rescan starting with next position - continue; - } - } } else if (_parent != NULL && !_irreducible) { // Not a counted loop. // Look for a safepoint on the idom-path to remove, preserving the first one @@ -1366,24 +1420,31 @@ } // Recursively - if( _child ) _child->counted_loop( phase ); - if( _next ) _next ->counted_loop( phase ); + if (_child) _child->counted_loop( phase ); + if (_next) _next ->counted_loop( phase ); } #ifndef PRODUCT //------------------------------dump_head-------------------------------------- // Dump 1 liner for loop header info void IdealLoopTree::dump_head( ) const { - for( uint i=0; i<_nest; i++ ) + for (uint i=0; i<_nest; i++) tty->print(" "); tty->print("Loop: N%d/N%d ",_head->_idx,_tail->_idx); - if( _irreducible ) tty->print(" IRREDUCIBLE"); - if( _head->is_CountedLoop() ) { + if (_irreducible) tty->print(" IRREDUCIBLE"); + if (UseLoopPredicate) { + Node* entry = _head->in(LoopNode::EntryControl); + if (entry != NULL && entry->is_Proj() && + PhaseIdealLoop::is_uncommon_trap_if_pattern(entry->as_Proj(), Deoptimization::Reason_predicate)) { + tty->print(" predicated"); + } + } + if (_head->is_CountedLoop()) { CountedLoopNode *cl = _head->as_CountedLoop(); tty->print(" counted"); - if( cl->is_pre_loop () ) tty->print(" pre" ); - if( cl->is_main_loop() ) tty->print(" main"); - if( cl->is_post_loop() ) tty->print(" post"); + if (cl->is_pre_loop ()) tty->print(" pre" ); + if (cl->is_main_loop()) tty->print(" main"); + if (cl->is_post_loop()) tty->print(" post"); } tty->cr(); } @@ -1392,8 +1453,8 @@ // Dump loops by loop tree void IdealLoopTree::dump( ) const { dump_head(); - if( _child ) _child->dump(); - if( _next ) _next ->dump(); + if (_child) _child->dump(); + if (_next) _next ->dump(); } #endif @@ -1439,19 +1500,19 @@ } // self (only loops that we can apply loop predication may use their predicates) - if (loop->_head->is_Loop() && - !loop->_irreducible && + if (loop->_head->is_Loop() && + !loop->_irreducible && !loop->tail()->is_top()) { - LoopNode *lpn = loop->_head->as_Loop(); + LoopNode* lpn = loop->_head->as_Loop(); Node* entry = lpn->in(LoopNode::EntryControl); - ProjNode *predicate_proj = find_predicate_insertion_point(entry); + Node* predicate_proj = find_predicate(entry); if (predicate_proj != NULL ) { // right pattern that can be used by loop predication - assert(entry->in(0)->in(1)->in(1)->Opcode()==Op_Opaque1, "must be"); + assert(entry->in(0)->in(1)->in(1)->Opcode() == Op_Opaque1, "must be"); useful_predicates.push(entry->in(0)->in(1)->in(1)); // good one } } - if ( loop->_next ) { // sibling + if (loop->_next) { // sibling collect_potentially_useful_predicates(loop->_next, useful_predicates); } } @@ -1459,7 +1520,8 @@ //------------------------eliminate_useless_predicates----------------------------- // Eliminate all inserted predicates if they could not be used by loop predication. void PhaseIdealLoop::eliminate_useless_predicates() { - if (C->predicate_count() == 0) return; // no predicate left + if (C->predicate_count() == 0) + return; // no predicate left Unique_Node_List useful_predicates; // to store useful predicates if (C->has_loops()) { @@ -1483,6 +1545,7 @@ ResourceMark rm; int old_progress = C->major_progress(); + uint orig_worklist_size = _igvn._worklist.size(); // Reset major-progress flag for the driver's heuristics C->clear_major_progress(); @@ -1546,6 +1609,7 @@ // Split shared headers and insert loop landing pads. // Do not bother doing this on the Root loop of course. if( !_verify_me && !_verify_only && _ltree_root->_child ) { + C->print_method("Before beautify loops", 3); if( _ltree_root->_child->beautify_loops( this ) ) { // Re-build loop tree! _ltree_root->_child = NULL; @@ -1630,7 +1694,7 @@ for (int i = 0; i < old_progress; i++) C->set_major_progress(); assert(C->unique() == unique, "verification mode made Nodes? ? ?"); - assert(_igvn._worklist.size() == 0, "shouldn't push anything"); + assert(_igvn._worklist.size() == orig_worklist_size, "shouldn't push anything"); return; } @@ -1647,12 +1711,15 @@ #ifndef PRODUCT C->verify_graph_edges(); - if( _verify_me ) { // Nested verify pass? + if (_verify_me) { // Nested verify pass? // Check to see if the verify mode is broken assert(C->unique() == unique, "non-optimize mode made Nodes? ? ?"); return; } - if( VerifyLoopOptimizations ) verify(); + if(VerifyLoopOptimizations) verify(); + if(TraceLoopOpts && C->has_loops()) { + _ltree_root->dump(); + } #endif if (ReassociateInvariants) {
--- a/src/share/vm/opto/loopnode.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/loopnode.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -93,6 +93,7 @@ in(1) != NULL && phase->type(in(1)) != Type::TOP && in(2) != NULL && phase->type(in(2)) != Type::TOP; } + bool is_valid_counted_loop() const; #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; #endif @@ -101,9 +102,8 @@ //------------------------------Counted Loops---------------------------------- // Counted loops are all trip-counted loops, with exactly 1 trip-counter exit // path (and maybe some other exit paths). The trip-counter exit is always -// last in the loop. The trip-counter does not have to stride by a constant, -// but it does have to stride by a loop-invariant amount; the exit value is -// also loop invariant. +// last in the loop. The trip-counter have to stride by a constant; +// the exit value is also loop invariant. // CountedLoopNodes and CountedLoopEndNodes come in matched pairs. The // CountedLoopNode has the incoming loop control and the loop-back-control @@ -112,7 +112,7 @@ // CountedLoopNode if there is control flow in the loop), the post-increment // trip-counter value, and the limit. The trip-counter value is always of // the form (Op old-trip-counter stride). The old-trip-counter is produced -// by a Phi connected to the CountedLoopNode. The stride is loop invariant. +// by a Phi connected to the CountedLoopNode. The stride is constant. // The Op is any commutable opcode, including Add, Mul, Xor. The // CountedLoopEndNode also takes in the loop-invariant limit value. @@ -696,6 +696,9 @@ // Is safept not required by an outer loop? bool is_deleteable_safept(Node* sfpt); + // Replace parallel induction variable (parallel to trip counter) + void replace_parallel_iv(IdealLoopTree *loop); + // Perform verification that the graph is valid. PhaseIdealLoop( PhaseIterGVN &igvn) : PhaseTransform(Ideal_Loop), @@ -751,7 +754,7 @@ // Per-Node transform virtual Node *transform( Node *a_node ) { return 0; } - Node *is_counted_loop( Node *x, IdealLoopTree *loop ); + bool is_counted_loop( Node *x, IdealLoopTree *loop ); // Return a post-walked LoopNode IdealLoopTree *get_loop( Node *n ) const { @@ -815,16 +818,22 @@ bool is_scaled_iv_plus_offset(Node* exp, Node* iv, int* p_scale, Node** p_offset, int depth = 0); // Return true if proj is for "proj->[region->..]call_uct" - bool is_uncommon_trap_proj(ProjNode* proj, bool must_reason_predicate = false); + // Return true if proj is for "proj->[region->..]call_uct" + static bool is_uncommon_trap_proj(ProjNode* proj, Deoptimization::DeoptReason reason); // Return true for "if(test)-> proj -> ... // | // V // other_proj->[region->..]call_uct" - bool is_uncommon_trap_if_pattern(ProjNode* proj, bool must_reason_predicate = false); + static bool is_uncommon_trap_if_pattern(ProjNode* proj, Deoptimization::DeoptReason reason); // Create a new if above the uncommon_trap_if_pattern for the predicate to be promoted - ProjNode* create_new_if_for_predicate(ProjNode* cont_proj); - // Find a good location to insert a predicate - ProjNode* find_predicate_insertion_point(Node* start_c); + ProjNode* create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry, + Deoptimization::DeoptReason reason); + void register_control(Node* n, IdealLoopTree *loop, Node* pred); + + // Find a good location to insert a predicate + static ProjNode* find_predicate_insertion_point(Node* start_c, Deoptimization::DeoptReason reason); + // Find a predicate + static Node* find_predicate(Node* entry); // Construct a range check for a predicate if BoolNode* rc_predicate(Node* ctrl, int scale, Node* offset, @@ -936,7 +945,7 @@ Node *has_local_phi_input( Node *n ); // Mark an IfNode as being dominated by a prior test, // without actually altering the CFG (and hence IDOM info). - void dominated_by( Node *prevdom, Node *iff ); + void dominated_by( Node *prevdom, Node *iff, bool flip = false ); // Split Node 'n' through merge point Node *split_thru_region( Node *n, Node *region );
--- a/src/share/vm/opto/loopopts.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/loopopts.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -42,13 +42,13 @@ return NULL; } int wins = 0; - assert( !n->is_CFG(), "" ); - assert( region->is_Region(), "" ); + assert(!n->is_CFG(), ""); + assert(region->is_Region(), ""); const Type* type = n->bottom_type(); const TypeOopPtr *t_oop = _igvn.type(n)->isa_oopptr(); Node *phi; - if( t_oop != NULL && t_oop->is_known_instance_field() ) { + if (t_oop != NULL && t_oop->is_known_instance_field()) { int iid = t_oop->instance_id(); int index = C->get_alias_index(t_oop); int offset = t_oop->offset(); @@ -57,20 +57,20 @@ phi = PhiNode::make_blank(region, n); } uint old_unique = C->unique(); - for( uint i = 1; i < region->req(); i++ ) { + for (uint i = 1; i < region->req(); i++) { Node *x; Node* the_clone = NULL; - if( region->in(i) == C->top() ) { + if (region->in(i) == C->top()) { x = C->top(); // Dead path? Use a dead data op } else { x = n->clone(); // Else clone up the data op the_clone = x; // Remember for possible deletion. // Alter data node to use pre-phi inputs - if( n->in(0) == region ) + if (n->in(0) == region) x->set_req( 0, region->in(i) ); - for( uint j = 1; j < n->req(); j++ ) { + for (uint j = 1; j < n->req(); j++) { Node *in = n->in(j); - if( in->is_Phi() && in->in(0) == region ) + if (in->is_Phi() && in->in(0) == region) x->set_req( j, in->in(i) ); // Use pre-Phi input for the clone } } @@ -85,7 +85,7 @@ // happen if the singleton occurs on loop entry, as the elimination of // the PhiNode may cause the resulting node to migrate back to a previous // loop iteration. - if( singleton && t == Type::TOP ) { + if (singleton && t == Type::TOP) { // Is_Loop() == false does not confirm the absence of a loop (e.g., an // irreducible loop may not be indicated by an affirmative is_Loop()); // therefore, the only top we can split thru a phi is on a backedge of @@ -93,7 +93,7 @@ singleton &= region->is_Loop() && (i != LoopNode::EntryControl); } - if( singleton ) { + if (singleton) { wins++; x = ((PhaseGVN&)_igvn).makecon(t); } else { @@ -108,12 +108,12 @@ // igvn->type(x) is set to x->Value() already. x->raise_bottom_type(t); Node *y = x->Identity(&_igvn); - if( y != x ) { + if (y != x) { wins++; x = y; } else { y = _igvn.hash_find(x); - if( y ) { + if (y) { wins++; x = y; } else { @@ -129,7 +129,7 @@ phi->set_req( i, x ); } // Too few wins? - if( wins <= policy ) { + if (wins <= policy) { _igvn.remove_dead_node(phi); return NULL; } @@ -137,7 +137,7 @@ // Record Phi register_new_node( phi, region ); - for( uint i2 = 1; i2 < phi->req(); i2++ ) { + for (uint i2 = 1; i2 < phi->req(); i2++) { Node *x = phi->in(i2); // If we commoned up the cloned 'x' with another existing Node, // the existing Node picks up a new use. We need to make the @@ -145,24 +145,44 @@ Node *old_ctrl; IdealLoopTree *old_loop; + if (x->is_Con()) { + // Constant's control is always root. + set_ctrl(x, C->root()); + continue; + } // The occasional new node - if( x->_idx >= old_unique ) { // Found a new, unplaced node? - old_ctrl = x->is_Con() ? C->root() : NULL; - old_loop = NULL; // Not in any prior loop + if (x->_idx >= old_unique) { // Found a new, unplaced node? + old_ctrl = NULL; + old_loop = NULL; // Not in any prior loop } else { - old_ctrl = x->is_Con() ? C->root() : get_ctrl(x); + old_ctrl = get_ctrl(x); old_loop = get_loop(old_ctrl); // Get prior loop } // New late point must dominate new use - Node *new_ctrl = dom_lca( old_ctrl, region->in(i2) ); + Node *new_ctrl = dom_lca(old_ctrl, region->in(i2)); + if (new_ctrl == old_ctrl) // Nothing is changed + continue; + + IdealLoopTree *new_loop = get_loop(new_ctrl); + + // Don't move x into a loop if its uses are + // outside of loop. Otherwise x will be cloned + // for each use outside of this loop. + IdealLoopTree *use_loop = get_loop(region); + if (!new_loop->is_member(use_loop) && + (old_loop == NULL || !new_loop->is_member(old_loop))) { + // Take early control, later control will be recalculated + // during next iteration of loop optimizations. + new_ctrl = get_early_ctrl(x); + new_loop = get_loop(new_ctrl); + } // Set new location set_ctrl(x, new_ctrl); - IdealLoopTree *new_loop = get_loop( new_ctrl ); // If changing loop bodies, see if we need to collect into new body - if( old_loop != new_loop ) { - if( old_loop && !old_loop->_child ) + if (old_loop != new_loop) { + if (old_loop && !old_loop->_child) old_loop->_body.yank(x); - if( !new_loop->_child ) + if (!new_loop->_child) new_loop->_body.push(x); // Collect body info } } @@ -174,9 +194,9 @@ // Replace the dominated test with an obvious true or false. Place it on the // IGVN worklist for later cleanup. Move control-dependent data Nodes on the // live path up to the dominating control. -void PhaseIdealLoop::dominated_by( Node *prevdom, Node *iff ) { +void PhaseIdealLoop::dominated_by( Node *prevdom, Node *iff, bool flip ) { #ifndef PRODUCT - if( VerifyLoopOptimizations && PrintOpto ) tty->print_cr("dominating test"); + if (VerifyLoopOptimizations && PrintOpto) tty->print_cr("dominating test"); #endif @@ -185,6 +205,12 @@ assert( iff->Opcode() == Op_If || iff->Opcode() == Op_CountedLoopEnd, "Check this code when new subtype is added"); int pop = prevdom->Opcode(); assert( pop == Op_IfFalse || pop == Op_IfTrue, "" ); + if (flip) { + if (pop == Op_IfTrue) + pop = Op_IfFalse; + else + pop = Op_IfTrue; + } // 'con' is set to true or false to kill the dominated test. Node *con = _igvn.makecon(pop == Op_IfTrue ? TypeInt::ONE : TypeInt::ZERO); set_ctrl(con, C->root()); // Constant gets a new use @@ -197,7 +223,7 @@ // I can assume this path reaches an infinite loop. In this case it's not // important to optimize the data Nodes - either the whole compilation will // be tossed or this path (and all data Nodes) will go dead. - if( iff->outcnt() != 2 ) return; + if (iff->outcnt() != 2) return; // Make control-dependent data Nodes on the live path (path that will remain // once the dominated IF is removed) become control-dependent on the @@ -207,16 +233,16 @@ for (DUIterator_Fast imax, i = dp->fast_outs(imax); i < imax; i++) { Node* cd = dp->fast_out(i); // Control-dependent node - if( cd->depends_only_on_test() ) { - assert( cd->in(0) == dp, "" ); - _igvn.hash_delete( cd ); + if (cd->depends_only_on_test()) { + assert(cd->in(0) == dp, ""); + _igvn.hash_delete(cd); cd->set_req(0, prevdom); - set_early_ctrl( cd ); + set_early_ctrl(cd); _igvn._worklist.push(cd); IdealLoopTree *new_loop = get_loop(get_ctrl(cd)); - if( old_loop != new_loop ) { - if( !old_loop->_child ) old_loop->_body.yank(cd); - if( !new_loop->_child ) new_loop->_body.push(cd); + if (old_loop != new_loop) { + if (!old_loop->_child) old_loop->_body.yank(cd); + if (!new_loop->_child) new_loop->_body.push(cd); } --i; --imax; @@ -2338,6 +2364,11 @@ } #if !defined(PRODUCT) + if (TraceLoopOpts) { + tty->print("PartialPeel "); + loop->dump_head(); + } + if (TracePartialPeeling) { tty->print_cr("before partial peel one iteration"); Node_List wl; @@ -2481,6 +2512,7 @@ // Create new loop head for new phis and to hang // the nodes being moved (sinked) from the peel region. LoopNode* new_head = new (C, 3) LoopNode(last_peel, last_peel); + new_head->set_unswitch_count(head->unswitch_count()); // Preserve _igvn.register_new_node_with_optimizer(new_head); assert(first_not_peeled->in(0) == last_peel, "last_peel <- first_not_peeled"); first_not_peeled->set_req(0, new_head); @@ -2651,24 +2683,23 @@ // prevent loop-fallout uses of the pre-incremented trip counter (which are // then alive with the post-incremented trip counter forcing an extra // register move) -void PhaseIdealLoop::reorg_offsets( IdealLoopTree *loop ) { +void PhaseIdealLoop::reorg_offsets(IdealLoopTree *loop) { + // Perform it only for canonical counted loops. + // Loop's shape could be messed up by iteration_split_impl. + if (!loop->_head->is_CountedLoop()) + return; + if (!loop->_head->as_Loop()->is_valid_counted_loop()) + return; CountedLoopNode *cl = loop->_head->as_CountedLoop(); CountedLoopEndNode *cle = cl->loopexit(); - if( !cle ) return; // The occasional dead loop - // Find loop exit control Node *exit = cle->proj_out(false); - assert( exit->Opcode() == Op_IfFalse, "" ); + Node *phi = cl->phi(); // Check for the special case of folks using the pre-incremented // trip-counter on the fall-out path (forces the pre-incremented // and post-incremented trip counter to be live at the same time). // Fix this by adjusting to use the post-increment trip counter. - Node *phi = cl->phi(); - if( !phi ) return; // Dead infinite loop - - // Shape messed up, probably by iteration_split_impl - if (phi->in(LoopNode::LoopBackControl) != cl->incr()) return; bool progress = true; while (progress) { @@ -2677,21 +2708,19 @@ Node* use = phi->fast_out(i); // User of trip-counter if (!has_ctrl(use)) continue; Node *u_ctrl = get_ctrl(use); - if( use->is_Phi() ) { + if (use->is_Phi()) { u_ctrl = NULL; - for( uint j = 1; j < use->req(); j++ ) - if( use->in(j) == phi ) - u_ctrl = dom_lca( u_ctrl, use->in(0)->in(j) ); + for (uint j = 1; j < use->req(); j++) + if (use->in(j) == phi) + u_ctrl = dom_lca(u_ctrl, use->in(0)->in(j)); } IdealLoopTree *u_loop = get_loop(u_ctrl); // Look for loop-invariant use - if( u_loop == loop ) continue; - if( loop->is_member( u_loop ) ) continue; + if (u_loop == loop) continue; + if (loop->is_member(u_loop)) continue; // Check that use is live out the bottom. Assuming the trip-counter // update is right at the bottom, uses of of the loop middle are ok. - if( dom_lca( exit, u_ctrl ) != exit ) continue; - // protect against stride not being a constant - if( !cle->stride_is_con() ) continue; + if (dom_lca(exit, u_ctrl) != exit) continue; // Hit! Refactor use to use the post-incremented tripcounter. // Compute a post-increment tripcounter. Node *opaq = new (C, 2) Opaque2Node( C, cle->incr() ); @@ -2702,9 +2731,10 @@ register_new_node( post, u_ctrl ); _igvn.hash_delete(use); _igvn._worklist.push(use); - for( uint j = 1; j < use->req(); j++ ) - if( use->in(j) == phi ) + for (uint j = 1; j < use->req(); j++) { + if (use->in(j) == phi) use->set_req(j, post); + } // Since DU info changed, rerun loop progress = true; break;
--- a/src/share/vm/opto/matcher.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/matcher.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -49,6 +49,9 @@ #ifdef TARGET_ARCH_MODEL_zero # include "adfiles/ad_zero.hpp" #endif +#ifdef TARGET_ARCH_MODEL_arm +# include "adfiles/ad_arm.hpp" +#endif OptoReg::Name OptoReg::c_frame_pointer;
--- a/src/share/vm/opto/matcher.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/matcher.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -427,6 +427,11 @@ // Do ints take an entire long register or just half? static const bool int_in_long; + // Do the processor's shift instructions only use the low 5/6 bits + // of the count for 32/64 bit ints? If not we need to do the masking + // ourselves. + static const bool need_masked_shift_count; + // This routine is run whenever a graph fails to match. // If it returns, the compiler should bailout to interpreter without error. // In non-product mode, SoftMatchFailure is false to detect non-canonical
--- a/src/share/vm/opto/memnode.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/memnode.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1573,9 +1573,9 @@ return TypeInt::make(constant.as_int()); } else if (constant.basic_type() == T_ARRAY) { if (adr->bottom_type()->is_ptr_to_narrowoop()) { - return TypeNarrowOop::make_from_constant(constant.as_object()); + return TypeNarrowOop::make_from_constant(constant.as_object(), true); } else { - return TypeOopPtr::make_from_constant(constant.as_object()); + return TypeOopPtr::make_from_constant(constant.as_object(), true); } } } @@ -2617,54 +2617,28 @@ } //============================================================================= -// Do we match on this edge? No memory edges -uint StrCompNode::match_edge(uint idx) const { - return idx == 2 || idx == 3; // StrComp (Binary str1 cnt1) (Binary str2 cnt2) -} - -//------------------------------Ideal------------------------------------------ -// Return a node which is more "ideal" than the current node. Strip out -// control copies -Node *StrCompNode::Ideal(PhaseGVN *phase, bool can_reshape){ - return remove_dead_region(phase, can_reshape) ? this : NULL; -} - -//============================================================================= -// Do we match on this edge? No memory edges -uint StrEqualsNode::match_edge(uint idx) const { - return idx == 2 || idx == 3; // StrEquals (Binary str1 str2) cnt +// Do not match memory edge. +uint StrIntrinsicNode::match_edge(uint idx) const { + return idx == 2 || idx == 3; } //------------------------------Ideal------------------------------------------ // Return a node which is more "ideal" than the current node. Strip out // control copies -Node *StrEqualsNode::Ideal(PhaseGVN *phase, bool can_reshape){ - return remove_dead_region(phase, can_reshape) ? this : NULL; -} - -//============================================================================= -// Do we match on this edge? No memory edges -uint StrIndexOfNode::match_edge(uint idx) const { - return idx == 2 || idx == 3; // StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2) -} - -//------------------------------Ideal------------------------------------------ -// Return a node which is more "ideal" than the current node. Strip out -// control copies -Node *StrIndexOfNode::Ideal(PhaseGVN *phase, bool can_reshape){ - return remove_dead_region(phase, can_reshape) ? this : NULL; -} - -//============================================================================= -// Do we match on this edge? No memory edges -uint AryEqNode::match_edge(uint idx) const { - return idx == 2 || idx == 3; // StrEquals ary1 ary2 -} -//------------------------------Ideal------------------------------------------ -// Return a node which is more "ideal" than the current node. Strip out -// control copies -Node *AryEqNode::Ideal(PhaseGVN *phase, bool can_reshape){ - return remove_dead_region(phase, can_reshape) ? this : NULL; +Node *StrIntrinsicNode::Ideal(PhaseGVN *phase, bool can_reshape) { + if (remove_dead_region(phase, can_reshape)) return this; + + if (can_reshape) { + Node* mem = phase->transform(in(MemNode::Memory)); + // If transformed to a MergeMem, get the desired slice + uint alias_idx = phase->C->get_alias_index(adr_type()); + mem = mem->is_MergeMem() ? mem->as_MergeMem()->memory_at(alias_idx) : mem; + if (mem != in(MemNode::Memory)) { + set_req(MemNode::Memory, mem); + return this; + } + } + return NULL; } //=============================================================================
--- a/src/share/vm/opto/memnode.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/memnode.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -776,67 +776,69 @@ static bool step_through(Node** np, uint instance_id, PhaseTransform* phase); }; -//------------------------------StrComp------------------------------------- -class StrCompNode: public Node { +//------------------------------StrIntrinsic------------------------------- +// Base class for Ideal nodes used in String instrinsic code. +class StrIntrinsicNode: public Node { public: - StrCompNode(Node* control, Node* char_array_mem, - Node* s1, Node* c1, - Node* s2, Node* c2): Node(control, char_array_mem, - s1, c1, - s2, c2) {}; - virtual int Opcode() const; + StrIntrinsicNode(Node* control, Node* char_array_mem, + Node* s1, Node* c1, Node* s2, Node* c2): + Node(control, char_array_mem, s1, c1, s2, c2) { + } + + StrIntrinsicNode(Node* control, Node* char_array_mem, + Node* s1, Node* s2, Node* c): + Node(control, char_array_mem, s1, s2, c) { + } + + StrIntrinsicNode(Node* control, Node* char_array_mem, + Node* s1, Node* s2): + Node(control, char_array_mem, s1, s2) { + } + virtual bool depends_only_on_test() const { return false; } - virtual const Type* bottom_type() const { return TypeInt::INT; } virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; } virtual uint match_edge(uint idx) const; virtual uint ideal_reg() const { return Op_RegI; } virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); }; +//------------------------------StrComp------------------------------------- +class StrCompNode: public StrIntrinsicNode { +public: + StrCompNode(Node* control, Node* char_array_mem, + Node* s1, Node* c1, Node* s2, Node* c2): + StrIntrinsicNode(control, char_array_mem, s1, c1, s2, c2) {}; + virtual int Opcode() const; + virtual const Type* bottom_type() const { return TypeInt::INT; } +}; + //------------------------------StrEquals------------------------------------- -class StrEqualsNode: public Node { +class StrEqualsNode: public StrIntrinsicNode { public: StrEqualsNode(Node* control, Node* char_array_mem, - Node* s1, Node* s2, Node* c): Node(control, char_array_mem, - s1, s2, c) {}; + Node* s1, Node* s2, Node* c): + StrIntrinsicNode(control, char_array_mem, s1, s2, c) {}; virtual int Opcode() const; - virtual bool depends_only_on_test() const { return false; } virtual const Type* bottom_type() const { return TypeInt::BOOL; } - virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; } - virtual uint match_edge(uint idx) const; - virtual uint ideal_reg() const { return Op_RegI; } - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); }; //------------------------------StrIndexOf------------------------------------- -class StrIndexOfNode: public Node { +class StrIndexOfNode: public StrIntrinsicNode { public: StrIndexOfNode(Node* control, Node* char_array_mem, - Node* s1, Node* c1, - Node* s2, Node* c2): Node(control, char_array_mem, - s1, c1, - s2, c2) {}; + Node* s1, Node* c1, Node* s2, Node* c2): + StrIntrinsicNode(control, char_array_mem, s1, c1, s2, c2) {}; virtual int Opcode() const; - virtual bool depends_only_on_test() const { return false; } virtual const Type* bottom_type() const { return TypeInt::INT; } - virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; } - virtual uint match_edge(uint idx) const; - virtual uint ideal_reg() const { return Op_RegI; } - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); }; //------------------------------AryEq--------------------------------------- -class AryEqNode: public Node { +class AryEqNode: public StrIntrinsicNode { public: - AryEqNode(Node* control, Node* char_array_mem, - Node* s1, Node* s2): Node(control, char_array_mem, s1, s2) {}; + AryEqNode(Node* control, Node* char_array_mem, Node* s1, Node* s2): + StrIntrinsicNode(control, char_array_mem, s1, s2) {}; virtual int Opcode() const; - virtual bool depends_only_on_test() const { return false; } virtual const Type* bottom_type() const { return TypeInt::BOOL; } - virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; } - virtual uint match_edge(uint idx) const; - virtual uint ideal_reg() const { return Op_RegI; } - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); }; //------------------------------MemBar-----------------------------------------
--- a/src/share/vm/opto/node.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/node.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1373,12 +1373,12 @@ //------------------------------find------------------------------------------ // Find a neighbor of this Node with the given _idx // If idx is negative, find its absolute value, following both _in and _out. -static void find_recur( Node* &result, Node *n, int idx, bool only_ctrl, - VectorSet &old_space, VectorSet &new_space ) { +static void find_recur(Compile* C, Node* &result, Node *n, int idx, bool only_ctrl, + VectorSet* old_space, VectorSet* new_space ) { int node_idx = (idx >= 0) ? idx : -idx; if (NotANode(n)) return; // Gracefully handle NULL, -1, 0xabababab, etc. - // Contained in new_space or old_space? - VectorSet *v = Compile::current()->node_arena()->contains(n) ? &new_space : &old_space; + // Contained in new_space or old_space? Check old_arena first since it's mostly empty. + VectorSet *v = C->old_arena()->contains(n) ? old_space : new_space; if( v->test(n->_idx) ) return; if( (int)n->_idx == node_idx debug_only(|| n->debug_idx() == node_idx) ) { @@ -1390,19 +1390,23 @@ v->set(n->_idx); for( uint i=0; i<n->len(); i++ ) { if( only_ctrl && !(n->is_Region()) && (n->Opcode() != Op_Root) && (i != TypeFunc::Control) ) continue; - find_recur( result, n->in(i), idx, only_ctrl, old_space, new_space ); + find_recur(C, result, n->in(i), idx, only_ctrl, old_space, new_space ); } // Search along forward edges also: if (idx < 0 && !only_ctrl) { for( uint j=0; j<n->outcnt(); j++ ) { - find_recur( result, n->raw_out(j), idx, only_ctrl, old_space, new_space ); + find_recur(C, result, n->raw_out(j), idx, only_ctrl, old_space, new_space ); } } #ifdef ASSERT - // Search along debug_orig edges last: - for (Node* orig = n->debug_orig(); orig != NULL && n != orig; orig = orig->debug_orig()) { - if (NotANode(orig)) break; - find_recur( result, orig, idx, only_ctrl, old_space, new_space ); + // Search along debug_orig edges last, checking for cycles + Node* orig = n->debug_orig(); + if (orig != NULL) { + do { + if (NotANode(orig)) break; + find_recur(C, result, orig, idx, only_ctrl, old_space, new_space ); + orig = orig->debug_orig(); + } while (orig != NULL && orig != n->debug_orig()); } #endif //ASSERT } @@ -1417,7 +1421,7 @@ ResourceArea *area = Thread::current()->resource_area(); VectorSet old_space(area), new_space(area); Node* result = NULL; - find_recur( result, (Node*) this, idx, false, old_space, new_space ); + find_recur(Compile::current(), result, (Node*) this, idx, false, &old_space, &new_space ); return result; } @@ -1427,7 +1431,7 @@ ResourceArea *area = Thread::current()->resource_area(); VectorSet old_space(area), new_space(area); Node* result = NULL; - find_recur( result, (Node*) this, idx, true, old_space, new_space ); + find_recur(Compile::current(), result, (Node*) this, idx, true, &old_space, &new_space ); return result; } #endif
--- a/src/share/vm/opto/parse.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/parse.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -136,6 +136,7 @@ uint _count; // how many times executed? Currently only set by _goto's bool _is_parsed; // has this block been parsed yet? bool _is_handler; // is this block an exception handler? + bool _has_merged_backedge; // does this block have merged backedge? SafePointNode* _start_map; // all values flowing into this block MethodLivenessResult _live_locals; // lazily initialized liveness bitmap @@ -168,6 +169,18 @@ // True after any predecessor flows control into this block bool is_merged() const { return _start_map != NULL; } +#ifdef ASSERT + // True after backedge predecessor flows control into this block + bool has_merged_backedge() const { return _has_merged_backedge; } + void mark_merged_backedge(Block* pred) { + assert(is_SEL_head(), "should be loop head"); + if (pred != NULL && is_SEL_backedge(pred)) { + assert(is_parsed(), "block should be parsed before merging backedges"); + _has_merged_backedge = true; + } + } +#endif + // True when all non-exception predecessors have been parsed. bool is_ready() const { return preds_parsed() == pred_count(); } @@ -441,11 +454,6 @@ } } - // Return true if the parser should add a loop predicate - bool should_add_predicate(int target_bci); - // Insert a loop predicate into the graph - void add_predicate(); - // Note: Intrinsic generation routines may be found in library_call.cpp. // Helper function to setup Ideal Call nodes @@ -483,8 +491,8 @@ bool static_field_ok_in_clinit(ciField *field, ciMethod *method); // common code for actually performing the load or store - void do_get_xxx(const TypePtr* obj_type, Node* obj, ciField* field, bool is_field); - void do_put_xxx(const TypePtr* obj_type, Node* obj, ciField* field, bool is_field); + void do_get_xxx(Node* obj, ciField* field, bool is_field); + void do_put_xxx(Node* obj, ciField* field, bool is_field); // loading from a constant field or the constant pool // returns false if push failed (non-perm field constants only, not ldcs)
--- a/src/share/vm/opto/parse1.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/parse1.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -637,6 +637,25 @@ // (Note that dead locals do not get phis built, ever.) ensure_phis_everywhere(); + if (block->is_SEL_head() && + UseLoopPredicate) { + // Add predicate to single entry (not irreducible) loop head. + assert(!block->has_merged_backedge(), "only entry paths should be merged for now"); + // Need correct bci for predicate. + // It is fine to set it here since do_one_block() will set it anyway. + set_parse_bci(block->start()); + add_predicate(); + // Add new region for back branches. + int edges = block->pred_count() - block->preds_parsed() + 1; // +1 for original region + RegionNode *r = new (C, edges+1) RegionNode(edges+1); + _gvn.set_type(r, Type::CONTROL); + record_for_igvn(r); + r->init_req(edges, control()); + set_control(r); + // Add new phis. + ensure_phis_everywhere(); + } + // Leave behind an undisturbed copy of the map, for future merges. set_map(clone_map()); } @@ -1113,7 +1132,7 @@ _preds_parsed = 0; _count = 0; assert(pred_count() == 0 && preds_parsed() == 0, "sanity"); - assert(!(is_merged() || is_parsed() || is_handler()), "sanity"); + assert(!(is_merged() || is_parsed() || is_handler() || has_merged_backedge()), "sanity"); assert(_live_locals.size() == 0, "sanity"); // entry point has additional predecessor @@ -1350,10 +1369,6 @@ set_parse_bci(iter().cur_bci()); if (bci() == block()->limit()) { - // insert a predicate if it falls through to a loop head block - if (should_add_predicate(bci())){ - add_predicate(); - } // Do not walk into the next block until directed by do_all_blocks. merge(bci()); break; @@ -1498,17 +1513,29 @@ || target->is_handler() // These have unpredictable inputs. || target->is_loop_head() // Known multiple inputs || control()->is_Region()) { // We must hide this guy. + + int current_bci = bci(); + set_parse_bci(target->start()); // Set target bci + if (target->is_SEL_head()) { + DEBUG_ONLY( target->mark_merged_backedge(block()); ) + if (target->start() == 0) { + // Add loop predicate for the special case when + // there are backbranches to the method entry. + add_predicate(); + } + } // Add a Region to start the new basic block. Phis will be added // later lazily. int edges = target->pred_count(); if (edges < pnum) edges = pnum; // might be a new path! - Node *r = new (C, edges+1) RegionNode(edges+1); + RegionNode *r = new (C, edges+1) RegionNode(edges+1); gvn().set_type(r, Type::CONTROL); record_for_igvn(r); // zap all inputs to NULL for debugging (done in Node(uint) constructor) // for (int j = 1; j < edges+1; j++) { r->init_req(j, NULL); } r->init_req(pnum, control()); set_control(r); + set_parse_bci(current_bci); // Restore bci } // Convert the existing Parser mapping into a mapping at this bci. @@ -1517,7 +1544,11 @@ } else { // Prior mapping at this bci if (TraceOptoParse) { tty->print(" with previous state"); } - +#ifdef ASSERT + if (target->is_SEL_head()) { + target->mark_merged_backedge(block()); + } +#endif // We must not manufacture more phis if the target is already parsed. bool nophi = target->is_parsed(); @@ -2054,37 +2085,6 @@ } } -//------------------------------should_add_predicate-------------------------- -bool Parse::should_add_predicate(int target_bci) { - if (!UseLoopPredicate) return false; - Block* target = successor_for_bci(target_bci); - if (target != NULL && - target->is_loop_head() && - block()->rpo() < target->rpo()) { - return true; - } - return false; -} - -//------------------------------add_predicate--------------------------------- -void Parse::add_predicate() { - assert(UseLoopPredicate,"use only for loop predicate"); - Node *cont = _gvn.intcon(1); - Node* opq = _gvn.transform(new (C, 2) Opaque1Node(C, cont)); - Node *bol = _gvn.transform(new (C, 2) Conv2BNode(opq)); - IfNode* iff = create_and_map_if(control(), bol, PROB_MAX, COUNT_UNKNOWN); - Node* iffalse = _gvn.transform(new (C, 1) IfFalseNode(iff)); - C->add_predicate_opaq(opq); - { - PreserveJVMState pjvms(this); - set_control(iffalse); - uncommon_trap(Deoptimization::Reason_predicate, - Deoptimization::Action_maybe_recompile); - } - Node* iftrue = _gvn.transform(new (C, 1) IfTrueNode(iff)); - set_control(iftrue); -} - #ifndef PRODUCT //------------------------show_parse_info-------------------------------------- void Parse::show_parse_info() {
--- a/src/share/vm/opto/parse2.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/parse2.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -293,11 +293,6 @@ if (len < 1) { // If this is a backward branch, add safepoint maybe_add_safepoint(default_dest); - if (should_add_predicate(default_dest)){ - _sp += 1; // set original stack for use by uncommon_trap - add_predicate(); - _sp -= 1; - } merge(default_dest); return; } @@ -344,11 +339,6 @@ if (len < 1) { // If this is a backward branch, add safepoint maybe_add_safepoint(default_dest); - if (should_add_predicate(default_dest)){ - _sp += 1; // set original stack for use by uncommon_trap - add_predicate(); - _sp -= 1; - } merge(default_dest); return; } @@ -756,9 +746,6 @@ push(_gvn.makecon(ret_addr)); // Flow to the jsr. - if (should_add_predicate(jsr_bci)){ - add_predicate(); - } merge(jsr_bci); } @@ -1040,11 +1027,6 @@ profile_taken_branch(target_bci); adjust_map_after_if(btest, c, prob, branch_block, next_block); if (!stopped()) { - if (should_add_predicate(target_bci)){ // add a predicate if it branches to a loop - int nargs = repush_if_args(); // set original stack for uncommon_trap - add_predicate(); - _sp -= nargs; - } merge(target_bci); } } @@ -1168,11 +1150,6 @@ profile_taken_branch(target_bci); adjust_map_after_if(taken_btest, c, prob, branch_block, next_block); if (!stopped()) { - if (should_add_predicate(target_bci)){ // add a predicate if it branches to a loop - int nargs = repush_if_args(); // set original stack for the uncommon_trap - add_predicate(); - _sp -= nargs; - } merge(target_bci); } } @@ -2166,10 +2143,6 @@ // Update method data profile_taken_branch(target_bci); - // Add loop predicate if it goes to a loop - if (should_add_predicate(target_bci)){ - add_predicate(); - } // Merge the current control into the target basic block merge(target_bci);
--- a/src/share/vm/opto/parse3.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/parse3.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -112,29 +112,31 @@ // Compile-time detect of null-exception? if (stopped()) return; +#ifdef ASSERT const TypeInstPtr *tjp = TypeInstPtr::make(TypePtr::NotNull, iter().get_declared_field_holder()); assert(_gvn.type(obj)->higher_equal(tjp), "cast_up is no longer needed"); +#endif if (is_get) { --_sp; // pop receiver before getting - do_get_xxx(tjp, obj, field, is_field); + do_get_xxx(obj, field, is_field); } else { - do_put_xxx(tjp, obj, field, is_field); + do_put_xxx(obj, field, is_field); --_sp; // pop receiver after putting } } else { - const TypeKlassPtr* tkp = TypeKlassPtr::make(field_holder); - obj = _gvn.makecon(tkp); + const TypeInstPtr* tip = TypeInstPtr::make(field_holder->java_mirror()); + obj = _gvn.makecon(tip); if (is_get) { - do_get_xxx(tkp, obj, field, is_field); + do_get_xxx(obj, field, is_field); } else { - do_put_xxx(tkp, obj, field, is_field); + do_put_xxx(obj, field, is_field); } } } -void Parse::do_get_xxx(const TypePtr* obj_type, Node* obj, ciField* field, bool is_field) { +void Parse::do_get_xxx(Node* obj, ciField* field, bool is_field) { // Does this field have a constant value? If so, just push the value. if (field->is_constant()) { if (field->is_static()) { @@ -231,7 +233,7 @@ } } -void Parse::do_put_xxx(const TypePtr* obj_type, Node* obj, ciField* field, bool is_field) { +void Parse::do_put_xxx(Node* obj, ciField* field, bool is_field) { bool is_vol = field->is_volatile(); // If reference is volatile, prevent following memory ops from // floating down past the volatile write. Also prevents commoning
--- a/src/share/vm/opto/stringopts.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/stringopts.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -910,7 +910,7 @@ ciObject* con = field->constant_value().as_object(); // Do not "join" in the previous type; it doesn't add value, // and may yield a vacuous result if the field is of interface type. - type = TypeOopPtr::make_from_constant(con)->isa_oopptr(); + type = TypeOopPtr::make_from_constant(con, true)->isa_oopptr(); assert(type != NULL, "field singleton type must be consistent"); } else { type = TypeOopPtr::make_from_klass(field_klass->as_klass()); @@ -969,6 +969,10 @@ // for (int i=0; ; i++) // if (x <= sizeTable[i]) // return i+1; + + // Add loop predicate first. + kit.add_predicate(); + RegionNode *loop = new (C, 3) RegionNode(3); loop->init_req(1, kit.control()); kit.gvn().set_type(loop, Type::CONTROL); @@ -1086,6 +1090,9 @@ // } { + // Add loop predicate first. + kit.add_predicate(); + RegionNode *head = new (C, 3) RegionNode(3); head->init_req(1, kit.control()); kit.gvn().set_type(head, Type::CONTROL);
--- a/src/share/vm/opto/type.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/type.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -32,6 +32,7 @@ #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "oops/instanceKlass.hpp" +#include "oops/instanceMirrorKlass.hpp" #include "oops/klassKlass.hpp" #include "oops/objArrayKlass.hpp" #include "oops/typeArrayKlass.hpp" @@ -2241,43 +2242,49 @@ } else if (this->isa_aryptr()) { _is_ptr_to_narrowoop = (klass()->is_obj_array_klass() && _offset != arrayOopDesc::length_offset_in_bytes()); - } else if (klass() == ciEnv::current()->Class_klass() && - (_offset == java_lang_Class::klass_offset_in_bytes() || - _offset == java_lang_Class::array_klass_offset_in_bytes())) { - // Special hidden fields from the Class. - assert(this->isa_instptr(), "must be an instance ptr."); - _is_ptr_to_narrowoop = true; } else if (klass()->is_instance_klass()) { ciInstanceKlass* ik = klass()->as_instance_klass(); ciField* field = NULL; if (this->isa_klassptr()) { - // Perm objects don't use compressed references, except for - // static fields which are currently compressed. - field = ik->get_field_by_offset(_offset, true); - if (field != NULL) { - BasicType basic_elem_type = field->layout_type(); - _is_ptr_to_narrowoop = (basic_elem_type == T_OBJECT || - basic_elem_type == T_ARRAY); - } + // Perm objects don't use compressed references } else if (_offset == OffsetBot || _offset == OffsetTop) { // unsafe access _is_ptr_to_narrowoop = true; } else { // exclude unsafe ops assert(this->isa_instptr(), "must be an instance ptr."); - // Field which contains a compressed oop references. - field = ik->get_field_by_offset(_offset, false); - if (field != NULL) { + + if (klass() == ciEnv::current()->Class_klass() && + (_offset == java_lang_Class::klass_offset_in_bytes() || + _offset == java_lang_Class::array_klass_offset_in_bytes())) { + // Special hidden fields from the Class. + assert(this->isa_instptr(), "must be an instance ptr."); + _is_ptr_to_narrowoop = true; + } else if (klass() == ciEnv::current()->Class_klass() && + _offset >= instanceMirrorKlass::offset_of_static_fields()) { + // Static fields + assert(o != NULL, "must be constant"); + ciInstanceKlass* k = o->as_instance()->java_lang_Class_klass()->as_instance_klass(); + ciField* field = k->get_field_by_offset(_offset, true); + assert(field != NULL, "missing field"); BasicType basic_elem_type = field->layout_type(); _is_ptr_to_narrowoop = (basic_elem_type == T_OBJECT || basic_elem_type == T_ARRAY); - } else if (klass()->equals(ciEnv::current()->Object_klass())) { - // Compile::find_alias_type() cast exactness on all types to verify - // that it does not affect alias type. - _is_ptr_to_narrowoop = true; } else { - // Type for the copy start in LibraryCallKit::inline_native_clone(). - assert(!klass_is_exact(), "only non-exact klass"); - _is_ptr_to_narrowoop = true; + // Instance fields which contains a compressed oop references. + field = ik->get_field_by_offset(_offset, false); + if (field != NULL) { + BasicType basic_elem_type = field->layout_type(); + _is_ptr_to_narrowoop = (basic_elem_type == T_OBJECT || + basic_elem_type == T_ARRAY); + } else if (klass()->equals(ciEnv::current()->Object_klass())) { + // Compile::find_alias_type() cast exactness on all types to verify + // that it does not affect alias type. + _is_ptr_to_narrowoop = true; + } else { + // Type for the copy start in LibraryCallKit::inline_native_clone(). + assert(!klass_is_exact(), "only non-exact klass"); + _is_ptr_to_narrowoop = true; + } } } }
--- a/src/share/vm/opto/type.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/opto/type.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -988,8 +988,8 @@ static const TypeNarrowOop *make( const TypePtr* type); - static const TypeNarrowOop* make_from_constant(ciObject* con) { - return make(TypeOopPtr::make_from_constant(con)); + static const TypeNarrowOop* make_from_constant(ciObject* con, bool require_constant = false) { + return make(TypeOopPtr::make_from_constant(con, require_constant)); } // returns the equivalent ptr type for this compressed pointer
--- a/src/share/vm/prims/jni.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/prims/jni.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -1858,7 +1858,7 @@ // Static field. The fieldID a JNIid specifying the field holder and the offset within the klassOop. JNIid* id = jfieldIDWorkaround::from_static_jfieldID(fieldID); assert(id->is_static_field_id(), "invalid static field id"); - found = instanceKlass::cast(id->holder())->find_local_field_from_offset(id->offset(), true, &fd); + found = id->find_local_field(&fd); } else { // Non-static field. The fieldID is really the offset of the field within the instanceOop. int offset = jfieldIDWorkaround::from_instance_jfieldID(k, fieldID); @@ -1906,9 +1906,7 @@ JNIid* id = instanceKlass::cast(fd.field_holder())->jni_id_for(fd.offset()); debug_only(id->set_is_static_field_id();) - debug_only(int first_offset = instanceKlass::cast(fd.field_holder())->offset_of_static_fields();) - debug_only(int end_offset = first_offset + (instanceKlass::cast(fd.field_holder())->static_field_size() * wordSize);) - assert(id->offset() >= first_offset && id->offset() < end_offset, "invalid static field offset"); + debug_only(id->verify(fd.field_holder())); ret = jfieldIDWorkaround::to_static_jfieldID(id); return ret; @@ -1928,7 +1926,7 @@ if (JvmtiExport::should_post_field_access()) { JvmtiExport::jni_GetField_probe(thread, NULL, NULL, id->holder(), fieldID, true); } - jobject ret = JNIHandles::make_local(id->holder()->obj_field(id->offset())); + jobject ret = JNIHandles::make_local(id->holder()->java_mirror()->obj_field(id->offset())); DTRACE_PROBE1(hotspot_jni, GetStaticObjectField__return, ret); return ret; JNI_END @@ -1950,7 +1948,7 @@ if (JvmtiExport::should_post_field_access()) { \ JvmtiExport::jni_GetField_probe(thread, NULL, NULL, id->holder(), fieldID, true); \ } \ - ret = id->holder()-> Fieldname##_field (id->offset()); \ + ret = id->holder()->java_mirror()-> Fieldname##_field (id->offset()); \ return ret;\ JNI_END @@ -1976,7 +1974,7 @@ field_value.l = value; JvmtiExport::jni_SetField_probe(thread, NULL, NULL, id->holder(), fieldID, true, 'L', (jvalue *)&field_value); } - id->holder()->obj_field_put(id->offset(), JNIHandles::resolve(value)); + id->holder()->java_mirror()->obj_field_put(id->offset(), JNIHandles::resolve(value)); DTRACE_PROBE(hotspot_jni, SetStaticObjectField__return); JNI_END @@ -1999,7 +1997,7 @@ field_value.unionType = value; \ JvmtiExport::jni_SetField_probe(thread, NULL, NULL, id->holder(), fieldID, true, SigType, (jvalue *)&field_value); \ } \ - id->holder()-> Fieldname##_field_put (id->offset(), value); \ + id->holder()->java_mirror()-> Fieldname##_field_put (id->offset(), value); \ DTRACE_PROBE(hotspot_jni, SetStatic##Result##Field__return);\ JNI_END
--- a/src/share/vm/prims/jniCheck.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/prims/jniCheck.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, 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 @@ -224,8 +224,7 @@ ReportJNIFatalError(thr, fatal_wrong_static_field); /* check for proper field type */ - if (!instanceKlass::cast(f_oop)->find_local_field_from_offset( - id->offset(), true, &fd)) + if (!id->find_local_field(&fd)) ReportJNIFatalError(thr, fatal_static_field_not_found); if ((fd.field_type() != ftype) && !(fd.field_type() == T_ARRAY && ftype == T_OBJECT)) {
--- a/src/share/vm/prims/jvm.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/prims/jvm.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1808,7 +1808,7 @@ THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Wrong type at constant pool index"); } klassOop k = cp->klass_at(index, CHECK_NULL); - return (jclass) JNIHandles::make_local(k->klass_part()->java_mirror()); + return (jclass) JNIHandles::make_local(k->java_mirror()); } JVM_END @@ -1824,7 +1824,7 @@ } klassOop k = constantPoolOopDesc::klass_at_if_loaded(cp, index); if (k == NULL) return NULL; - return (jclass) JNIHandles::make_local(k->klass_part()->java_mirror()); + return (jclass) JNIHandles::make_local(k->java_mirror()); } JVM_END
--- a/src/share/vm/prims/jvmtiEnvBase.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/prims/jvmtiEnvBase.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, 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 @@ -616,9 +616,7 @@ bool found = false; if (jfieldIDWorkaround::is_static_jfieldID(field)) { JNIid* id = jfieldIDWorkaround::from_static_jfieldID(field); - int offset = id->offset(); - klassOop holder = id->holder(); - found = instanceKlass::cast(holder)->find_local_field_from_offset(offset, true, fd); + found = id->find_local_field(fd); } else { // Non-static field. The fieldID is really the offset of the field within the object. int offset = jfieldIDWorkaround::from_instance_jfieldID(k, field);
--- a/src/share/vm/prims/jvmtiImpl.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/prims/jvmtiImpl.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -919,15 +919,24 @@ nmethod* nm) { JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_COMPILED_METHOD_LOAD); event._event_data.compiled_method_load = nm; - nmethodLocker::lock_nmethod(nm); // will be unlocked when posted + // Keep the nmethod alive until the ServiceThread can process + // this deferred event. + nmethodLocker::lock_nmethod(nm); return event; } JvmtiDeferredEvent JvmtiDeferredEvent::compiled_method_unload_event( - jmethodID id, const void* code) { + nmethod* nm, jmethodID id, const void* code) { JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_COMPILED_METHOD_UNLOAD); + event._event_data.compiled_method_unload.nm = nm; event._event_data.compiled_method_unload.method_id = id; event._event_data.compiled_method_unload.code_begin = code; + // Keep the nmethod alive until the ServiceThread can process + // this deferred event. This will keep the memory for the + // generated code from being reused too early. We pass + // zombie_ok == true here so that our nmethod that was just + // made into a zombie can be locked. + nmethodLocker::lock_nmethod(nm, true /* zombie_ok */); return event; } JvmtiDeferredEvent JvmtiDeferredEvent::dynamic_code_generated_event( @@ -946,14 +955,19 @@ case TYPE_COMPILED_METHOD_LOAD: { nmethod* nm = _event_data.compiled_method_load; JvmtiExport::post_compiled_method_load(nm); + // done with the deferred event so unlock the nmethod nmethodLocker::unlock_nmethod(nm); break; } - case TYPE_COMPILED_METHOD_UNLOAD: + case TYPE_COMPILED_METHOD_UNLOAD: { + nmethod* nm = _event_data.compiled_method_unload.nm; JvmtiExport::post_compiled_method_unload( _event_data.compiled_method_unload.method_id, _event_data.compiled_method_unload.code_begin); + // done with the deferred event so unlock the nmethod + nmethodLocker::unlock_nmethod(nm); break; + } case TYPE_DYNAMIC_CODE_GENERATED: JvmtiExport::post_dynamic_code_generated_internal( _event_data.dynamic_code_generated.name,
--- a/src/share/vm/prims/jvmtiImpl.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/prims/jvmtiImpl.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -458,6 +458,7 @@ union { nmethod* compiled_method_load; struct { + nmethod* nm; jmethodID method_id; const void* code_begin; } compiled_method_unload; @@ -477,7 +478,7 @@ // Factory methods static JvmtiDeferredEvent compiled_method_load_event(nmethod* nm) KERNEL_RETURN_(JvmtiDeferredEvent()); - static JvmtiDeferredEvent compiled_method_unload_event( + static JvmtiDeferredEvent compiled_method_unload_event(nmethod* nm, jmethodID id, const void* code) KERNEL_RETURN_(JvmtiDeferredEvent()); static JvmtiDeferredEvent dynamic_code_generated_event( const char* name, const void* begin, const void* end)
--- a/src/share/vm/prims/jvmtiRedefineClasses.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -3350,11 +3350,12 @@ for (Klass *subk = ik->subklass(); subk != NULL; subk = subk->next_sibling()) { - klassOop sub = subk->as_klassOop(); - instanceKlass *subik = (instanceKlass *)sub->klass_part(); - - // recursively do subclasses of the current subclass - increment_class_counter(subik, THREAD); + if (subk->oop_is_instance()) { + // Only update instanceKlasses + instanceKlass *subik = (instanceKlass*)subk; + // recursively do subclasses of the current subclass + increment_class_counter(subik, THREAD); + } } }
--- a/src/share/vm/prims/jvmtiTagMap.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/prims/jvmtiTagMap.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, 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,6 +27,7 @@ #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "jvmtifiles/jvmtiEnv.hpp" +#include "oops/instanceMirrorKlass.hpp" #include "oops/objArrayKlass.hpp" #include "oops/oop.inline2.hpp" #include "prims/jvmtiEventController.hpp" @@ -2594,6 +2595,11 @@ if (o->is_klass()) { klassOop k = (klassOop)o; o = Klass::cast(k)->java_mirror(); + if (o == NULL) { + // Classes without mirrors don't correspond to real Java + // classes so just ignore them. + return; + } } else { // SystemDictionary::always_strong_oops_do reports the application @@ -2834,10 +2840,10 @@ // verify that a static oop field is in range static inline bool verify_static_oop(instanceKlass* ik, - klassOop k, int offset) { - address obj_p = (address)k + offset; - address start = (address)ik->start_of_static_fields(); - address end = start + (ik->static_oop_field_size() * heapOopSize); + oop mirror, int offset) { + address obj_p = (address)mirror + offset; + address start = (address)instanceMirrorKlass::start_of_static_fields(mirror); + address end = start + (java_lang_Class::static_oop_field_count(mirror) * heapOopSize); assert(end >= start, "sanity check"); if (obj_p >= start && obj_p < end) { @@ -2938,8 +2944,8 @@ ClassFieldDescriptor* field = field_map->field_at(i); char type = field->field_type(); if (!is_primitive_field_type(type)) { - oop fld_o = k->obj_field(field->field_offset()); - assert(verify_static_oop(ik, k, field->field_offset()), "sanity check"); + oop fld_o = mirror->obj_field(field->field_offset()); + assert(verify_static_oop(ik, mirror, field->field_offset()), "sanity check"); if (fld_o != NULL) { int slot = field->field_index(); if (!CallbackInvoker::report_static_field_reference(mirror, fld_o, slot)) { @@ -2949,7 +2955,7 @@ } } else { if (is_reporting_primitive_fields()) { - address addr = (address)k + field->field_offset(); + address addr = (address)mirror + field->field_offset(); int slot = field->field_index(); if (!CallbackInvoker::report_primitive_static_field(mirror, slot, addr, type)) { delete field_map;
--- a/src/share/vm/prims/methodHandles.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/prims/methodHandles.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -112,7 +112,7 @@ // MethodHandles::generate_adapters // void MethodHandles::generate_adapters() { - if (!EnableMethodHandles || SystemDictionary::MethodHandle_klass() == NULL) return; + if (!EnableInvokeDynamic || SystemDictionary::MethodHandle_klass() == NULL) return; assert(_adapter_code == NULL, "generate only once"); @@ -143,7 +143,7 @@ void MethodHandles::set_enabled(bool z) { if (_enabled != z) { - guarantee(z && EnableMethodHandles, "can only enable once, and only if -XX:+EnableMethodHandles"); + guarantee(z && EnableInvokeDynamic, "can only enable once, and only if -XX:+EnableInvokeDynamic"); _enabled = z; } } @@ -2579,7 +2579,6 @@ {CC"getMembers", CC"("CLS""STRG""STRG"I"CLS"I["MEM")I", FN_PTR(MHN_getMembers)} }; -// More entry points specifically for EnableInvokeDynamic. // FIXME: Remove methods2 after AllowTransitionalJSR292 is removed. static JNINativeMethod methods2[] = { {CC"registerBootstrap", CC"("CLS MH")V", FN_PTR(MHN_registerBootstrap)}, @@ -2618,10 +2617,8 @@ JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) { assert(MethodHandles::spot_check_entry_names(), "entry enum is OK"); - // note: this explicit warning-producing stuff will be replaced by auto-detection of the JSR 292 classes - - if (!EnableMethodHandles) { - warning("JSR 292 method handles are disabled in this JVM. Use -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles to enable."); + if (!EnableInvokeDynamic) { + warning("JSR 292 is disabled in this JVM. Use -XX:+UnlockDiagnosticVMOptions -XX:+EnableInvokeDynamic to enable."); return; // bind nothing } @@ -2702,11 +2699,6 @@ MethodHandles::set_enabled(true); } - if (!EnableInvokeDynamic) { - warning("JSR 292 invokedynamic is disabled in this JVM. Use -XX:+UnlockExperimentalVMOptions -XX:+EnableInvokeDynamic to enable."); - return; // bind nothing - } - if (AllowTransitionalJSR292) { ThreadToNativeFromVM ttnfv(thread);
--- a/src/share/vm/prims/unsafe.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/prims/unsafe.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -688,7 +688,7 @@ THROW_0(vmSymbols::java_lang_IllegalArgumentException()); } - return JNIHandles::make_local(env, java_lang_Class::as_klassOop(mirror)); + return JNIHandles::make_local(env, mirror); UNSAFE_END //@deprecated @@ -706,7 +706,7 @@ if (clazz == NULL) { THROW_0(vmSymbols::java_lang_NullPointerException()); } - return JNIHandles::make_local(env, java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(clazz))); + return JNIHandles::make_local(env, JNIHandles::resolve_non_null(clazz)); UNSAFE_END UNSAFE_ENTRY(void, Unsafe_EnsureClassInitialized(JNIEnv *env, jobject unsafe, jobject clazz)) @@ -1560,7 +1560,7 @@ } } } - if (AnonymousClasses) { + if (EnableInvokeDynamic) { env->RegisterNatives(unsafecls, anonk_methods, sizeof(anonk_methods)/sizeof(JNINativeMethod)); if (env->ExceptionOccurred()) { if (PrintMiscellaneous && (Verbose || WizardMode)) {
--- a/src/share/vm/runtime/arguments.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/runtime/arguments.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -242,6 +242,7 @@ 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) }, { NULL, JDK_Version(0), JDK_Version(0) } }; @@ -1003,28 +1004,6 @@ } } -void Arguments::check_compressed_oops_compat() { -#ifdef _LP64 - assert(UseCompressedOops, "Precondition"); - // Is it on by default or set on ergonomically - bool is_on_by_default = FLAG_IS_DEFAULT(UseCompressedOops) || FLAG_IS_ERGO(UseCompressedOops); - - // If dumping an archive or forcing its use, disable compressed oops if possible - if (DumpSharedSpaces || RequireSharedSpaces) { - if (is_on_by_default) { - FLAG_SET_DEFAULT(UseCompressedOops, false); - return; - } else { - vm_exit_during_initialization( - "Class Data Sharing is not supported with compressed oops yet", NULL); - } - } else if (UseSharedSpaces) { - // UseSharedSpaces is on by default. With compressed oops, we turn it off. - FLAG_SET_DEFAULT(UseSharedSpaces, false); - } -#endif -} - void Arguments::set_tiered_flags() { // With tiered, set default policy to AdvancedThresholdPolicy, which is 3. if (FLAG_IS_DEFAULT(CompilationPolicyChoice)) { @@ -1123,40 +1102,28 @@ set_parnew_gc_flags(); } + // MaxHeapSize is aligned down in collectorPolicy + size_t max_heap = align_size_down(MaxHeapSize, + CardTableRS::ct_max_alignment_constraint()); + // Now make adjustments for CMS - size_t young_gen_per_worker; - intx new_ratio; - size_t min_new_default; - intx tenuring_default; - if (CMSUseOldDefaults) { // old defaults: "old" as of 6.0 - if FLAG_IS_DEFAULT(CMSYoungGenPerWorker) { - FLAG_SET_ERGO(intx, CMSYoungGenPerWorker, 4*M); - } - young_gen_per_worker = 4*M; - new_ratio = (intx)15; - min_new_default = 4*M; - tenuring_default = (intx)0; - } else { // new defaults: "new" as of 6.0 - young_gen_per_worker = CMSYoungGenPerWorker; - new_ratio = (intx)7; - min_new_default = 16*M; - tenuring_default = (intx)4; - } - - // Preferred young gen size for "short" pauses + intx tenuring_default = (intx)6; + size_t young_gen_per_worker = CMSYoungGenPerWorker; + + // Preferred young gen size for "short" pauses: + // upper bound depends on # of threads and NewRatio. const uintx parallel_gc_threads = (ParallelGCThreads == 0 ? 1 : ParallelGCThreads); const size_t preferred_max_new_size_unaligned = - ScaleForWordSize(young_gen_per_worker * parallel_gc_threads); - const size_t preferred_max_new_size = + MIN2(max_heap/(NewRatio+1), ScaleForWordSize(young_gen_per_worker * parallel_gc_threads)); + size_t preferred_max_new_size = align_size_up(preferred_max_new_size_unaligned, os::vm_page_size()); // Unless explicitly requested otherwise, size young gen - // for "short" pauses ~ 4M*ParallelGCThreads + // for "short" pauses ~ CMSYoungGenPerWorker*ParallelGCThreads // If either MaxNewSize or NewRatio is set on the command line, // assume the user is trying to set the size of the young gen. - if (FLAG_IS_DEFAULT(MaxNewSize) && FLAG_IS_DEFAULT(NewRatio)) { // Set MaxNewSize to our calculated preferred_max_new_size unless @@ -1169,49 +1136,13 @@ } if (PrintGCDetails && Verbose) { // Too early to use gclog_or_tty - tty->print_cr("Ergo set MaxNewSize: " SIZE_FORMAT, MaxNewSize); + tty->print_cr("CMS ergo set MaxNewSize: " SIZE_FORMAT, MaxNewSize); } - // Unless explicitly requested otherwise, prefer a large - // Old to Young gen size so as to shift the collection load - // to the old generation concurrent collector - - // If this is only guarded by FLAG_IS_DEFAULT(NewRatio) - // then NewSize and OldSize may be calculated. That would - // generally lead to some differences with ParNewGC for which - // there was no obvious reason. Also limit to the case where - // MaxNewSize has not been set. - - FLAG_SET_ERGO(intx, NewRatio, MAX2(NewRatio, new_ratio)); - // Code along this path potentially sets NewSize and OldSize - // Calculate the desired minimum size of the young gen but if - // NewSize has been set on the command line, use it here since - // it should be the final value. - size_t min_new; - if (FLAG_IS_DEFAULT(NewSize)) { - min_new = align_size_up(ScaleForWordSize(min_new_default), - os::vm_page_size()); - } else { - min_new = NewSize; - } - size_t prev_initial_size = InitialHeapSize; - if (prev_initial_size != 0 && prev_initial_size < min_new + OldSize) { - FLAG_SET_ERGO(uintx, InitialHeapSize, min_new + OldSize); - // Currently minimum size and the initial heap sizes are the same. - set_min_heap_size(InitialHeapSize); - if (PrintGCDetails && Verbose) { - warning("Initial heap size increased to " SIZE_FORMAT " M from " - SIZE_FORMAT " M; use -XX:NewSize=... for finer control.", - InitialHeapSize/M, prev_initial_size/M); - } - } - - // MaxHeapSize is aligned down in collectorPolicy - size_t max_heap = - align_size_down(MaxHeapSize, - CardTableRS::ct_max_alignment_constraint()); + assert(max_heap >= InitialHeapSize, "Error"); + assert(max_heap >= NewSize, "Error"); if (PrintGCDetails && Verbose) { // Too early to use gclog_or_tty @@ -1220,7 +1151,11 @@ " max_heap: " SIZE_FORMAT, min_heap_size(), InitialHeapSize, max_heap); } - if (max_heap > min_new) { + size_t min_new = preferred_max_new_size; + if (FLAG_IS_CMDLINE(NewSize)) { + min_new = NewSize; + } + if (max_heap > min_new && min_heap_size() > min_new) { // Unless explicitly requested otherwise, make young gen // at least min_new, and at most preferred_max_new_size. if (FLAG_IS_DEFAULT(NewSize)) { @@ -1228,18 +1163,17 @@ FLAG_SET_ERGO(uintx, NewSize, MIN2(preferred_max_new_size, NewSize)); if (PrintGCDetails && Verbose) { // Too early to use gclog_or_tty - tty->print_cr("Ergo set NewSize: " SIZE_FORMAT, NewSize); + tty->print_cr("CMS ergo set NewSize: " SIZE_FORMAT, NewSize); } } // Unless explicitly requested otherwise, size old gen - // so that it's at least 3X of NewSize to begin with; - // later NewRatio will decide how it grows; see above. + // so it's NewRatio x of NewSize. if (FLAG_IS_DEFAULT(OldSize)) { if (max_heap > NewSize) { - FLAG_SET_ERGO(uintx, OldSize, MIN2(3*NewSize, max_heap - NewSize)); + FLAG_SET_ERGO(uintx, OldSize, MIN2(NewRatio*NewSize, max_heap - NewSize)); if (PrintGCDetails && Verbose) { // Too early to use gclog_or_tty - tty->print_cr("Ergo set OldSize: " SIZE_FORMAT, OldSize); + tty->print_cr("CMS ergo set OldSize: " SIZE_FORMAT, OldSize); } } } @@ -1383,7 +1317,7 @@ void Arguments::set_ergonomics_flags() { // Parallel GC is not compatible with sharing. If one specifies // that they want sharing explicitly, do not set ergonomics flags. - if (DumpSharedSpaces || ForceSharedSpaces) { + if (DumpSharedSpaces || RequireSharedSpaces) { return; } @@ -1690,13 +1624,13 @@ } bool Arguments::verify_min_value(intx val, intx min, const char* name) { - // Returns true if given value is greater than specified min threshold + // Returns true if given value is at least specified min threshold // false, otherwise. if (val >= min ) { return true; } jio_fprintf(defaultStream::error_stream(), - "%s of " INTX_FORMAT " is invalid; must be greater than " INTX_FORMAT "\n", + "%s of " INTX_FORMAT " is invalid; must be at least " INTX_FORMAT "\n", name, val, min); return false; } @@ -1846,33 +1780,6 @@ status = status && verify_percentage(GCHeapFreeLimit, "GCHeapFreeLimit"); - // Check whether user-specified sharing option conflicts with GC or page size. - // Both sharing and large pages are enabled by default on some platforms; - // large pages override sharing only if explicitly set on the command line. - const bool cannot_share = UseConcMarkSweepGC || CMSIncrementalMode || - UseG1GC || UseParNewGC || UseParallelGC || UseParallelOldGC || - UseLargePages && FLAG_IS_CMDLINE(UseLargePages); - if (cannot_share) { - // Either force sharing on by forcing the other options off, or - // force sharing off. - if (DumpSharedSpaces || ForceSharedSpaces) { - jio_fprintf(defaultStream::error_stream(), - "Using Serial GC and default page size because of %s\n", - ForceSharedSpaces ? "-Xshare:on" : "-Xshare:dump"); - force_serial_gc(); - FLAG_SET_DEFAULT(UseLargePages, false); - } else { - if (UseSharedSpaces && Verbose) { - jio_fprintf(defaultStream::error_stream(), - "Turning off use of shared archive because of " - "choice of garbage collector or large pages\n"); - } - no_shared_spaces(); - } - } else if (UseLargePages && (UseSharedSpaces || DumpSharedSpaces)) { - FLAG_SET_DEFAULT(UseLargePages, false); - } - status = status && check_gc_consistency(); status = status && check_stack_pages(); @@ -1950,6 +1857,8 @@ status = false; } + status = status && verify_min_value(ParGCArrayScanChunk, 1, "ParGCArrayScanChunk"); + #ifndef SERIALGC if (UseG1GC) { status = status && verify_percentage(InitiatingHeapOccupancyPercent, @@ -2413,9 +2322,6 @@ } else if (match_option(option, "-Xshare:on", &tail)) { FLAG_SET_CMDLINE(bool, UseSharedSpaces, true); FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true); -#ifdef TIERED - FLAG_SET_CMDLINE(bool, ForceSharedSpaces, true); -#endif // TIERED // -Xshare:auto } else if (match_option(option, "-Xshare:auto", &tail)) { FLAG_SET_CMDLINE(bool, UseSharedSpaces, true); @@ -2912,6 +2818,52 @@ return JNI_OK; } +void Arguments::set_shared_spaces_flags() { + const bool must_share = DumpSharedSpaces || RequireSharedSpaces; + const bool might_share = must_share || UseSharedSpaces; + + // The string table is part of the shared archive so the size must match. + if (!FLAG_IS_DEFAULT(StringTableSize)) { + // Disable sharing. + if (must_share) { + warning("disabling shared archive %s because of non-default " + "StringTableSize", DumpSharedSpaces ? "creation" : "use"); + } + if (might_share) { + FLAG_SET_DEFAULT(DumpSharedSpaces, false); + FLAG_SET_DEFAULT(RequireSharedSpaces, false); + FLAG_SET_DEFAULT(UseSharedSpaces, false); + } + return; + } + + // Check whether class data sharing settings conflict with GC, compressed oops + // or page size, and fix them up. Explicit sharing options override other + // settings. + const bool cannot_share = UseConcMarkSweepGC || CMSIncrementalMode || + UseG1GC || UseParNewGC || UseParallelGC || UseParallelOldGC || + UseCompressedOops || UseLargePages && FLAG_IS_CMDLINE(UseLargePages); + if (cannot_share) { + if (must_share) { + warning("selecting serial gc and disabling large pages %s" + "because of %s", "" LP64_ONLY("and compressed oops "), + DumpSharedSpaces ? "-Xshare:dump" : "-Xshare:on"); + force_serial_gc(); + FLAG_SET_CMDLINE(bool, UseLargePages, false); + LP64_ONLY(FLAG_SET_CMDLINE(bool, UseCompressedOops, false)); + } else { + if (UseSharedSpaces && Verbose) { + warning("turning off use of shared archive because of " + "choice of garbage collector or large pages"); + } + no_shared_spaces(); + } + } else if (UseLargePages && might_share) { + // Disable large pages to allow shared spaces. This is sub-optimal, since + // there may not even be a shared archive to use. + FLAG_SET_DEFAULT(UseLargePages, false); + } +} // Parse entry point called from JNI_CreateJavaVM @@ -3022,21 +2974,34 @@ } #endif // PRODUCT - if (EnableInvokeDynamic && !EnableMethodHandles) { - if (!FLAG_IS_DEFAULT(EnableMethodHandles)) { - warning("forcing EnableMethodHandles true because EnableInvokeDynamic is true"); + // Transitional + if (EnableMethodHandles || AnonymousClasses) { + if (!EnableInvokeDynamic && !FLAG_IS_DEFAULT(EnableInvokeDynamic)) { + warning("EnableMethodHandles and AnonymousClasses are obsolete. Keeping EnableInvokeDynamic disabled."); + } else { + EnableInvokeDynamic = true; } - EnableMethodHandles = true; } - if (EnableMethodHandles && !AnonymousClasses) { - if (!FLAG_IS_DEFAULT(AnonymousClasses)) { - warning("forcing AnonymousClasses true because EnableMethodHandles is true"); + + // JSR 292 is not supported before 1.7 + if (!JDK_Version::is_gte_jdk17x_version()) { + if (EnableInvokeDynamic) { + if (!FLAG_IS_DEFAULT(EnableInvokeDynamic)) { + warning("JSR 292 is not supported before 1.7. Disabling support."); + } + EnableInvokeDynamic = false; } - AnonymousClasses = true; } - if ((EnableMethodHandles || AnonymousClasses) && ScavengeRootsInCode == 0) { + + if (EnableInvokeDynamic && ScavengeRootsInCode == 0) { if (!FLAG_IS_DEFAULT(ScavengeRootsInCode)) { - warning("forcing ScavengeRootsInCode non-zero because EnableMethodHandles or AnonymousClasses is true"); + warning("forcing ScavengeRootsInCode non-zero because EnableInvokeDynamic is true"); + } + ScavengeRootsInCode = 1; + } + if (!JavaObjectsInPerm && ScavengeRootsInCode == 0) { + if (!FLAG_IS_DEFAULT(ScavengeRootsInCode)) { + warning("forcing ScavengeRootsInCode non-zero because JavaObjectsInPerm is false"); } ScavengeRootsInCode = 1; } @@ -3059,9 +3024,7 @@ // Set flags based on ergonomics. set_ergonomics_flags(); - if (UseCompressedOops) { - check_compressed_oops_compat(); - } + set_shared_spaces_flags(); // Check the GC selections again. if (!check_gc_consistency()) { @@ -3079,22 +3042,17 @@ } #ifndef KERNEL - if (UseConcMarkSweepGC) { - // Set flags for CMS and ParNew. Check UseConcMarkSweep first - // to ensure that when both UseConcMarkSweepGC and UseParNewGC - // are true, we don't call set_parnew_gc_flags() as well. + // Set heap size based on available physical memory + set_heap_size(); + // Set per-collector flags + if (UseParallelGC || UseParallelOldGC) { + set_parallel_gc_flags(); + } else if (UseConcMarkSweepGC) { // should be done before ParNew check below set_cms_and_parnew_gc_flags(); - } else { - // Set heap size based on available physical memory - set_heap_size(); - // Set per-collector flags - if (UseParallelGC || UseParallelOldGC) { - set_parallel_gc_flags(); - } else if (UseParNewGC) { - set_parnew_gc_flags(); - } else if (UseG1GC) { - set_g1_gc_flags(); - } + } else if (UseParNewGC) { // skipped if CMS is set above + set_parnew_gc_flags(); + } else if (UseG1GC) { + set_g1_gc_flags(); } #endif // KERNEL
--- a/src/share/vm/runtime/arguments.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/runtime/arguments.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -301,8 +301,6 @@ // Tiered static void set_tiered_flags(); - // Check compressed oops compatibility with other flags - static void check_compressed_oops_compat(); // CMS/ParNew garbage collectors static void set_parnew_gc_flags(); static void set_cms_and_parnew_gc_flags(); @@ -312,6 +310,7 @@ static void set_g1_gc_flags(); // GC ergonomics static void set_ergonomics_flags(); + static void set_shared_spaces_flags(); // Setup heap size static void set_heap_size(); // Based on automatic selection criteria, should the
--- a/src/share/vm/runtime/compilationPolicy.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/runtime/compilationPolicy.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -396,8 +396,6 @@ // SimpleCompPolicy - compile current method void SimpleCompPolicy::method_invocation_event( methodHandle m, TRAPS) { - assert(UseCompiler || CompileTheWorld, "UseCompiler should be set by now."); - int hot_count = m->invocation_count(); reset_counter_for_invocation_event(m); const char* comment = "count"; @@ -413,8 +411,6 @@ } void SimpleCompPolicy::method_back_branch_event(methodHandle m, int bci, TRAPS) { - assert(UseCompiler || CompileTheWorld, "UseCompiler should be set by now."); - int hot_count = m->backedge_count(); const char* comment = "backedge_count"; @@ -432,8 +428,6 @@ // Consider m for compilation void StackWalkCompPolicy::method_invocation_event(methodHandle m, TRAPS) { - assert(UseCompiler || CompileTheWorld, "UseCompiler should be set by now."); - int hot_count = m->invocation_count(); reset_counter_for_invocation_event(m); const char* comment = "count"; @@ -473,8 +467,6 @@ } void StackWalkCompPolicy::method_back_branch_event(methodHandle m, int bci, TRAPS) { - assert(UseCompiler || CompileTheWorld, "UseCompiler should be set by now."); - int hot_count = m->backedge_count(); const char* comment = "backedge_count";
--- a/src/share/vm/runtime/deoptimization.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/runtime/deoptimization.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -101,9 +101,9 @@ _frame_pcs = frame_pcs; _register_block = NEW_C_HEAP_ARRAY(intptr_t, RegisterMap::reg_count * 2); _return_type = return_type; + _initial_fp = 0; // PD (x86 only) _counter_temp = 0; - _initial_fp = 0; _unpack_kind = 0; _sender_sp_temp = 0; @@ -459,18 +459,9 @@ frame_sizes, frame_pcs, return_type); -#if defined(IA32) || defined(AMD64) - // We need a way to pass fp to the unpacking code so the skeletal frames - // come out correct. This is only needed for x86 because of c2 using ebp - // as an allocatable register. So this update is useless (and harmless) - // on the other platforms. It would be nice to do this in a different - // way but even the old style deoptimization had a problem with deriving - // this value. NEEDS_CLEANUP - // Note: now that c1 is using c2's deopt blob we must do this on all - // x86 based platforms - intptr_t** fp_addr = (intptr_t**) (((address)info) + info->initial_fp_offset_in_bytes()); - *fp_addr = array->sender().fp(); // was adapter_caller -#endif /* IA32 || AMD64 */ + // On some platforms, we need a way to pass fp to the unpacking code + // so the skeletal frames come out correct. + info->set_initial_fp((intptr_t) array->sender().fp()); if (array->frames() > 1) { if (VerifyStack && TraceDeoptimization) {
--- a/src/share/vm/runtime/deoptimization.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/runtime/deoptimization.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -136,12 +136,12 @@ address* _frame_pcs; // Array of frame pc's, in bytes, for unrolling the stack intptr_t* _register_block; // Block for storing callee-saved registers. BasicType _return_type; // Tells if we have to restore double or long return value + intptr_t _initial_fp; // FP of the sender frame // The following fields are used as temps during the unpacking phase // (which is tight on registers, especially on x86). They really ought // to be PD variables but that involves moving this class into its own // file to use the pd include mechanism. Maybe in a later cleanup ... intptr_t _counter_temp; // SHOULD BE PD VARIABLE (x86 frame count temp) - intptr_t _initial_fp; // SHOULD BE PD VARIABLE (x86/c2 initial ebp) intptr_t _unpack_kind; // SHOULD BE PD VARIABLE (x86 unpack kind) intptr_t _sender_sp_temp; // SHOULD BE PD VARIABLE (x86 sender_sp) public: @@ -165,6 +165,8 @@ // Returns the total size of frames int size_of_frames() const; + void set_initial_fp(intptr_t fp) { _initial_fp = fp; } + // Accessors used by the code generator for the unpack stub. static int size_of_deoptimized_frame_offset_in_bytes() { return offset_of(UnrollBlock, _size_of_deoptimized_frame); } static int caller_adjustment_offset_in_bytes() { return offset_of(UnrollBlock, _caller_adjustment); }
--- a/src/share/vm/runtime/globals.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/runtime/globals.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -851,7 +851,7 @@ diagnostic(bool, TraceNMethodInstalls, false, \ "Trace nmethod intallation") \ \ - diagnostic(intx, ScavengeRootsInCode, 0, \ + diagnostic(intx, ScavengeRootsInCode, 1, \ "0: do not allow scavengable oops in the code cache; " \ "1: allow scavenging from the code cache; " \ "2: emit as many constants as the compiler can see") \ @@ -1221,6 +1221,11 @@ "Decay time (in milliseconds) to re-enable bulk rebiasing of a " \ "type after previous bulk rebias") \ \ + develop(bool, JavaObjectsInPerm, false, \ + "controls whether Classes and interned Strings are allocated" \ + "in perm. This purely intended to allow debugging issues" \ + "in production.") \ + \ /* tracing */ \ \ notproduct(bool, TraceRuntimeCalls, false, \ @@ -1540,12 +1545,8 @@ product(bool, AlwaysPreTouch, false, \ "It forces all freshly committed pages to be pre-touched.") \ \ - product(bool, CMSUseOldDefaults, false, \ - "A flag temporarily introduced to allow reverting to some " \ - "older default settings; older as of 6.0") \ - \ - product(intx, CMSYoungGenPerWorker, 16*M, \ - "The amount of young gen chosen by default per GC worker " \ + product_pd(intx, CMSYoungGenPerWorker, \ + "The maximum size of young gen chosen by default per GC worker " \ "thread available") \ \ product(bool, GCOverheadReporting, false, \ @@ -2376,6 +2377,9 @@ develop(intx, CICloneLoopTestLimit, 100, \ "size limit for blocks heuristically cloned in ciTypeFlow") \ \ + develop(intx, OSROnlyBCI, -1, \ + "OSR only at this bci. Negative values mean exclude that bci") \ + \ /* temp diagnostics */ \ \ diagnostic(bool, TraceRedundantCompiles, false, \ @@ -3653,9 +3657,6 @@ product(bool, RequireSharedSpaces, false, \ "Require shared spaces in the permanent generation") \ \ - product(bool, ForceSharedSpaces, false, \ - "Require shared spaces in the permanent generation") \ - \ product(bool, DumpSharedSpaces, false, \ "Special mode: JVM reads a class list, loads classes, builds " \ "shared spaces, and dumps the shared spaces to a file to be " \ @@ -3692,11 +3693,15 @@ "Skip assert() and verify() which page-in unwanted shared " \ "objects. ") \ \ + diagnostic(bool, EnableInvokeDynamic, true, \ + "support JSR 292 (method handles, invokedynamic, " \ + "anonymous classes") \ + \ product(bool, AnonymousClasses, false, \ - "support sun.misc.Unsafe.defineAnonymousClass") \ + "support sun.misc.Unsafe.defineAnonymousClass (deprecated)") \ \ experimental(bool, EnableMethodHandles, false, \ - "support method handles (true by default under JSR 292)") \ + "support method handles (deprecated)") \ \ diagnostic(intx, MethodHandlePushLimit, 3, \ "number of additional stack slots a method handle may push") \ @@ -3713,9 +3718,6 @@ experimental(bool, TrustFinalNonStaticFields, false, \ "trust final non-static declarations for constant folding") \ \ - experimental(bool, EnableInvokeDynamic, false, \ - "recognize the invokedynamic instruction") \ - \ experimental(bool, AllowTransitionalJSR292, true, \ "recognize pre-PFD formats of invokedynamic") \ \ @@ -3758,6 +3760,9 @@ diagnostic(bool, PrintDTraceDOF, false, \ "Print the DTrace DOF passed to the system for JSDT probes") \ \ + product(uintx, StringTableSize, 1009, \ + "Number of buckets in the interned String table") \ + \ product(bool, UseVMInterruptibleIO, false, \ "(Unstable, Solaris-specific) Thread interrupt before or with " \ "EINTR for I/O operations results in OS_INTRPT. The default value"\
--- a/src/share/vm/runtime/os.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/runtime/os.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1079,11 +1079,6 @@ "%/lib/jsse.jar:" "%/lib/jce.jar:" "%/lib/charsets.jar:" - - // ## TEMPORARY hack to keep the legacy launcher working when - // ## only the boot module is installed (cf. j.l.ClassLoader) - "%/lib/modules/jdk.boot.jar:" - "%/classes"; char* sysclasspath = format_boot_path(classpath_format, home, home_len, fileSep, pathSep); if (sysclasspath == NULL) return false;
--- a/src/share/vm/runtime/osThread.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/runtime/osThread.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,7 @@ OSThreadStartFunc _start_proc; // Thread start routine void* _start_parm; // Thread start routine parameter volatile ThreadState _state; // Thread state *hint* - jint _interrupted; // Thread.isInterrupted state + volatile jint _interrupted; // Thread.isInterrupted state // Note: _interrupted must be jint, so that Java intrinsics can access it. // The value stored there must be either 0 or 1. It must be possible @@ -89,7 +89,7 @@ void* start_parm() const { return _start_parm; } void set_start_parm(void* start_parm) { _start_parm = start_parm; } - bool interrupted() const { return _interrupted != 0; } + volatile bool interrupted() const { return _interrupted != 0; } void set_interrupted(bool z) { _interrupted = z ? 1 : 0; } // Printing
--- a/src/share/vm/runtime/reflection.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/runtime/reflection.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -649,7 +649,7 @@ if (TraceClassResolution) { trace_class_resolution(k); } - return k->klass_part()->java_mirror(); + return k->java_mirror(); }; }
--- a/src/share/vm/runtime/serviceThread.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/runtime/serviceThread.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -70,11 +70,10 @@ java_lang_Thread::set_priority(thread_oop(), NearMaxPriority); java_lang_Thread::set_daemon(thread_oop()); thread->set_threadObj(thread_oop()); + _instance = thread; Threads::add(thread); Thread::start(thread); - - _instance = thread; } }
--- a/src/share/vm/runtime/sharedRuntime.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/runtime/sharedRuntime.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1682,7 +1682,7 @@ tty->print_cr("WrongMethodType thread="PTR_FORMAT" req="PTR_FORMAT" act="PTR_FORMAT"", thread, required, actual); } - assert(EnableMethodHandles, ""); + assert(EnableInvokeDynamic, ""); oop singleKlass = wrong_method_type_is_for_single_argument(thread, required); char* message = NULL; if (singleKlass != NULL) { @@ -2479,20 +2479,10 @@ // java compiled calling convention to the native convention, handlizes // arguments, and transitions to native. On return from the native we transition // back to java blocking if a safepoint is in progress. -nmethod *AdapterHandlerLibrary::create_native_wrapper(methodHandle method) { +nmethod *AdapterHandlerLibrary::create_native_wrapper(methodHandle method, int compile_id) { ResourceMark rm; nmethod* nm = NULL; - if (PrintCompilation) { - ttyLocker ttyl; - tty->print("--- n%s ", (method->is_synchronized() ? "s" : " ")); - method->print_short_name(tty); - if (method->is_static()) { - tty->print(" (static)"); - } - tty->cr(); - } - assert(method->has_native_function(), "must have something valid to call!"); { @@ -2537,6 +2527,7 @@ // Generate the compiled-to-native wrapper code nm = SharedRuntime::generate_native_wrapper(&_masm, method, + compile_id, total_args_passed, comp_args_on_stack, sig_bt,regs, @@ -2548,6 +2539,10 @@ // Install the generated code. if (nm != NULL) { + if (PrintCompilation) { + ttyLocker ttyl; + CompileTask::print_compilation(tty, nm, method->is_static() ? "(static)" : ""); + } method->set_code(method, nm); nm->post_compiled_method_load_event(); } else {
--- a/src/share/vm/runtime/sharedRuntime.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/runtime/sharedRuntime.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -438,6 +438,7 @@ // returns. static nmethod *generate_native_wrapper(MacroAssembler* masm, methodHandle method, + int compile_id, int total_args_passed, int max_arg, BasicType *sig_bt, @@ -659,7 +660,7 @@ static AdapterHandlerEntry* new_entry(AdapterFingerPrint* fingerprint, address i2c_entry, address c2i_entry, address c2i_unverified_entry); - static nmethod* create_native_wrapper(methodHandle method); + static nmethod* create_native_wrapper(methodHandle method, int compile_id); static AdapterHandlerEntry* get_adapter(methodHandle method); #ifdef HAVE_DTRACE_H
--- a/src/share/vm/runtime/thread.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/runtime/thread.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -3166,7 +3166,7 @@ fieldDescriptor fd; // Possible we might not find this field; if so, don't break if (ik->find_local_field(vmSymbols::frontCacheEnabled_name(), vmSymbols::bool_signature(), &fd)) { - k()->bool_field_put(fd.offset(), true); + k()->java_mirror()->bool_field_put(fd.offset(), true); } } @@ -3182,7 +3182,7 @@ fieldDescriptor fd; // Possible we might not find this field: if so, silently don't break if (ik->find_local_field(vmSymbols::stringCacheEnabled_name(), vmSymbols::bool_signature(), &fd)) { - k()->bool_field_put(fd.offset(), true); + k()->java_mirror()->bool_field_put(fd.offset(), true); } } } @@ -3229,7 +3229,7 @@ warning("java.lang.ArithmeticException has not been initialized"); warning("java.lang.StackOverflowError has not been initialized"); } - } + } // See : bugid 4211085. // Background : the static initializer of java.lang.Compiler tries to read
--- a/src/share/vm/runtime/vmStructs.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/runtime/vmStructs.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -70,6 +70,7 @@ #include "oops/cpCacheKlass.hpp" #include "oops/cpCacheOop.hpp" #include "oops/instanceKlass.hpp" +#include "oops/instanceMirrorKlass.hpp" #include "oops/instanceKlassKlass.hpp" #include "oops/instanceOop.hpp" #include "oops/klass.hpp" @@ -269,7 +270,7 @@ nonstatic_field(instanceKlass, _inner_classes, typeArrayOop) \ nonstatic_field(instanceKlass, _nonstatic_field_size, int) \ nonstatic_field(instanceKlass, _static_field_size, int) \ - nonstatic_field(instanceKlass, _static_oop_field_size, int) \ + nonstatic_field(instanceKlass, _static_oop_field_count, int) \ nonstatic_field(instanceKlass, _nonstatic_oop_map_size, int) \ nonstatic_field(instanceKlass, _is_marked_dependent, bool) \ nonstatic_field(instanceKlass, _minor_version, u2) \ @@ -840,7 +841,7 @@ /* OSThread */ \ /************/ \ \ - nonstatic_field(OSThread, _interrupted, jint) \ + volatile_nonstatic_field(OSThread, _interrupted, jint) \ \ /************************/ \ /* OopMap and OopMapSet */ \ @@ -945,6 +946,15 @@ static_field(Arguments, _num_jvm_args, int) \ static_field(Arguments, _java_command, char*) \ \ + /*********************************/ \ + /* java_lang_Class fields */ \ + /*********************************/ \ + \ + static_field(java_lang_Class, klass_offset, int) \ + static_field(java_lang_Class, resolved_constructor_offset, int) \ + static_field(java_lang_Class, array_klass_offset, int) \ + static_field(java_lang_Class, oop_size_offset, int) \ + static_field(java_lang_Class, static_oop_field_count_offset, int) \ \ /************************/ \ /* Miscellaneous fields */ \ @@ -1092,6 +1102,7 @@ declare_type(instanceKlass, Klass) \ declare_type(instanceKlassKlass, klassKlass) \ declare_type(instanceOopDesc, oopDesc) \ + declare_type(instanceMirrorKlass, instanceKlass) \ declare_type(instanceRefKlass, instanceKlass) \ declare_type(klassKlass, Klass) \ declare_type(klassOopDesc, oopDesc) \ @@ -1414,6 +1425,7 @@ declare_toplevel_type(intptr_t*) \ declare_unsigned_integer_type(InvocationCounter) /* FIXME: wrong type (not integer) */ \ declare_toplevel_type(JavaThread*) \ + declare_toplevel_type(java_lang_Class) \ declare_toplevel_type(jbyte*) \ declare_toplevel_type(jbyte**) \ declare_toplevel_type(jint*) \ @@ -1543,12 +1555,6 @@ \ declare_constant(SymbolTable::symbol_table_size) \ \ - /***************/ \ - /* StringTable */ \ - /***************/ \ - \ - declare_constant(StringTable::string_table_size) \ - \ /********************/ \ /* SystemDictionary */ \ /********************/ \ @@ -1700,15 +1706,6 @@ \ declare_constant(ConstantPoolCacheEntry::tosBits) \ \ - /*********************************/ \ - /* java_lang_Class field offsets */ \ - /*********************************/ \ - \ - declare_constant(java_lang_Class::hc_klass_offset) \ - declare_constant(java_lang_Class::hc_array_klass_offset) \ - declare_constant(java_lang_Class::hc_resolved_constructor_offset) \ - declare_constant(java_lang_Class::hc_number_of_fake_oop_fields) \ - \ /***************************************/ \ /* java_lang_Thread::ThreadStatus enum */ \ /***************************************/ \
--- a/src/share/vm/services/heapDumper.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/services/heapDumper.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -832,7 +832,7 @@ // value int offset = fld.offset(); - address addr = (address)k + offset; + address addr = (address)ikh->java_mirror() + offset; dump_field_value(writer, sig->byte_at(0), addr); }
--- a/src/share/vm/shark/sharkNativeWrapper.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/shark/sharkNativeWrapper.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -101,7 +101,7 @@ builder()->CreateStore( builder()->CreateInlineOop( JNIHandles::make_local( - target()->method_holder()->klass_part()->java_mirror())), + target()->method_holder()->java_mirror())), oop_tmp_slot()); param_types.push_back(box_type);
--- a/src/share/vm/utilities/debug.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/utilities/debug.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -25,6 +25,7 @@ #ifndef SHARE_VM_UTILITIES_DEBUG_HPP #define SHARE_VM_UTILITIES_DEBUG_HPP +#include "prims/jvm.h" #include "utilities/globalDefinitions.hpp" #include <stdarg.h> @@ -48,7 +49,7 @@ FormatBuffer<bufsz>::FormatBuffer(const char * format, ...) { va_list argp; va_start(argp, format); - vsnprintf(_buf, bufsz, format, argp); + jio_vsnprintf(_buf, bufsz, format, argp); va_end(argp); } @@ -61,7 +62,7 @@ va_list argp; va_start(argp, format); - vsnprintf(buf_end, bufsz - len, format, argp); + jio_vsnprintf(buf_end, bufsz - len, format, argp); va_end(argp); }
--- a/src/share/vm/utilities/globalDefinitions.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/utilities/globalDefinitions.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1185,7 +1185,7 @@ // '%d' formats to indicate a 64-bit quantity; commonly "l" (in LP64) or "ll" // (in ILP32). -#define BOOL_TO_STR(__b) (__b) ? "true" : "false" +#define BOOL_TO_STR(_b_) ((_b_) ? "true" : "false") // Format 32-bit quantities. #define INT32_FORMAT "%d"
--- a/src/share/vm/utilities/ostream.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/utilities/ostream.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -424,6 +424,15 @@ const char* star = strchr(basename, '*'); int star_pos = (star == NULL) ? -1 : (star - nametail); + int skip = 1; + if (star == NULL) { + // Try %p + star = strstr(basename, "%p"); + if (star != NULL) { + skip = 2; + } + } + star_pos = (star == NULL) ? -1 : (star - nametail); char pid[32]; if (star_pos >= 0) { @@ -442,11 +451,11 @@ } if (star_pos >= 0) { - // convert foo*bar.log to foo123bar.log + // convert foo*bar.log or foo%pbar.log to foo123bar.log int buf_pos = (int) strlen(buf); strncpy(&buf[buf_pos], nametail, star_pos); strcpy(&buf[buf_pos + star_pos], pid); - nametail += star_pos + 1; // skip prefix and star + nametail += star_pos + skip; // skip prefix and pid format } strcat(buf, nametail); // append rest of name, or all of name @@ -466,7 +475,7 @@ // Note: This feature is for maintainer use only. No need for L10N. jio_print(warnbuf); FREE_C_HEAP_ARRAY(char, try_name); - try_name = make_log_name("hs_pid*.log", os::get_temp_directory()); + try_name = make_log_name("hs_pid%p.log", os::get_temp_directory()); jio_snprintf(warnbuf, sizeof(warnbuf), "Warning: Forcing option -XX:LogFile=%s\n", try_name); jio_print(warnbuf); @@ -801,6 +810,8 @@ _buffer = buffer; _buflen = buflen; _outer_stream = outer_stream; + // compile task prints time stamp relative to VM start + _stamp.update_to(1); } void staticBufferStream::write(const char* c, size_t len) {
--- a/src/share/vm/utilities/workgroup.cpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/utilities/workgroup.cpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, 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 @@ -156,7 +156,7 @@ tty->print_cr("/nFinished work gang %s: %d/%d sequence %d", name(), finished_workers(), total_workers(), _sequence_number); - } + } } void AbstractWorkGang::stop() {
--- a/src/share/vm/utilities/workgroup.hpp Fri Apr 01 10:58:10 2011 +0100 +++ b/src/share/vm/utilities/workgroup.hpp Fri Apr 01 11:06:30 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,20 @@ # include "thread_windows.inline.hpp" #endif +// Task class hierarchy: +// AbstractGangTask +// AbstractGangTaskWOopQueues +// +// Gang/Group class hierarchy: +// AbstractWorkGang +// WorkGang +// FlexibleWorkGang +// YieldingFlexibleWorkGang (defined in another file) +// +// Worker class hierarchy: +// GangWorker (subclass of WorkerThread) +// YieldingFlexibleGangWorker (defined in another file) + // Forward declarations of classes defined here class WorkGang;
--- a/test/compiler/6987555/Test6987555.java Fri Apr 01 10:58:10 2011 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2010, 2011, 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 6987555 - * @summary JSR 292 unboxing to a boolean value fails on big-endian SPARC - * - * @run main/othervm -Xint -ea -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles -XX:+EnableInvokeDynamic -XX:+UnlockDiagnosticVMOptions -XX:+VerifyMethodHandles Test6987555 - */ - -import java.dyn.*; - -public class Test6987555 { - private static final Class CLASS = Test6987555.class; - private static final String NAME = "foo"; - private static final boolean DEBUG = false; - - public static void main(String[] args) throws Throwable { - testboolean(); - testbyte(); - testchar(); - testshort(); - testint(); - } - - // boolean - static void testboolean() throws Throwable { - doboolean(false); - doboolean(true); - } - static void doboolean(boolean x) throws Throwable { - if (DEBUG) System.out.println("boolean=" + x); - MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(boolean.class, boolean.class)); - MethodHandle mh2 = mh1.asType(MethodType.methodType(boolean.class, Boolean.class)); - boolean a = (boolean) mh1.invokeExact(x); - boolean b = (boolean) mh2.invokeExact(Boolean.valueOf(x)); - assert a == b : a + " != " + b; - } - - // byte - static void testbyte() throws Throwable { - byte[] a = new byte[] { - Byte.MIN_VALUE, - Byte.MIN_VALUE + 1, - -0x0F, - -1, - 0, - 1, - 0x0F, - Byte.MAX_VALUE - 1, - Byte.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - dobyte(a[i]); - } - } - static void dobyte(byte x) throws Throwable { - if (DEBUG) System.out.println("byte=" + x); - MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(byte.class, byte.class)); - MethodHandle mh2 = mh1.asType(MethodType.methodType(byte.class, Byte.class)); - byte a = (byte) mh1.invokeExact(x); - byte b = (byte) mh2.invokeExact(Byte.valueOf(x)); - assert a == b : a + " != " + b; - } - - // char - static void testchar() throws Throwable { - char[] a = new char[] { - Character.MIN_VALUE, - Character.MIN_VALUE + 1, - 0x000F, - 0x00FF, - 0x0FFF, - Character.MAX_VALUE - 1, - Character.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - dochar(a[i]); - } - } - static void dochar(char x) throws Throwable { - if (DEBUG) System.out.println("char=" + x); - MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(char.class, char.class)); - MethodHandle mh2 = mh1.asType(MethodType.methodType(char.class, Character.class)); - char a = (char) mh1.invokeExact(x); - char b = (char) mh2.invokeExact(Character.valueOf(x)); - assert a == b : a + " != " + b; - } - - // short - static void testshort() throws Throwable { - short[] a = new short[] { - Short.MIN_VALUE, - Short.MIN_VALUE + 1, - -0x0FFF, - -0x00FF, - -0x000F, - -1, - 0, - 1, - 0x000F, - 0x00FF, - 0x0FFF, - Short.MAX_VALUE - 1, - Short.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - doshort(a[i]); - } - } - static void doshort(short x) throws Throwable { - if (DEBUG) System.out.println("short=" + x); - MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(short.class, short.class)); - MethodHandle mh2 = mh1.asType(MethodType.methodType(short.class, Short.class)); - short a = (short) mh1.invokeExact(x); - short b = (short) mh2.invokeExact(Short.valueOf(x)); - assert a == b : a + " != " + b; - } - - // int - static void testint() throws Throwable { - int[] a = new int[] { - Integer.MIN_VALUE, - Integer.MIN_VALUE + 1, - -0x00000FFF, - -0x000000FF, - -0x0000000F, - -1, - 0, - 1, - 0x0000000F, - 0x000000FF, - 0x00000FFF, - Integer.MAX_VALUE - 1, - Integer.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - doint(a[i]); - } - } - static void doint(int x) throws Throwable { - if (DEBUG) System.out.println("int=" + x); - MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(int.class, int.class)); - MethodHandle mh2 = mh1.asType(MethodType.methodType(int.class, Integer.class)); - int a = (int) mh1.invokeExact(x); - int b = (int) mh2.invokeExact(Integer.valueOf(x)); - assert a == b : a + " != " + b; - } - - public static boolean foo(boolean i) { return i; } - public static byte foo(byte i) { return i; } - public static char foo(char i) { return i; } - public static short foo(short i) { return i; } - public static int foo(int i) { return i; } -}
--- a/test/compiler/6991596/Test6991596.java Fri Apr 01 10:58:10 2011 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,465 +0,0 @@ -/* - * Copyright (c) 2010, 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 6991596 - * @summary JSR 292 unimplemented adapter_opt_i2i and adapter_opt_l2i on SPARC - * - * @run main/othervm -ea -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles -XX:+EnableInvokeDynamic -XX:+UnlockDiagnosticVMOptions -XX:+VerifyMethodHandles Test6991596 - */ - -import java.dyn.*; - -public class Test6991596 { - private static final Class CLASS = Test6991596.class; - private static final String NAME = "foo"; - private static final boolean DEBUG = System.getProperty("DEBUG", "false").equals("true"); - - public static void main(String[] args) throws Throwable { - testboolean(); - testbyte(); - testchar(); - testshort(); - testint(); - testlong(); - } - - // Helpers to get various methods. - static MethodHandle getmh1(Class ret, Class arg) throws NoAccessException { - return MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(ret, arg)); - } - static MethodHandle getmh2(MethodHandle mh1, Class ret, Class arg) { - return MethodHandles.convertArguments(mh1, MethodType.methodType(ret, arg)); - } - static MethodHandle getmh3(MethodHandle mh1, Class ret, Class arg) { - return MethodHandles.convertArguments(mh1, MethodType.methodType(ret, arg)); - } - - // test adapter_opt_i2i - static void testboolean() throws Throwable { - boolean[] a = new boolean[] { - true, - false - }; - for (int i = 0; i < a.length; i++) { - doboolean(a[i]); - } - } - static void doboolean(boolean x) throws Throwable { - if (DEBUG) System.out.println("boolean=" + x); - - // boolean - { - MethodHandle mh1 = getmh1( boolean.class, boolean.class); - MethodHandle mh2 = getmh2(mh1, boolean.class, boolean.class); - // TODO add this for all cases when the bugs are fixed. - //MethodHandle mh3 = getmh3(mh1, boolean.class, boolean.class); - boolean a = (boolean) mh1.invokeExact((boolean) x); - boolean b = (boolean) mh2.invokeExact(x); - //boolean c = mh3.<boolean>invokeExact((boolean) x); - check(x, a, b); - //check(x, c, x); - } - - // byte - { - MethodHandle mh1 = getmh1( byte.class, byte.class ); - MethodHandle mh2 = getmh2(mh1, byte.class, boolean.class); - byte a = (byte) mh1.invokeExact((byte) (x ? 1 : 0)); - byte b = (byte) mh2.invokeExact(x); - check(x, a, b); - } - - // char - { - MethodHandle mh1 = getmh1( char.class, char.class); - MethodHandle mh2 = getmh2(mh1, char.class, boolean.class); - char a = (char) mh1.invokeExact((char) (x ? 1 : 0)); - char b = (char) mh2.invokeExact(x); - check(x, a, b); - } - - // short - { - MethodHandle mh1 = getmh1( short.class, short.class); - MethodHandle mh2 = getmh2(mh1, short.class, boolean.class); - short a = (short) mh1.invokeExact((short) (x ? 1 : 0)); - short b = (short) mh2.invokeExact(x); - check(x, a, b); - } - } - - static void testbyte() throws Throwable { - byte[] a = new byte[] { - Byte.MIN_VALUE, - Byte.MIN_VALUE + 1, - -0x0F, - -1, - 0, - 1, - 0x0F, - Byte.MAX_VALUE - 1, - Byte.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - dobyte(a[i]); - } - } - static void dobyte(byte x) throws Throwable { - if (DEBUG) System.out.println("byte=" + x); - - // boolean - { - MethodHandle mh1 = getmh1( boolean.class, boolean.class); - MethodHandle mh2 = getmh2(mh1, boolean.class, byte.class); - boolean a = (boolean) mh1.invokeExact((x & 1) == 1); - boolean b = (boolean) mh2.invokeExact(x); - check(x, a, b); - } - - // byte - { - MethodHandle mh1 = getmh1( byte.class, byte.class); - MethodHandle mh2 = getmh2(mh1, byte.class, byte.class); - byte a = (byte) mh1.invokeExact((byte) x); - byte b = (byte) mh2.invokeExact(x); - check(x, a, b); - } - - // char - { - MethodHandle mh1 = getmh1( char.class, char.class); - MethodHandle mh2 = getmh2(mh1, char.class, byte.class); - char a = (char) mh1.invokeExact((char) x); - char b = (char) mh2.invokeExact(x); - check(x, a, b); - } - - // short - { - MethodHandle mh1 = getmh1( short.class, short.class); - MethodHandle mh2 = getmh2(mh1, short.class, byte.class); - short a = (short) mh1.invokeExact((short) x); - short b = (short) mh2.invokeExact(x); - check(x, a, b); - } - } - - static void testchar() throws Throwable { - char[] a = new char[] { - Character.MIN_VALUE, - Character.MIN_VALUE + 1, - 0x000F, - 0x00FF, - 0x0FFF, - Character.MAX_VALUE - 1, - Character.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - dochar(a[i]); - } - } - static void dochar(char x) throws Throwable { - if (DEBUG) System.out.println("char=" + x); - - // boolean - { - MethodHandle mh1 = getmh1( boolean.class, boolean.class); - MethodHandle mh2 = getmh2(mh1, boolean.class, char.class); - boolean a = (boolean) mh1.invokeExact((x & 1) == 1); - boolean b = (boolean) mh2.invokeExact(x); - check(x, a, b); - } - - // byte - { - MethodHandle mh1 = getmh1( byte.class, byte.class); - MethodHandle mh2 = getmh2(mh1, byte.class, char.class); - byte a = (byte) mh1.invokeExact((byte) x); - byte b = (byte) mh2.invokeExact(x); - check(x, a, b); - } - - // char - { - MethodHandle mh1 = getmh1( char.class, char.class); - MethodHandle mh2 = getmh2(mh1, char.class, char.class); - char a = (char) mh1.invokeExact((char) x); - char b = (char) mh2.invokeExact(x); - check(x, a, b); - } - - // short - { - MethodHandle mh1 = getmh1( short.class, short.class); - MethodHandle mh2 = getmh2(mh1, short.class, char.class); - short a = (short) mh1.invokeExact((short) x); - short b = (short) mh2.invokeExact(x); - check(x, a, b); - } - } - - static void testshort() throws Throwable { - short[] a = new short[] { - Short.MIN_VALUE, - Short.MIN_VALUE + 1, - -0x0FFF, - -0x00FF, - -0x000F, - -1, - 0, - 1, - 0x000F, - 0x00FF, - 0x0FFF, - Short.MAX_VALUE - 1, - Short.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - doshort(a[i]); - } - } - static void doshort(short x) throws Throwable { - if (DEBUG) System.out.println("short=" + x); - - // boolean - { - MethodHandle mh1 = getmh1( boolean.class, boolean.class); - MethodHandle mh2 = getmh2(mh1, boolean.class, short.class); - boolean a = (boolean) mh1.invokeExact((x & 1) == 1); - boolean b = (boolean) mh2.invokeExact(x); - check(x, a, b); - } - - // byte - { - MethodHandle mh1 = getmh1( byte.class, byte.class); - MethodHandle mh2 = getmh2(mh1, byte.class, short.class); - byte a = (byte) mh1.invokeExact((byte) x); - byte b = (byte) mh2.invokeExact(x); - check(x, a, b); - } - - // char - { - MethodHandle mh1 = getmh1( char.class, char.class); - MethodHandle mh2 = getmh2(mh1, char.class, short.class); - char a = (char) mh1.invokeExact((char) x); - char b = (char) mh2.invokeExact(x); - check(x, a, b); - } - - // short - { - MethodHandle mh1 = getmh1( short.class, short.class); - MethodHandle mh2 = getmh2(mh1, short.class, short.class); - short a = (short) mh1.invokeExact((short) x); - short b = (short) mh2.invokeExact(x); - check(x, a, b); - } - } - - static void testint() throws Throwable { - int[] a = new int[] { - Integer.MIN_VALUE, - Integer.MIN_VALUE + 1, - -0x0FFFFFFF, - -0x00FFFFFF, - -0x000FFFFF, - -0x0000FFFF, - -0x00000FFF, - -0x000000FF, - -0x0000000F, - -1, - 0, - 1, - 0x0000000F, - 0x000000FF, - 0x00000FFF, - 0x0000FFFF, - 0x000FFFFF, - 0x00FFFFFF, - 0x0FFFFFFF, - Integer.MAX_VALUE - 1, - Integer.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - doint(a[i]); - } - } - static void doint(int x) throws Throwable { - if (DEBUG) System.out.println("int=" + x); - - // boolean - { - MethodHandle mh1 = getmh1( boolean.class, boolean.class); - MethodHandle mh2 = getmh2(mh1, boolean.class, int.class); - boolean a = (boolean) mh1.invokeExact((x & 1) == 1); - boolean b = (boolean) mh2.invokeExact(x); - check(x, a, b); - } - - // byte - { - MethodHandle mh1 = getmh1( byte.class, byte.class); - MethodHandle mh2 = getmh2(mh1, byte.class, int.class); - byte a = (byte) mh1.invokeExact((byte) x); - byte b = (byte) mh2.invokeExact(x); - check(x, a, b); - } - - // char - { - MethodHandle mh1 = getmh1( char.class, char.class); - MethodHandle mh2 = getmh2(mh1, char.class, int.class); - char a = (char) mh1.invokeExact((char) x); - char b = (char) mh2.invokeExact(x); - check(x, a, b); - } - - // short - { - MethodHandle mh1 = getmh1( short.class, short.class); - MethodHandle mh2 = getmh2(mh1, short.class, int.class); - short a = (short) mh1.invokeExact((short) x); - short b = (short) mh2.invokeExact(x); - assert a == b : a + " != " + b; - check(x, a, b); - } - - // int - { - MethodHandle mh1 = getmh1( int.class, int.class); - MethodHandle mh2 = getmh2(mh1, int.class, int.class); - int a = (int) mh1.invokeExact((int) x); - int b = (int) mh2.invokeExact(x); - check(x, a, b); - } - } - - // test adapter_opt_l2i - static void testlong() throws Throwable { - long[] a = new long[] { - Long.MIN_VALUE, - Long.MIN_VALUE + 1, - -0x000000000FFFFFFFL, - -0x0000000000FFFFFFL, - -0x00000000000FFFFFL, - -0x000000000000FFFFL, - -0x0000000000000FFFL, - -0x00000000000000FFL, - -0x000000000000000FL, - -1L, - 0L, - 1L, - 0x000000000000000FL, - 0x00000000000000FFL, - 0x0000000000000FFFL, - 0x0000000000000FFFL, - 0x000000000000FFFFL, - 0x00000000000FFFFFL, - 0x0000000000FFFFFFL, - 0x000000000FFFFFFFL, - Long.MAX_VALUE - 1, - Long.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - dolong(a[i]); - } - } - static void dolong(long x) throws Throwable { - if (DEBUG) System.out.println("long=" + x); - - // boolean - { - MethodHandle mh1 = getmh1( boolean.class, boolean.class); - MethodHandle mh2 = getmh2(mh1, boolean.class, long.class); - boolean a = (boolean) mh1.invokeExact((x & 1L) == 1L); - boolean b = (boolean) mh2.invokeExact(x); - check(x, a, b); - } - - // byte - { - MethodHandle mh1 = getmh1( byte.class, byte.class); - MethodHandle mh2 = getmh2(mh1, byte.class, long.class); - byte a = (byte) mh1.invokeExact((byte) x); - byte b = (byte) mh2.invokeExact(x); - check(x, a, b); - } - - // char - { - MethodHandle mh1 = getmh1( char.class, char.class); - MethodHandle mh2 = getmh2(mh1, char.class, long.class); - char a = (char) mh1.invokeExact((char) x); - char b = (char) mh2.invokeExact(x); - check(x, a, b); - } - - // short - { - MethodHandle mh1 = getmh1( short.class, short.class); - MethodHandle mh2 = getmh2(mh1, short.class, long.class); - short a = (short) mh1.invokeExact((short) x); - short b = (short) mh2.invokeExact(x); - check(x, a, b); - } - - // int - { - MethodHandle mh1 = getmh1( int.class, int.class); - MethodHandle mh2 = getmh2(mh1, int.class, long.class); - int a = (int) mh1.invokeExact((int) x); - int b = (int) mh2.invokeExact(x); - check(x, a, b); - } - } - - static void check(boolean x, boolean e, boolean a) { p(z2h(x), z2h(e), z2h(a)); assert e == a : z2h(x) + ": " + z2h(e) + " != " + z2h(a); } - static void check(boolean x, byte e, byte a) { p(z2h(x), i2h(e), i2h(a)); assert e == a : z2h(x) + ": " + i2h(e) + " != " + i2h(a); } - static void check(boolean x, int e, int a) { p(z2h(x), i2h(e), i2h(a)); assert e == a : z2h(x) + ": " + i2h(e) + " != " + i2h(a); } - - static void check(int x, boolean e, boolean a) { p(i2h(x), z2h(e), z2h(a)); assert e == a : i2h(x) + ": " + z2h(e) + " != " + z2h(a); } - static void check(int x, byte e, byte a) { p(i2h(x), i2h(e), i2h(a)); assert e == a : i2h(x) + ": " + i2h(e) + " != " + i2h(a); } - static void check(int x, int e, int a) { p(i2h(x), i2h(e), i2h(a)); assert e == a : i2h(x) + ": " + i2h(e) + " != " + i2h(a); } - - static void check(long x, boolean e, boolean a) { p(l2h(x), z2h(e), z2h(a)); assert e == a : l2h(x) + ": " + z2h(e) + " != " + z2h(a); } - static void check(long x, byte e, byte a) { p(l2h(x), i2h(e), i2h(a)); assert e == a : l2h(x) + ": " + i2h(e) + " != " + i2h(a); } - static void check(long x, int e, int a) { p(l2h(x), i2h(e), i2h(a)); assert e == a : l2h(x) + ": " + i2h(e) + " != " + i2h(a); } - - static void p(String x, String e, String a) { if (DEBUG) System.out.println(x + ": expected: " + e + ", actual: " + a); } - - static String z2h(boolean x) { return x ? "1" : "0"; } - static String i2h(int x) { return Integer.toHexString(x); } - static String l2h(long x) { return Long.toHexString(x); } - - // to int - public static boolean foo(boolean i) { return i; } - public static byte foo(byte i) { return i; } - public static char foo(char i) { return i; } - public static short foo(short i) { return i; } - public static int foo(int i) { return i; } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/7024475/Test7024475.java Fri Apr 01 11:06:30 2011 +0100 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2011, 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 7024475 + * @summary loop doesn't terminate when compiled + * + * @run main Test7024475 + */ + +public class Test7024475 { + + static int i; + static int x1; + static int[] bucket_B; + + static void test(Test7024475 test, int i, int c0, int j, int c1) { + for (;;) { + if (c1 > c0) { + if (c0 > 253) { + throw new InternalError("c0 = " + c0); + } + int index = c0 * 256 + c1; + if (index == -1) return; + i = bucket_B[index]; + if (1 < j - i && test != null) + x1 = 0; + j = i; + c1--; + } else { + c0--; + if (j <= 0) + break; + c1 = 255; + } + } + } + + public static void main(String args[]) { + Test7024475 t = new Test7024475(); + bucket_B = new int[256*256]; + for (int i = 1; i < 256*256; i++) { + bucket_B[i] = 1; + } + for (int n = 0; n < 100000; n++) { + test(t, 2, 85, 1, 134); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/7029152/Test.java Fri Apr 01 11:06:30 2011 +0100 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2011, 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 7029152 + * @summary Ideal nodes for String intrinsics miss memory edge optimization + * + * @run main/othervm -Xbatch Test + */ + +public class Test { + + static final String str = "11111xx11111xx1x"; + static int idx = 0; + + static int IndexOfTest(String str) { + return str.indexOf("11111xx1x"); + } + + public static void main(String args[]) { + final int ITERS=2000000; + + for (int i=0; i<ITERS; i++) { + idx = IndexOfTest(str); + } + System.out.println("IndexOf = " + idx); + } +}