# HG changeset patch # User duke # Date 1499269285 -7200 # Node ID 0327745d37371fc813db6f02863a51fd78f87b34 # Parent af2ac0dd2fa64c3e68e7ae0f032b4525dd5ba3f7# Parent 4c517ce821341d288129061b61eeb88500bd3c28 Merge diff -r af2ac0dd2fa6 -r 0327745d3737 .hgtags-top-repo --- a/.hgtags-top-repo Thu Apr 14 15:22:12 2011 -0700 +++ b/.hgtags-top-repo Wed Jul 05 17:41:25 2017 +0200 @@ -112,3 +112,4 @@ 783bd02b4ab4596059c74b10a1793d7bd2f1c157 jdk7-b135 2fe76e73adaa5133ac559f0b3c2c0707eca04580 jdk7-b136 7654afc6a29e43cb0a1343ce7f1287bf690d5e5f jdk7-b137 +fc47c97bbbd91b1f774d855c48a7e285eb1a351a jdk7-b138 diff -r af2ac0dd2fa6 -r 0327745d3737 corba/.hgtags --- a/corba/.hgtags Thu Apr 14 15:22:12 2011 -0700 +++ b/corba/.hgtags Wed Jul 05 17:41:25 2017 +0200 @@ -112,3 +112,4 @@ e0b72ae5dc5e824b342801c8d1d336a55eb54e2c jdk7-b135 48ef0c712e7cbf272f47f9224db92a3c6a9e2612 jdk7-b136 a66c01d8bf895261715955df0b95545c000ed6a8 jdk7-b137 +78d8cf04697e9df54f7f11e195b7da29b8e345a2 jdk7-b138 diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/.hgtags --- a/hotspot/.hgtags Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/.hgtags Wed Jul 05 17:41:25 2017 +0200 @@ -162,3 +162,5 @@ bd586e392d93b7ed7a1636dcc8da2b6a4203a102 hs21-b06 2dbcb4a4d8dace5fe78ceb563b134f1fb296cd8f jdk7-b137 2dbcb4a4d8dace5fe78ceb563b134f1fb296cd8f hs21-b07 +0930dc920c185afbf40fed9a655290b8e5b16783 jdk7-b138 +0930dc920c185afbf40fed9a655290b8e5b16783 hs21-b08 diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/agent/src/share/classes/sun/jvm/hotspot/HelloWorld.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/HelloWorld.java Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/HelloWorld.java Wed Jul 05 17:41:25 2017 +0200 @@ -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 @@ -55,7 +55,7 @@ synchronized(lock) { if (useMethodInvoke) { try { - Method method = HelloWorld.class.getMethod("e", null); + Method method = HelloWorld.class.getMethod("e"); Integer result = (Integer) method.invoke(null, new Object[0]); return result.intValue(); } diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ByteValueImpl.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ByteValueImpl.java Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ByteValueImpl.java Wed Jul 05 17:41:25 2017 +0200 @@ -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 @@ -52,12 +52,10 @@ return intValue(); } - public int compareTo(Object obj) { - byte other = ((ByteValue)obj).value(); - return value() - other; + public int compareTo(ByteValue byteVal) { + return value() - byteVal.value(); } - public Type type() { return vm.theByteType(); } diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/CharValueImpl.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/CharValueImpl.java Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/CharValueImpl.java Wed Jul 05 17:41:25 2017 +0200 @@ -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 @@ -52,9 +52,8 @@ return intValue(); } - public int compareTo(Object obj) { - char other = ((CharValue)obj).value(); - return value() - other; + public int compareTo(CharValue charVal) { + return value() - charVal.value(); } public Type type() { diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ConnectorImpl.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ConnectorImpl.java Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ConnectorImpl.java Wed Jul 05 17:41:25 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2004, 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 @@ -186,7 +186,7 @@ // assert isVMVersionMismatch(throwable), "not a VMVersionMismatch" Class expClass = throwable.getClass(); Method targetVersionMethod = expClass.getMethod("getTargetVersion", new Class[0]); - return (String) targetVersionMethod.invoke(throwable, null); + return (String) targetVersionMethod.invoke(throwable); } /** If the causal chain has a sun.jvm.hotspot.runtime.VMVersionMismatchException, diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/DoubleValueImpl.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/DoubleValueImpl.java Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/DoubleValueImpl.java Wed Jul 05 17:41:25 2017 +0200 @@ -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 @@ -45,8 +45,8 @@ } } - public int compareTo(Object obj) { - double other = ((DoubleValue)obj).value(); + public int compareTo(DoubleValue doubleVal) { + double other = doubleVal.value(); if (value() < other) { return -1; } else if (value() == other) { diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/FieldImpl.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/FieldImpl.java Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/FieldImpl.java Wed Jul 05 17:41:25 2017 +0200 @@ -145,8 +145,7 @@ } // From interface Comparable - public int compareTo(Object object) { - Field field = (Field)object; + public int compareTo(Field field) { ReferenceTypeImpl declaringType = (ReferenceTypeImpl)declaringType(); int rc = declaringType.compareTo(field.declaringType()); if (rc == 0) { diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/FloatValueImpl.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/FloatValueImpl.java Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/FloatValueImpl.java Wed Jul 05 17:41:25 2017 +0200 @@ -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 @@ -52,8 +52,8 @@ return intValue(); } - public int compareTo(Object obj) { - float other = ((FloatValue)obj).value(); + public int compareTo(FloatValue floatVal) { + float other = floatVal.value(); if (value() < other) { return -1; } else if (value() == other) { diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/IntegerValueImpl.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/IntegerValueImpl.java Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/IntegerValueImpl.java Wed Jul 05 17:41:25 2017 +0200 @@ -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 @@ -52,9 +52,8 @@ return intValue(); } - public int compareTo(Object obj) { - int other = ((IntegerValue)obj).value(); - return value() - other; + public int compareTo(IntegerValue integerVal) { + return value() - integerVal.value(); } public Type type() { diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/LocalVariableImpl.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/LocalVariableImpl.java Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/LocalVariableImpl.java Wed Jul 05 17:41:25 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2004, 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 @@ -67,8 +67,8 @@ return (int)method.hashCode() + slot(); } - public int compareTo(Object object) { - LocalVariableImpl other = (LocalVariableImpl)object; + public int compareTo(LocalVariable localVar) { + LocalVariableImpl other = (LocalVariableImpl) localVar; int rc = method.compareTo(other.method); if (rc == 0) { rc = slot() - other.slot(); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/LocationImpl.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/LocationImpl.java Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/LocationImpl.java Wed Jul 05 17:41:25 2017 +0200 @@ -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 @@ -78,8 +78,7 @@ return method().hashCode() + (int)codeIndex(); } - public int compareTo(Object object) { - LocationImpl other = (LocationImpl)object; + public int compareTo(Location other) { int rc = method().compareTo(other.method()); if (rc == 0) { long diff = codeIndex() - other.codeIndex(); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/LongValueImpl.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/LongValueImpl.java Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/LongValueImpl.java Wed Jul 05 17:41:25 2017 +0200 @@ -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 @@ -52,8 +52,8 @@ return intValue(); } - public int compareTo(Object obj) { - long other = ((LongValue)obj).value(); + public int compareTo(LongValue longVal) { + long other = longVal.value(); if (value() < other) { return -1; } else if (value() == other) { diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/MethodImpl.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/MethodImpl.java Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/MethodImpl.java Wed Jul 05 17:41:25 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2005, 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 @@ -200,8 +200,7 @@ } // From interface Comparable - public int compareTo(Object object) { - Method method = (Method)object; + public int compareTo(Method method) { ReferenceTypeImpl declaringType = (ReferenceTypeImpl)declaringType(); int rc = declaringType.compareTo(method.declaringType()); if (rc == 0) { diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ReferenceTypeImpl.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ReferenceTypeImpl.java Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ReferenceTypeImpl.java Wed Jul 05 17:41:25 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2005, 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 @@ -99,7 +99,7 @@ return saKlass.hashCode(); } - public int compareTo(Object object) { + public int compareTo(ReferenceType refType) { /* * Note that it is critical that compareTo() == 0 * implies that equals() == true. Otherwise, TreeSet @@ -108,7 +108,7 @@ * (Classes of the same name loaded by different class loaders * or in different VMs must not return 0). */ - ReferenceTypeImpl other = (ReferenceTypeImpl)object; + ReferenceTypeImpl other = (ReferenceTypeImpl)refType; int comp = name().compareTo(other.name()); if (comp == 0) { Oop rf1 = ref(); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ShortValueImpl.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ShortValueImpl.java Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ShortValueImpl.java Wed Jul 05 17:41:25 2017 +0200 @@ -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 @@ -52,9 +52,8 @@ return intValue(); } - public int compareTo(Object obj) { - short other = ((ShortValue)obj).value(); - return value() - other; + public int compareTo(ShortValue shortVal) { + return value() - shortVal.value(); } public Type type() { diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/VirtualMachineImpl.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/VirtualMachineImpl.java Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/VirtualMachineImpl.java Wed Jul 05 17:41:25 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2006, 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 @@ -798,12 +798,11 @@ } public String description() { - String[] versionParts = {"" + vmmgr.majorInterfaceVersion(), - "" + vmmgr.minorInterfaceVersion(), - name()}; return java.text.MessageFormat.format(java.util.ResourceBundle. getBundle("com.sun.tools.jdi.resources.jdi").getString("version_format"), - versionParts); + "" + vmmgr.majorInterfaceVersion(), + "" + vmmgr.minorInterfaceVersion(), + name()); } public String version() { diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java Wed Jul 05 17:41:25 2017 +0200 @@ -331,8 +331,6 @@ if (Assert.ASSERTS_ENABLED) { Assert.that(getTagAt(i).isInvokeDynamic(), "Corrupted constant pool"); } - if (getTagAt(i).value() == JVM_CONSTANT_InvokeDynamicTrans) - return null; int bsmSpec = extractLowShortFromInt(this.getIntAt(i)); TypeArray operands = getOperands(); if (operands == null) return null; // safety first @@ -368,7 +366,6 @@ case JVM_CONSTANT_MethodHandle: return "JVM_CONSTANT_MethodHandle"; case JVM_CONSTANT_MethodType: return "JVM_CONSTANT_MethodType"; case JVM_CONSTANT_InvokeDynamic: return "JVM_CONSTANT_InvokeDynamic"; - case JVM_CONSTANT_InvokeDynamicTrans: return "JVM_CONSTANT_InvokeDynamic/transitional"; case JVM_CONSTANT_Invalid: return "JVM_CONSTANT_Invalid"; case JVM_CONSTANT_UnresolvedClass: return "JVM_CONSTANT_UnresolvedClass"; case JVM_CONSTANT_UnresolvedClassInError: return "JVM_CONSTANT_UnresolvedClassInError"; @@ -428,7 +425,6 @@ case JVM_CONSTANT_MethodHandle: case JVM_CONSTANT_MethodType: case JVM_CONSTANT_InvokeDynamic: - case JVM_CONSTANT_InvokeDynamicTrans: visitor.doInt(new IntField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true); break; } @@ -592,7 +588,6 @@ break; } - case JVM_CONSTANT_InvokeDynamicTrans: case JVM_CONSTANT_InvokeDynamic: { dos.writeByte(cpConstType); int value = getIntAt(ci); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java Wed Jul 05 17:41:25 2017 +0200 @@ -42,7 +42,7 @@ public static final int JVM_CONSTANT_NameAndType = 12; public static final int JVM_CONSTANT_MethodHandle = 15; public static final int JVM_CONSTANT_MethodType = 16; - public static final int JVM_CONSTANT_InvokeDynamicTrans = 17; // only occurs in old class files + // static final int JVM_CONSTANT_(unused) = 17; public static final int JVM_CONSTANT_InvokeDynamic = 18; // JVM_CONSTANT_MethodHandle subtypes diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java Wed Jul 05 17:41:25 2017 +0200 @@ -321,7 +321,6 @@ break; } - case JVM_CONSTANT_InvokeDynamicTrans: case JVM_CONSTANT_InvokeDynamic: { dos.writeByte(cpConstType); int value = cpool.getIntAt(ci); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java Wed Jul 05 17:41:25 2017 +0200 @@ -598,7 +598,6 @@ buf.cell(Integer.toString(cpool.getIntAt(index))); break; - case JVM_CONSTANT_InvokeDynamicTrans: case JVM_CONSTANT_InvokeDynamic: buf.cell("JVM_CONSTANT_InvokeDynamic"); buf.cell(genLowHighShort(cpool.getIntAt(index)) + diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java Wed Jul 05 17:41:25 2017 +0200 @@ -40,7 +40,7 @@ private static int JVM_CONSTANT_NameAndType = 12; private static int JVM_CONSTANT_MethodHandle = 15; // JSR 292 private static int JVM_CONSTANT_MethodType = 16; // JSR 292 - private static int JVM_CONSTANT_InvokeDynamicTrans = 17; // JSR 292, only occurs in old class files + // static int JVM_CONSTANT_(unused) = 17; // JSR 292 early drafts only private static int JVM_CONSTANT_InvokeDynamic = 18; // JSR 292 private static int JVM_CONSTANT_Invalid = 0; // For bad value initialization private static int JVM_CONSTANT_UnresolvedClass = 100; // Temporary tag until actual use @@ -83,7 +83,6 @@ public boolean isMethodHandle() { return tag == JVM_CONSTANT_MethodHandle; } public boolean isMethodType() { return tag == JVM_CONSTANT_MethodType; } public boolean isInvokeDynamic() { return tag == JVM_CONSTANT_InvokeDynamic; } - public boolean isInvokeDynamicTrans() { return tag == JVM_CONSTANT_InvokeDynamicTrans; } public boolean isInvalid() { return tag == JVM_CONSTANT_Invalid; } diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/make/hotspot_version --- a/hotspot/make/hotspot_version Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/make/hotspot_version Wed Jul 05 17:41:25 2017 +0200 @@ -35,7 +35,7 @@ HS_MAJOR_VER=21 HS_MINOR_VER=0 -HS_BUILD_NUMBER=08 +HS_BUILD_NUMBER=09 JDK_MAJOR_VER=1 JDK_MINOR_VER=7 diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/make/linux/makefiles/sa.make --- a/hotspot/make/linux/makefiles/sa.make Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/make/linux/makefiles/sa.make Wed Jul 05 17:41:25 2017 +0200 @@ -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 @@ -97,8 +97,8 @@ $(foreach file,$(AGENT_FILES1),$(shell echo $(file) >> $(AGENT_FILES1_LIST))) $(foreach file,$(AGENT_FILES2),$(shell echo $(file) >> $(AGENT_FILES2_LIST))) - $(QUIETLY) $(REMOTE) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES1_LIST) - $(QUIETLY) $(REMOTE) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES2_LIST) + $(QUIETLY) $(REMOTE) $(COMPILE.JAVAC) -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES1_LIST) + $(QUIETLY) $(REMOTE) $(COMPILE.JAVAC) -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES2_LIST) $(QUIETLY) $(REMOTE) $(COMPILE.RMIC) -classpath $(SA_CLASSDIR) -d $(SA_CLASSDIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer $(QUIETLY) echo "$(SA_BUILD_VERSION_PROP)" > $(SA_PROPERTIES) diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/make/linux/makefiles/vm.make --- a/hotspot/make/linux/makefiles/vm.make Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/make/linux/makefiles/vm.make Wed Jul 05 17:41:25 2017 +0200 @@ -142,13 +142,15 @@ COMPILER2_PATHS += $(HS_COMMON_SRC)/share/vm/libadt COMPILER2_PATHS += $(GENERATED)/adfiles +SHARK_PATHS := $(GAMMADIR)/src/share/vm/shark + # Include dirs per type. Src_Dirs/CORE := $(CORE_PATHS) Src_Dirs/COMPILER1 := $(CORE_PATHS) $(COMPILER1_PATHS) Src_Dirs/COMPILER2 := $(CORE_PATHS) $(COMPILER2_PATHS) Src_Dirs/TIERED := $(CORE_PATHS) $(COMPILER1_PATHS) $(COMPILER2_PATHS) Src_Dirs/ZERO := $(CORE_PATHS) -Src_Dirs/SHARK := $(CORE_PATHS) +Src_Dirs/SHARK := $(CORE_PATHS) $(SHARK_PATHS) Src_Dirs := $(Src_Dirs/$(TYPE)) COMPILER2_SPECIFIC_FILES := opto libadt bcEscapeAnalyzer.cpp chaitin\* c2_\* runtime_\* diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/make/solaris/makefiles/sa.make --- a/hotspot/make/solaris/makefiles/sa.make Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/make/solaris/makefiles/sa.make Wed Jul 05 17:41:25 2017 +0200 @@ -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 @@ -88,8 +88,8 @@ $(foreach file,$(AGENT_FILES1),$(shell echo $(file) >> $(AGENT_FILES1_LIST))) $(foreach file,$(AGENT_FILES2),$(shell echo $(file) >> $(AGENT_FILES2_LIST))) - $(QUIETLY) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES1_LIST) - $(QUIETLY) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES2_LIST) + $(QUIETLY) $(COMPILE.JAVAC) -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES1_LIST) + $(QUIETLY) $(COMPILE.JAVAC) -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES2_LIST) $(QUIETLY) $(COMPILE.RMIC) -classpath $(SA_CLASSDIR) -d $(SA_CLASSDIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer $(QUIETLY) echo "$(SA_BUILD_VERSION_PROP)" > $(SA_PROPERTIES) diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/make/windows/makefiles/sa.make --- a/hotspot/make/windows/makefiles/sa.make Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/make/windows/makefiles/sa.make Wed Jul 05 17:41:25 2017 +0200 @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2009, 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 @@ -55,9 +55,9 @@ $(GENERATED)\sa-jdi.jar: $(AGENT_FILES1:/=\) $(AGENT_FILES2:/=\) @if not exist $(SA_CLASSDIR) mkdir $(SA_CLASSDIR) @echo ...Building sa-jdi.jar - @echo ...$(COMPILE_JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -d $(SA_CLASSDIR) .... - @$(COMPILE_JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) $(AGENT_FILES1:/=\) - @$(COMPILE_JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) $(AGENT_FILES2:/=\) + @echo ...$(COMPILE_JAVAC) -classpath $(SA_CLASSPATH) -d $(SA_CLASSDIR) .... + @$(COMPILE_JAVAC) -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) $(AGENT_FILES1:/=\) + @$(COMPILE_JAVAC) -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) $(AGENT_FILES2:/=\) $(COMPILE_RMIC) -classpath $(SA_CLASSDIR) -d $(SA_CLASSDIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer $(QUIETLY) echo $(SA_BUILD_VERSION_PROP)> $(SA_PROPERTIES) $(QUIETLY) rm -f $(SA_CLASSDIR)/sun/jvm/hotspot/utilities/soql/sa.js diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -2058,6 +2058,13 @@ BasicType basic_type = default_type != NULL ? default_type->element_type()->basic_type() : T_ILLEGAL; if (basic_type == T_ARRAY) basic_type = T_OBJECT; +#ifdef _LP64 + // higher 32bits must be null + __ sra(dst_pos, 0, dst_pos); + __ sra(src_pos, 0, src_pos); + __ sra(length, 0, length); +#endif + // set up the arraycopy stub information ArrayCopyStub* stub = op->stub(); @@ -2065,20 +2072,36 @@ // the known type isn't loaded since the code sanity checks // in debug mode and the type isn't required when we know the exact type // also check that the type is an array type. - // We also, for now, always call the stub if the barrier set requires a - // write_ref_pre barrier (which the stub does, but none of the optimized - // cases currently does). - if (op->expected_type() == NULL || - Universe::heap()->barrier_set()->has_write_ref_pre_barrier()) { + if (op->expected_type() == NULL) { __ mov(src, O0); __ mov(src_pos, O1); __ mov(dst, O2); __ mov(dst_pos, O3); __ mov(length, O4); - __ call_VM_leaf(tmp, CAST_FROM_FN_PTR(address, Runtime1::arraycopy)); - - __ br_zero(Assembler::less, false, Assembler::pn, O0, *stub->entry()); - __ delayed()->nop(); + address copyfunc_addr = StubRoutines::generic_arraycopy(); + + if (copyfunc_addr == NULL) { // Use C version if stub was not generated + __ call_VM_leaf(tmp, CAST_FROM_FN_PTR(address, Runtime1::arraycopy)); + } else { +#ifndef PRODUCT + if (PrintC1Statistics) { + address counter = (address)&Runtime1::_generic_arraycopystub_cnt; + __ inc_counter(counter, G1, G3); + } +#endif + __ call_VM_leaf(tmp, copyfunc_addr); + } + + if (copyfunc_addr != NULL) { + __ xor3(O0, -1, tmp); + __ sub(length, tmp, length); + __ add(src_pos, tmp, src_pos); + __ br_zero(Assembler::less, false, Assembler::pn, O0, *stub->entry()); + __ delayed()->add(dst_pos, tmp, dst_pos); + } else { + __ br_zero(Assembler::less, false, Assembler::pn, O0, *stub->entry()); + __ delayed()->nop(); + } __ bind(*stub->continuation()); return; } @@ -2135,20 +2158,137 @@ __ delayed()->nop(); } + int shift = shift_amount(basic_type); + if (flags & LIR_OpArrayCopy::type_check) { - if (UseCompressedOops) { - // We don't need decode because we just need to compare - __ lduw(src, oopDesc::klass_offset_in_bytes(), tmp); - __ lduw(dst, oopDesc::klass_offset_in_bytes(), tmp2); - __ cmp(tmp, tmp2); - __ br(Assembler::notEqual, false, Assembler::pt, *stub->entry()); + // We don't know the array types are compatible + if (basic_type != T_OBJECT) { + // Simple test for basic type arrays + if (UseCompressedOops) { + // We don't need decode because we just need to compare + __ lduw(src, oopDesc::klass_offset_in_bytes(), tmp); + __ lduw(dst, oopDesc::klass_offset_in_bytes(), tmp2); + __ cmp(tmp, tmp2); + __ br(Assembler::notEqual, false, Assembler::pt, *stub->entry()); + } else { + __ ld_ptr(src, oopDesc::klass_offset_in_bytes(), tmp); + __ ld_ptr(dst, oopDesc::klass_offset_in_bytes(), tmp2); + __ cmp(tmp, tmp2); + __ brx(Assembler::notEqual, false, Assembler::pt, *stub->entry()); + } + __ delayed()->nop(); } else { - __ ld_ptr(src, oopDesc::klass_offset_in_bytes(), tmp); - __ ld_ptr(dst, oopDesc::klass_offset_in_bytes(), tmp2); - __ cmp(tmp, tmp2); - __ brx(Assembler::notEqual, false, Assembler::pt, *stub->entry()); + // For object arrays, if src is a sub class of dst then we can + // safely do the copy. + address copyfunc_addr = StubRoutines::checkcast_arraycopy(); + + Label cont, slow; + assert_different_registers(tmp, tmp2, G3, G1); + + __ load_klass(src, G3); + __ load_klass(dst, G1); + + __ check_klass_subtype_fast_path(G3, G1, tmp, tmp2, &cont, copyfunc_addr == NULL ? stub->entry() : &slow, NULL); + + __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type); + __ delayed()->nop(); + + __ cmp(G3, 0); + if (copyfunc_addr != NULL) { // use stub if available + // src is not a sub class of dst so we have to do a + // per-element check. + __ br(Assembler::notEqual, false, Assembler::pt, cont); + __ delayed()->nop(); + + __ bind(slow); + + int mask = LIR_OpArrayCopy::src_objarray|LIR_OpArrayCopy::dst_objarray; + if ((flags & mask) != mask) { + // Check that at least both of them object arrays. + assert(flags & mask, "one of the two should be known to be an object array"); + + if (!(flags & LIR_OpArrayCopy::src_objarray)) { + __ load_klass(src, tmp); + } else if (!(flags & LIR_OpArrayCopy::dst_objarray)) { + __ load_klass(dst, tmp); + } + int lh_offset = klassOopDesc::header_size() * HeapWordSize + + Klass::layout_helper_offset_in_bytes(); + + __ lduw(tmp, lh_offset, tmp2); + + jint objArray_lh = Klass::array_layout_helper(T_OBJECT); + __ set(objArray_lh, tmp); + __ cmp(tmp, tmp2); + __ br(Assembler::notEqual, false, Assembler::pt, *stub->entry()); + __ delayed()->nop(); + } + + Register src_ptr = O0; + Register dst_ptr = O1; + Register len = O2; + Register chk_off = O3; + Register super_k = O4; + + __ add(src, arrayOopDesc::base_offset_in_bytes(basic_type), src_ptr); + if (shift == 0) { + __ add(src_ptr, src_pos, src_ptr); + } else { + __ sll(src_pos, shift, tmp); + __ add(src_ptr, tmp, src_ptr); + } + + __ add(dst, arrayOopDesc::base_offset_in_bytes(basic_type), dst_ptr); + if (shift == 0) { + __ add(dst_ptr, dst_pos, dst_ptr); + } else { + __ sll(dst_pos, shift, tmp); + __ add(dst_ptr, tmp, dst_ptr); + } + __ mov(length, len); + __ load_klass(dst, tmp); + + int ek_offset = (klassOopDesc::header_size() * HeapWordSize + + objArrayKlass::element_klass_offset_in_bytes()); + __ ld_ptr(tmp, ek_offset, super_k); + + int sco_offset = (klassOopDesc::header_size() * HeapWordSize + + Klass::super_check_offset_offset_in_bytes()); + __ lduw(super_k, sco_offset, chk_off); + + __ call_VM_leaf(tmp, copyfunc_addr); + +#ifndef PRODUCT + if (PrintC1Statistics) { + Label failed; + __ br_notnull(O0, false, Assembler::pn, failed); + __ delayed()->nop(); + __ inc_counter((address)&Runtime1::_arraycopy_checkcast_cnt, G1, G3); + __ bind(failed); + } +#endif + + __ br_null(O0, false, Assembler::pt, *stub->continuation()); + __ delayed()->xor3(O0, -1, tmp); + +#ifndef PRODUCT + if (PrintC1Statistics) { + __ inc_counter((address)&Runtime1::_arraycopy_checkcast_attempt_cnt, G1, G3); + } +#endif + + __ sub(length, tmp, length); + __ add(src_pos, tmp, src_pos); + __ br(Assembler::always, false, Assembler::pt, *stub->entry()); + __ delayed()->add(dst_pos, tmp, dst_pos); + + __ bind(cont); + } else { + __ br(Assembler::equal, false, Assembler::pn, *stub->entry()); + __ delayed()->nop(); + __ bind(cont); + } } - __ delayed()->nop(); } #ifdef ASSERT @@ -2207,14 +2347,18 @@ } #endif - int shift = shift_amount(basic_type); +#ifndef PRODUCT + if (PrintC1Statistics) { + address counter = Runtime1::arraycopy_count_address(basic_type); + __ inc_counter(counter, G1, G3); + } +#endif Register src_ptr = O0; Register dst_ptr = O1; Register len = O2; __ add(src, arrayOopDesc::base_offset_in_bytes(basic_type), src_ptr); - LP64_ONLY(__ sra(src_pos, 0, src_pos);) //higher 32bits must be null if (shift == 0) { __ add(src_ptr, src_pos, src_ptr); } else { @@ -2223,7 +2367,6 @@ } __ add(dst, arrayOopDesc::base_offset_in_bytes(basic_type), dst_ptr); - LP64_ONLY(__ sra(dst_pos, 0, dst_pos);) //higher 32bits must be null if (shift == 0) { __ add(dst_ptr, dst_pos, dst_ptr); } else { @@ -2231,18 +2374,14 @@ __ add(dst_ptr, tmp, dst_ptr); } - if (basic_type != T_OBJECT) { - if (shift == 0) { - __ mov(length, len); - } else { - __ sll(length, shift, len); - } - __ call_VM_leaf(tmp, CAST_FROM_FN_PTR(address, Runtime1::primitive_arraycopy)); - } else { - // oop_arraycopy takes a length in number of elements, so don't scale it. - __ mov(length, len); - __ call_VM_leaf(tmp, CAST_FROM_FN_PTR(address, Runtime1::oop_arraycopy)); - } + bool disjoint = (flags & LIR_OpArrayCopy::overlapping) == 0; + bool aligned = (flags & LIR_OpArrayCopy::unaligned) == 0; + const char *name; + address entry = StubRoutines::select_arraycopy_function(basic_type, aligned, disjoint, name, false); + + // arraycopy stubs takes a length in number of elements, so don't scale it. + __ mov(length, len); + __ call_VM_leaf(tmp, entry); __ bind(*stub->continuation()); } diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -387,7 +387,7 @@ void C1_MacroAssembler::verify_not_null_oop(Register r) { Label not_null; - br_zero(Assembler::notEqual, false, Assembler::pt, r, not_null); + br_notnull(r, false, Assembler::pt, not_null); delayed()->nop(); stop("non-null oop required"); bind(not_null); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/cpu/x86/vm/assembler_x86.cpp --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -2317,7 +2317,7 @@ } void Assembler::prefetchr(Address src) { - NOT_LP64(assert(VM_Version::supports_3dnow(), "must support")); + NOT_LP64(assert(VM_Version::supports_3dnow_prefetch(), "must support")); InstructionMark im(this); prefetch_prefix(src); emit_byte(0x0D); @@ -2349,7 +2349,7 @@ } void Assembler::prefetchw(Address src) { - NOT_LP64(assert(VM_Version::supports_3dnow(), "must support")); + NOT_LP64(assert(VM_Version::supports_3dnow_prefetch(), "must support")); InstructionMark im(this); prefetch_prefix(src); emit_byte(0x0D); @@ -7941,12 +7941,12 @@ #endif push(rax); // save rax, // addr may contain rsp so we will have to adjust it based on the push - // we just did + // we just did (and on 64 bit we do two pushes) // NOTE: 64bit seemed to have had a bug in that it did movq(addr, rax); which // stores rax into addr which is backwards of what was intended. if (addr.uses(rsp)) { lea(rax, addr); - pushptr(Address(rax, BytesPerWord)); + pushptr(Address(rax, LP64_ONLY(2 *) BytesPerWord)); } else { pushptr(addr); } @@ -8396,6 +8396,17 @@ movptr(dst, src); } +// Doesn't do verfication, generates fixed size code +void MacroAssembler::load_heap_oop_not_null(Register dst, Address src) { +#ifdef _LP64 + if (UseCompressedOops) { + movl(dst, src); + decode_heap_oop_not_null(dst); + } else +#endif + movptr(dst, src); +} + void MacroAssembler::store_heap_oop(Address dst, Register src) { #ifdef _LP64 if (UseCompressedOops) { diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/cpu/x86/vm/assembler_x86.hpp --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -385,10 +385,18 @@ }; class ExternalAddress: public AddressLiteral { - - public: - - ExternalAddress(address target) : AddressLiteral(target, relocInfo::external_word_type){} + private: + static relocInfo::relocType reloc_for_target(address target) { + // Sometimes ExternalAddress is used for values which aren't + // exactly addresses, like the card table base. + // external_word_type can't be used for values in the first page + // so just skip the reloc in that case. + return external_word_Relocation::can_be_relocated(target) ? relocInfo::external_word_type : relocInfo::none; + } + + public: + + ExternalAddress(address target) : AddressLiteral(target, reloc_for_target(target)) {} }; @@ -1701,6 +1709,7 @@ void store_klass(Register dst, Register src); void load_heap_oop(Register dst, Address src); + void load_heap_oop_not_null(Register dst, Address src); void store_heap_oop(Address dst, Register src); // Used for storing NULL. All other oop constants should be diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp --- a/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -316,7 +316,9 @@ Register tmp2 = rbx; __ push(tmp); __ push(tmp2); - __ load_heap_oop(tmp2, Address(_obj, java_lang_Class::klass_offset_in_bytes())); + // Load without verification to keep code size small. We need it because + // begin_initialized_entry_offset has to fit in a byte. Also, we know it's not null. + __ load_heap_oop_not_null(tmp2, Address(_obj, java_lang_Class::klass_offset_in_bytes())); __ get_thread(tmp); __ cmpptr(tmp, Address(tmp2, instanceKlass::init_thread_offset_in_bytes() + sizeof(klassOopDesc))); __ pop(tmp2); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp --- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -1401,7 +1401,7 @@ default: ShouldNotReachHere(); break; } - } else if (VM_Version::supports_3dnow()) { + } else if (VM_Version::supports_3dnow_prefetch()) { __ prefetchr(from_addr); } } @@ -1424,7 +1424,7 @@ default: ShouldNotReachHere(); break; } - } else if (VM_Version::supports_3dnow()) { + } else if (VM_Version::supports_3dnow_prefetch()) { __ prefetchw(from_addr); } } @@ -3102,7 +3102,7 @@ BasicType basic_type = default_type != NULL ? default_type->element_type()->basic_type() : T_ILLEGAL; if (basic_type == T_ARRAY) basic_type = T_OBJECT; - // if we don't know anything or it's an object array, just go through the generic arraycopy + // if we don't know anything, just go through the generic arraycopy if (default_type == NULL) { Label done; // save outgoing arguments on stack in case call to System.arraycopy is needed @@ -3123,7 +3123,9 @@ store_parameter(src, 4); NOT_LP64(assert(src == rcx && src_pos == rdx, "mismatch in calling convention");) - address entry = CAST_FROM_FN_PTR(address, Runtime1::arraycopy); + address C_entry = CAST_FROM_FN_PTR(address, Runtime1::arraycopy); + + address copyfunc_addr = StubRoutines::generic_arraycopy(); // pass arguments: may push as this is not a safepoint; SP must be fix at each safepoint #ifdef _LP64 @@ -3141,11 +3143,29 @@ // Allocate abi space for args but be sure to keep stack aligned __ subptr(rsp, 6*wordSize); store_parameter(j_rarg4, 4); - __ call(RuntimeAddress(entry)); + if (copyfunc_addr == NULL) { // Use C version if stub was not generated + __ call(RuntimeAddress(C_entry)); + } else { +#ifndef PRODUCT + if (PrintC1Statistics) { + __ incrementl(ExternalAddress((address)&Runtime1::_generic_arraycopystub_cnt)); + } +#endif + __ call(RuntimeAddress(copyfunc_addr)); + } __ addptr(rsp, 6*wordSize); #else __ mov(c_rarg4, j_rarg4); - __ call(RuntimeAddress(entry)); + if (copyfunc_addr == NULL) { // Use C version if stub was not generated + __ call(RuntimeAddress(C_entry)); + } else { +#ifndef PRODUCT + if (PrintC1Statistics) { + __ incrementl(ExternalAddress((address)&Runtime1::_generic_arraycopystub_cnt)); + } +#endif + __ call(RuntimeAddress(copyfunc_addr)); + } #endif // _WIN64 #else __ push(length); @@ -3153,13 +3173,28 @@ __ push(dst); __ push(src_pos); __ push(src); - __ call_VM_leaf(entry, 5); // removes pushed parameter from the stack + + if (copyfunc_addr == NULL) { // Use C version if stub was not generated + __ call_VM_leaf(C_entry, 5); // removes pushed parameter from the stack + } else { +#ifndef PRODUCT + if (PrintC1Statistics) { + __ incrementl(ExternalAddress((address)&Runtime1::_generic_arraycopystub_cnt)); + } +#endif + __ call_VM_leaf(copyfunc_addr, 5); // removes pushed parameter from the stack + } #endif // _LP64 __ cmpl(rax, 0); __ jcc(Assembler::equal, *stub->continuation()); + if (copyfunc_addr != NULL) { + __ mov(tmp, rax); + __ xorl(tmp, -1); + } + // Reload values from the stack so they are where the stub // expects them. __ movptr (dst, Address(rsp, 0*BytesPerWord)); @@ -3167,6 +3202,12 @@ __ movptr (length, Address(rsp, 2*BytesPerWord)); __ movptr (src_pos, Address(rsp, 3*BytesPerWord)); __ movptr (src, Address(rsp, 4*BytesPerWord)); + + if (copyfunc_addr != NULL) { + __ subl(length, tmp); + __ addl(src_pos, tmp); + __ addl(dst_pos, tmp); + } __ jmp(*stub->entry()); __ bind(*stub->continuation()); @@ -3226,10 +3267,6 @@ __ testl(dst_pos, dst_pos); __ jcc(Assembler::less, *stub->entry()); } - if (flags & LIR_OpArrayCopy::length_positive_check) { - __ testl(length, length); - __ jcc(Assembler::less, *stub->entry()); - } if (flags & LIR_OpArrayCopy::src_range_check) { __ lea(tmp, Address(src_pos, length, Address::times_1, 0)); @@ -3242,15 +3279,190 @@ __ jcc(Assembler::above, *stub->entry()); } + if (flags & LIR_OpArrayCopy::length_positive_check) { + __ testl(length, length); + __ jcc(Assembler::less, *stub->entry()); + __ jcc(Assembler::zero, *stub->continuation()); + } + +#ifdef _LP64 + __ movl2ptr(src_pos, src_pos); //higher 32bits must be null + __ movl2ptr(dst_pos, dst_pos); //higher 32bits must be null +#endif + if (flags & LIR_OpArrayCopy::type_check) { - if (UseCompressedOops) { - __ movl(tmp, src_klass_addr); - __ cmpl(tmp, dst_klass_addr); + // We don't know the array types are compatible + if (basic_type != T_OBJECT) { + // Simple test for basic type arrays + if (UseCompressedOops) { + __ movl(tmp, src_klass_addr); + __ cmpl(tmp, dst_klass_addr); + } else { + __ movptr(tmp, src_klass_addr); + __ cmpptr(tmp, dst_klass_addr); + } + __ jcc(Assembler::notEqual, *stub->entry()); } else { - __ movptr(tmp, src_klass_addr); - __ cmpptr(tmp, dst_klass_addr); + // For object arrays, if src is a sub class of dst then we can + // safely do the copy. + Label cont, slow; + + __ push(src); + __ push(dst); + + __ load_klass(src, src); + __ load_klass(dst, dst); + + __ check_klass_subtype_fast_path(src, dst, tmp, &cont, &slow, NULL); + + __ push(src); + __ push(dst); + __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); + __ pop(dst); + __ pop(src); + + __ cmpl(src, 0); + __ jcc(Assembler::notEqual, cont); + + __ bind(slow); + __ pop(dst); + __ pop(src); + + address copyfunc_addr = StubRoutines::checkcast_arraycopy(); + if (copyfunc_addr != NULL) { // use stub if available + // src is not a sub class of dst so we have to do a + // per-element check. + + int mask = LIR_OpArrayCopy::src_objarray|LIR_OpArrayCopy::dst_objarray; + if ((flags & mask) != mask) { + // Check that at least both of them object arrays. + assert(flags & mask, "one of the two should be known to be an object array"); + + if (!(flags & LIR_OpArrayCopy::src_objarray)) { + __ load_klass(tmp, src); + } else if (!(flags & LIR_OpArrayCopy::dst_objarray)) { + __ load_klass(tmp, dst); + } + int lh_offset = klassOopDesc::header_size() * HeapWordSize + + Klass::layout_helper_offset_in_bytes(); + Address klass_lh_addr(tmp, lh_offset); + jint objArray_lh = Klass::array_layout_helper(T_OBJECT); + __ cmpl(klass_lh_addr, objArray_lh); + __ jcc(Assembler::notEqual, *stub->entry()); + } + +#ifndef _LP64 + // save caller save registers + store_parameter(rax, 2); + store_parameter(rcx, 1); + store_parameter(rdx, 0); + + __ movptr(tmp, dst_klass_addr); + __ movptr(tmp, Address(tmp, objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc))); + __ push(tmp); + __ movl(tmp, Address(tmp, Klass::super_check_offset_offset_in_bytes() + sizeof(oopDesc))); + __ push(tmp); + __ push(length); + __ lea(tmp, Address(dst, dst_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type))); + __ push(tmp); + __ lea(tmp, Address(src, src_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type))); + __ push(tmp); + + __ call_VM_leaf(copyfunc_addr, 5); +#else + __ movl2ptr(length, length); //higher 32bits must be null + + // save caller save registers: copy them to callee save registers + __ mov(rbx, rdx); + __ mov(r13, r8); + __ mov(r14, r9); +#ifndef _WIN64 + store_parameter(rsi, 1); + store_parameter(rcx, 0); + // on WIN64 other incoming parameters are in rdi and rsi saved + // across the call +#endif + + __ lea(c_rarg0, Address(src, src_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type))); + assert_different_registers(c_rarg0, dst, dst_pos, length); + __ lea(c_rarg1, Address(dst, dst_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type))); + assert_different_registers(c_rarg1, dst, length); + + __ mov(c_rarg2, length); + assert_different_registers(c_rarg2, dst); + +#ifdef _WIN64 + // Allocate abi space for args but be sure to keep stack aligned + __ subptr(rsp, 6*wordSize); + __ load_klass(c_rarg3, dst); + __ movptr(c_rarg3, Address(c_rarg3, objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc))); + store_parameter(c_rarg3, 4); + __ movl(c_rarg3, Address(c_rarg3, Klass::super_check_offset_offset_in_bytes() + sizeof(oopDesc))); + __ call(RuntimeAddress(copyfunc_addr)); + __ addptr(rsp, 6*wordSize); +#else + __ load_klass(c_rarg4, dst); + __ movptr(c_rarg4, Address(c_rarg4, objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc))); + __ movl(c_rarg3, Address(c_rarg4, Klass::super_check_offset_offset_in_bytes() + sizeof(oopDesc))); + __ call(RuntimeAddress(copyfunc_addr)); +#endif + +#endif + +#ifndef PRODUCT + if (PrintC1Statistics) { + Label failed; + __ testl(rax, rax); + __ jcc(Assembler::notZero, failed); + __ incrementl(ExternalAddress((address)&Runtime1::_arraycopy_checkcast_cnt)); + __ bind(failed); + } +#endif + + __ testl(rax, rax); + __ jcc(Assembler::zero, *stub->continuation()); + +#ifndef PRODUCT + if (PrintC1Statistics) { + __ incrementl(ExternalAddress((address)&Runtime1::_arraycopy_checkcast_attempt_cnt)); + } +#endif + + __ mov(tmp, rax); + + __ xorl(tmp, -1); + +#ifndef _LP64 + // restore caller save registers + assert_different_registers(tmp, rdx, rcx, rax); // result of stub will be lost + __ movptr(rdx, Address(rsp, 0*BytesPerWord)); + __ movptr(rcx, Address(rsp, 1*BytesPerWord)); + __ movptr(rax, Address(rsp, 2*BytesPerWord)); +#else + // restore caller save registers + __ mov(rdx, rbx); + __ mov(r8, r13); + __ mov(r9, r14); +#ifndef _WIN64 + assert_different_registers(tmp, rdx, r8, r9, rcx, rsi); // result of stub will be lost + __ movptr(rcx, Address(rsp, 0*BytesPerWord)); + __ movptr(rsi, Address(rsp, 1*BytesPerWord)); +#else + assert_different_registers(tmp, rdx, r8, r9); // result of stub will be lost +#endif +#endif + + __ subl(length, tmp); + __ addl(src_pos, tmp); + __ addl(dst_pos, tmp); + } + + __ jmp(*stub->entry()); + + __ bind(cont); + __ pop(dst); + __ pop(src); } - __ jcc(Assembler::notEqual, *stub->entry()); } #ifdef ASSERT @@ -3291,16 +3503,16 @@ } #endif - if (shift_amount > 0 && basic_type != T_OBJECT) { - __ shlptr(length, shift_amount); +#ifndef PRODUCT + if (PrintC1Statistics) { + __ incrementl(ExternalAddress(Runtime1::arraycopy_count_address(basic_type))); } +#endif #ifdef _LP64 assert_different_registers(c_rarg0, dst, dst_pos, length); - __ movl2ptr(src_pos, src_pos); //higher 32bits must be null __ lea(c_rarg0, Address(src, src_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type))); assert_different_registers(c_rarg1, length); - __ movl2ptr(dst_pos, dst_pos); //higher 32bits must be null __ lea(c_rarg1, Address(dst, dst_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type))); __ mov(c_rarg2, length); @@ -3311,11 +3523,12 @@ store_parameter(tmp, 1); store_parameter(length, 2); #endif // _LP64 - if (basic_type == T_OBJECT) { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, Runtime1::oop_arraycopy), 0); - } else { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, Runtime1::primitive_arraycopy), 0); - } + + bool disjoint = (flags & LIR_OpArrayCopy::overlapping) == 0; + bool aligned = (flags & LIR_OpArrayCopy::unaligned) == 0; + const char *name; + address entry = StubRoutines::select_arraycopy_function(basic_type, aligned, disjoint, name, false); + __ call_VM_leaf(entry, 0); __ bind(*stub->continuation()); } diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/cpu/x86/vm/vm_version_x86.cpp --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -348,7 +348,7 @@ } char buf[256]; - jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", cores_per_cpu(), threads_per_core(), cpu_family(), _model, _stepping, (supports_cmov() ? ", cmov" : ""), @@ -363,8 +363,7 @@ (supports_sse4_2() ? ", sse4.2" : ""), (supports_popcnt() ? ", popcnt" : ""), (supports_mmx_ext() ? ", mmxext" : ""), - (supports_3dnow() ? ", 3dnow" : ""), - (supports_3dnow2() ? ", 3dnowext" : ""), + (supports_3dnow_prefetch() ? ", 3dnowpref" : ""), (supports_lzcnt() ? ", lzcnt": ""), (supports_sse4a() ? ", sse4a": ""), (supports_ht() ? ", ht": "")); @@ -522,13 +521,13 @@ // set valid Prefetch instruction if( ReadPrefetchInstr < 0 ) ReadPrefetchInstr = 0; if( ReadPrefetchInstr > 3 ) ReadPrefetchInstr = 3; - if( ReadPrefetchInstr == 3 && !supports_3dnow() ) ReadPrefetchInstr = 0; - if( !supports_sse() && supports_3dnow() ) ReadPrefetchInstr = 3; + if( ReadPrefetchInstr == 3 && !supports_3dnow_prefetch() ) ReadPrefetchInstr = 0; + if( !supports_sse() && supports_3dnow_prefetch() ) ReadPrefetchInstr = 3; if( AllocatePrefetchInstr < 0 ) AllocatePrefetchInstr = 0; if( AllocatePrefetchInstr > 3 ) AllocatePrefetchInstr = 3; - if( AllocatePrefetchInstr == 3 && !supports_3dnow() ) AllocatePrefetchInstr=0; - if( !supports_sse() && supports_3dnow() ) AllocatePrefetchInstr = 3; + if( AllocatePrefetchInstr == 3 && !supports_3dnow_prefetch() ) AllocatePrefetchInstr=0; + if( !supports_sse() && supports_3dnow_prefetch() ) AllocatePrefetchInstr = 3; // Allocation prefetch settings intx cache_line_size = L1_data_cache_line_size(); @@ -576,10 +575,10 @@ logical_processors_per_package()); tty->print_cr("UseSSE=%d",UseSSE); tty->print("Allocation: "); - if (AllocatePrefetchStyle <= 0 || UseSSE == 0 && !supports_3dnow()) { + if (AllocatePrefetchStyle <= 0 || UseSSE == 0 && !supports_3dnow_prefetch()) { tty->print_cr("no prefetching"); } else { - if (UseSSE == 0 && supports_3dnow()) { + if (UseSSE == 0 && supports_3dnow_prefetch()) { tty->print("PREFETCHW"); } else if (UseSSE >= 1) { if (AllocatePrefetchInstr == 0) { diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/cpu/x86/vm/vm_version_x86.hpp --- a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -188,7 +188,8 @@ CPU_FXSR = (1 << 2), CPU_HT = (1 << 3), CPU_MMX = (1 << 4), - CPU_3DNOW = (1 << 5), // 3DNow comes from cpuid 0x80000001 (EDX) + CPU_3DNOW_PREFETCH = (1 << 5), // Processor supports 3dnow prefetch and prefetchw instructions + // may not necessarily support other 3dnow instructions CPU_SSE = (1 << 6), CPU_SSE2 = (1 << 7), CPU_SSE3 = (1 << 8), // SSE3 comes from cpuid 1 (ECX) @@ -328,8 +329,9 @@ // AMD features. if (is_amd()) { - if (_cpuid_info.ext_cpuid1_edx.bits.tdnow != 0) - result |= CPU_3DNOW; + if ((_cpuid_info.ext_cpuid1_edx.bits.tdnow != 0) || + (_cpuid_info.ext_cpuid1_ecx.bits.prefetchw != 0)) + result |= CPU_3DNOW_PREFETCH; if (_cpuid_info.ext_cpuid1_ecx.bits.lzcnt != 0) result |= CPU_LZCNT; if (_cpuid_info.ext_cpuid1_ecx.bits.sse4a != 0) @@ -446,9 +448,8 @@ // // AMD features // - static bool supports_3dnow() { return (_cpuFeatures & CPU_3DNOW) != 0; } + static bool supports_3dnow_prefetch() { return (_cpuFeatures & CPU_3DNOW_PREFETCH) != 0; } static bool supports_mmx_ext() { return is_amd() && _cpuid_info.ext_cpuid1_edx.bits.mmx_amd != 0; } - static bool supports_3dnow2() { return is_amd() && _cpuid_info.ext_cpuid1_edx.bits.tdnow2 != 0; } static bool supports_lzcnt() { return (_cpuFeatures & CPU_LZCNT) != 0; } static bool supports_sse4a() { return (_cpuFeatures & CPU_SSE4A) != 0; } diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/cpu/x86/vm/x86_32.ad --- a/hotspot/src/cpu/x86/vm/x86_32.ad Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/cpu/x86/vm/x86_32.ad Wed Jul 05 17:41:25 2017 +0200 @@ -3423,7 +3423,7 @@ masm.movptr(boxReg, tmpReg); // consider: LEA box, [tmp-2] // Using a prefetchw helps avoid later RTS->RTO upgrades and cache probes - if ((EmitSync & 2048) && VM_Version::supports_3dnow() && os::is_MP()) { + if ((EmitSync & 2048) && VM_Version::supports_3dnow_prefetch() && os::is_MP()) { // prefetchw [eax + Offset(_owner)-2] masm.prefetchw(Address(rax, ObjectMonitor::owner_offset_in_bytes()-2)); } @@ -3467,7 +3467,7 @@ masm.movptr(boxReg, tmpReg) ; // Using a prefetchw helps avoid later RTS->RTO upgrades and cache probes - if ((EmitSync & 2048) && VM_Version::supports_3dnow() && os::is_MP()) { + if ((EmitSync & 2048) && VM_Version::supports_3dnow_prefetch() && os::is_MP()) { // prefetchw [eax + Offset(_owner)-2] masm.prefetchw(Address(rax, ObjectMonitor::owner_offset_in_bytes()-2)); } @@ -3614,7 +3614,7 @@ // See also http://gee.cs.oswego.edu/dl/jmm/cookbook.html. masm.get_thread (boxReg) ; - if ((EmitSync & 4096) && VM_Version::supports_3dnow() && os::is_MP()) { + if ((EmitSync & 4096) && VM_Version::supports_3dnow_prefetch() && os::is_MP()) { // prefetchw [ebx + Offset(_owner)-2] masm.prefetchw(Address(rbx, ObjectMonitor::owner_offset_in_bytes()-2)); } @@ -7333,7 +7333,7 @@ // Must be safe to execute with invalid address (cannot fault). instruct prefetchr0( memory mem ) %{ - predicate(UseSSE==0 && !VM_Version::supports_3dnow()); + predicate(UseSSE==0 && !VM_Version::supports_3dnow_prefetch()); match(PrefetchRead mem); ins_cost(0); size(0); @@ -7343,7 +7343,7 @@ %} instruct prefetchr( memory mem ) %{ - predicate(UseSSE==0 && VM_Version::supports_3dnow() || ReadPrefetchInstr==3); + predicate(UseSSE==0 && VM_Version::supports_3dnow_prefetch() || ReadPrefetchInstr==3); match(PrefetchRead mem); ins_cost(100); @@ -7387,7 +7387,7 @@ %} instruct prefetchw0( memory mem ) %{ - predicate(UseSSE==0 && !VM_Version::supports_3dnow()); + predicate(UseSSE==0 && !VM_Version::supports_3dnow_prefetch()); match(PrefetchWrite mem); ins_cost(0); size(0); @@ -7397,7 +7397,7 @@ %} instruct prefetchw( memory mem ) %{ - predicate(UseSSE==0 && VM_Version::supports_3dnow() || AllocatePrefetchInstr==3); + predicate(UseSSE==0 && VM_Version::supports_3dnow_prefetch() || AllocatePrefetchInstr==3); match( PrefetchWrite mem ); ins_cost(100); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/cpu/zero/vm/bytecodeInterpreter_zero.hpp --- a/hotspot/src/cpu/zero/vm/bytecodeInterpreter_zero.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/cpu/zero/vm/bytecodeInterpreter_zero.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -1,6 +1,6 @@ /* * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2007, 2008 Red Hat, Inc. + * Copyright 2007, 2008, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -150,4 +150,22 @@ #define SET_LOCALS_LONG_FROM_ADDR(addr, offset) (((VMJavaVal64*)&locals[-((offset)+1)])->l = \ ((VMJavaVal64*)(addr))->l) +// VMSlots implementation + +#define VMSLOTS_SLOT(offset) ((intptr_t*)&vmslots[(offset)]) +#define VMSLOTS_ADDR(offset) ((address)vmslots[(offset)]) +#define VMSLOTS_INT(offset) (*((jint*)&vmslots[(offset)])) +#define VMSLOTS_FLOAT(offset) (*((jfloat*)&vmslots[(offset)])) +#define VMSLOTS_OBJECT(offset) ((oop)vmslots[(offset)]) +#define VMSLOTS_DOUBLE(offset) (((VMJavaVal64*)&vmslots[(offset) - 1])->d) +#define VMSLOTS_LONG(offset) (((VMJavaVal64*)&vmslots[(offset) - 1])->l) + +#define SET_VMSLOTS_SLOT(value, offset) (*(intptr_t*)&vmslots[(offset)] = *(intptr_t *)(value)) +#define SET_VMSLOTS_ADDR(value, offset) (*((address *)&vmslots[(offset)]) = (value)) +#define SET_VMSLOTS_INT(value, offset) (*((jint *)&vmslots[(offset)]) = (value)) +#define SET_VMSLOTS_FLOAT(value, offset) (*((jfloat *)&vmslots[(offset)]) = (value)) +#define SET_VMSLOTS_OBJECT(value, offset) (*((oop *)&vmslots[(offset)]) = (value)) +#define SET_VMSLOTS_DOUBLE(value, offset) (((VMJavaVal64*)&vmslots[(offset) - 1])->d = (value)) +#define SET_VMSLOTS_LONG(value, offset) (((VMJavaVal64*)&vmslots[(offset) - 1])->l = (value)) + #endif // CPU_ZERO_VM_BYTECODEINTERPRETER_ZERO_HPP diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp --- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -1,6 +1,6 @@ /* * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. - * Copyright 2007, 2008, 2009, 2010 Red Hat, Inc. + * Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,10 +56,13 @@ #define fixup_after_potential_safepoint() \ method = istate->method() -#define CALL_VM_NOCHECK(func) \ +#define CALL_VM_NOCHECK_NOFIX(func) \ thread->set_last_Java_frame(); \ func; \ - thread->reset_last_Java_frame(); \ + thread->reset_last_Java_frame(); + +#define CALL_VM_NOCHECK(func) \ + CALL_VM_NOCHECK_NOFIX(func) \ fixup_after_potential_safepoint() int CppInterpreter::normal_entry(methodOop method, intptr_t UNUSED, TRAPS) { @@ -177,6 +180,25 @@ method, istate->osr_entry(), istate->osr_buf(), THREAD); return; } + else if (istate->msg() == BytecodeInterpreter::call_method_handle) { + oop method_handle = istate->callee(); + + // Trim back the stack to put the parameters at the top + stack->set_sp(istate->stack() + 1); + + // Make the call + process_method_handle(method_handle, THREAD); + fixup_after_potential_safepoint(); + + // Convert the result + istate->set_stack(stack->sp() - 1); + + // Restore the stack + stack->set_sp(istate->stack_limit() + 1); + + // Resume the interpreter + istate->set_msg(BytecodeInterpreter::method_resume); + } else { ShouldNotReachHere(); } @@ -607,6 +629,549 @@ return 0; } +int CppInterpreter::method_handle_entry(methodOop method, + intptr_t UNUSED, TRAPS) { + JavaThread *thread = (JavaThread *) THREAD; + ZeroStack *stack = thread->zero_stack(); + int argument_slots = method->size_of_parameters(); + int result_slots = type2size[result_type_of(method)]; + intptr_t *vmslots = stack->sp(); + intptr_t *unwind_sp = vmslots + argument_slots; + + // Find the MethodType + address p = (address) method; + for (jint* pc = method->method_type_offsets_chain(); (*pc) != -1; pc++) { + p = *(address*)(p + (*pc)); + } + oop method_type = (oop) p; + + // The MethodHandle is in the slot after the arguments + oop form = java_lang_invoke_MethodType::form(method_type); + int num_vmslots = java_lang_invoke_MethodTypeForm::vmslots(form); + assert(argument_slots == num_vmslots + 1, "should be"); + oop method_handle = VMSLOTS_OBJECT(num_vmslots); + + // InvokeGeneric requires some extra shuffling + oop mhtype = java_lang_invoke_MethodHandle::type(method_handle); + bool is_exact = mhtype == method_type; + if (!is_exact) { + if (method->intrinsic_id() == vmIntrinsics::_invokeExact) { + CALL_VM_NOCHECK_NOFIX( + InterpreterRuntime::throw_WrongMethodTypeException( + thread, method_type, mhtype)); + // NB all oops trashed! + assert(HAS_PENDING_EXCEPTION, "should do"); + stack->set_sp(unwind_sp); + return 0; + } + assert(method->intrinsic_id() == vmIntrinsics::_invokeGeneric, "should be"); + + // Load up an adapter from the calling type + // NB the x86 code for this (in methodHandles_x86.cpp, search for + // "genericInvoker") is really really odd. I'm hoping it's trying + // to accomodate odd VM/class library combinations I can ignore. + oop adapter = java_lang_invoke_MethodTypeForm::genericInvoker(form); + if (adapter == NULL) { + CALL_VM_NOCHECK_NOFIX( + InterpreterRuntime::throw_WrongMethodTypeException( + thread, method_type, mhtype)); + // NB all oops trashed! + assert(HAS_PENDING_EXCEPTION, "should do"); + stack->set_sp(unwind_sp); + return 0; + } + + // Adapters are shared among form-families of method-type. The + // type being called is passed as a trusted first argument so that + // the adapter knows the actual types of its arguments and return + // values. + insert_vmslots(num_vmslots + 1, 1, THREAD); + if (HAS_PENDING_EXCEPTION) { + // NB all oops trashed! + stack->set_sp(unwind_sp); + return 0; + } + + vmslots = stack->sp(); + num_vmslots++; + SET_VMSLOTS_OBJECT(method_type, num_vmslots); + + method_handle = adapter; + } + + // Start processing + process_method_handle(method_handle, THREAD); + if (HAS_PENDING_EXCEPTION) + result_slots = 0; + + // If this is an invokeExact then the eventual callee will not + // have unwound the method handle argument so we have to do it. + // If a result is being returned the it will be above the method + // handle argument we're unwinding. + if (is_exact) { + intptr_t result[2]; + for (int i = 0; i < result_slots; i++) + result[i] = stack->pop(); + stack->pop(); + for (int i = result_slots - 1; i >= 0; i--) + stack->push(result[i]); + } + + // Check + assert(stack->sp() == unwind_sp - result_slots, "should be"); + + // No deoptimized frames on the stack + return 0; +} + +void CppInterpreter::process_method_handle(oop method_handle, TRAPS) { + JavaThread *thread = (JavaThread *) THREAD; + ZeroStack *stack = thread->zero_stack(); + intptr_t *vmslots = stack->sp(); + + bool direct_to_method = false; + BasicType src_rtype = T_ILLEGAL; + BasicType dst_rtype = T_ILLEGAL; + + MethodHandleEntry *entry = + java_lang_invoke_MethodHandle::vmentry(method_handle); + MethodHandles::EntryKind entry_kind = + (MethodHandles::EntryKind) (((intptr_t) entry) & 0xffffffff); + + methodOop method = NULL; + switch (entry_kind) { + case MethodHandles::_invokestatic_mh: + direct_to_method = true; + break; + + case MethodHandles::_invokespecial_mh: + case MethodHandles::_invokevirtual_mh: + case MethodHandles::_invokeinterface_mh: + { + oop receiver = + VMSLOTS_OBJECT( + java_lang_invoke_MethodHandle::vmslots(method_handle) - 1); + if (receiver == NULL) { + stack->set_sp(calculate_unwind_sp(stack, method_handle)); + CALL_VM_NOCHECK_NOFIX( + throw_exception( + thread, vmSymbols::java_lang_NullPointerException())); + // NB all oops trashed! + assert(HAS_PENDING_EXCEPTION, "should do"); + return; + } + if (entry_kind != MethodHandles::_invokespecial_mh) { + int index = java_lang_invoke_DirectMethodHandle::vmindex(method_handle); + instanceKlass* rcvrKlass = + (instanceKlass *) receiver->klass()->klass_part(); + if (entry_kind == MethodHandles::_invokevirtual_mh) { + method = (methodOop) rcvrKlass->start_of_vtable()[index]; + } + else { + oop iclass = java_lang_invoke_MethodHandle::vmtarget(method_handle); + itableOffsetEntry* ki = + (itableOffsetEntry *) rcvrKlass->start_of_itable(); + int i, length = rcvrKlass->itable_length(); + for (i = 0; i < length; i++, ki++ ) { + if (ki->interface_klass() == iclass) + break; + } + if (i == length) { + stack->set_sp(calculate_unwind_sp(stack, method_handle)); + CALL_VM_NOCHECK_NOFIX( + throw_exception( + thread, vmSymbols::java_lang_IncompatibleClassChangeError())); + // NB all oops trashed! + assert(HAS_PENDING_EXCEPTION, "should do"); + return; + } + itableMethodEntry* im = ki->first_method_entry(receiver->klass()); + method = im[index].method(); + if (method == NULL) { + stack->set_sp(calculate_unwind_sp(stack, method_handle)); + CALL_VM_NOCHECK_NOFIX( + throw_exception( + thread, vmSymbols::java_lang_AbstractMethodError())); + // NB all oops trashed! + assert(HAS_PENDING_EXCEPTION, "should do"); + return; + } + } + } + } + direct_to_method = true; + break; + + case MethodHandles::_bound_ref_direct_mh: + case MethodHandles::_bound_int_direct_mh: + case MethodHandles::_bound_long_direct_mh: + direct_to_method = true; + // fall through + case MethodHandles::_bound_ref_mh: + case MethodHandles::_bound_int_mh: + case MethodHandles::_bound_long_mh: + { + BasicType arg_type = T_ILLEGAL; + int arg_mask = -1; + int arg_slots = -1; + MethodHandles::get_ek_bound_mh_info( + entry_kind, arg_type, arg_mask, arg_slots); + int arg_slot = + java_lang_invoke_BoundMethodHandle::vmargslot(method_handle); + + // Create the new slot(s) + intptr_t *unwind_sp = calculate_unwind_sp(stack, method_handle); + insert_vmslots(arg_slot, arg_slots, THREAD); + if (HAS_PENDING_EXCEPTION) { + // all oops trashed + stack->set_sp(unwind_sp); + return; + } + vmslots = stack->sp(); + + // Store bound argument into new stack slot + oop arg = java_lang_invoke_BoundMethodHandle::argument(method_handle); + if (arg_type == T_OBJECT) { + assert(arg_slots == 1, "should be"); + SET_VMSLOTS_OBJECT(arg, arg_slot); + } + else { + jvalue arg_value; + arg_type = java_lang_boxing_object::get_value(arg, &arg_value); + switch (arg_type) { + case T_BOOLEAN: + SET_VMSLOTS_INT(arg_value.z, arg_slot); + break; + case T_CHAR: + SET_VMSLOTS_INT(arg_value.c, arg_slot); + break; + case T_BYTE: + SET_VMSLOTS_INT(arg_value.b, arg_slot); + break; + case T_SHORT: + SET_VMSLOTS_INT(arg_value.s, arg_slot); + break; + case T_INT: + SET_VMSLOTS_INT(arg_value.i, arg_slot); + break; + case T_FLOAT: + SET_VMSLOTS_FLOAT(arg_value.f, arg_slot); + break; + case T_LONG: + SET_VMSLOTS_LONG(arg_value.j, arg_slot + 1); + break; + case T_DOUBLE: + SET_VMSLOTS_DOUBLE(arg_value.d, arg_slot + 1); + break; + default: + tty->print_cr("unhandled type %s", type2name(arg_type)); + ShouldNotReachHere(); + } + } + } + break; + + case MethodHandles::_adapter_retype_only: + case MethodHandles::_adapter_retype_raw: + src_rtype = result_type_of_handle( + java_lang_invoke_MethodHandle::vmtarget(method_handle)); + dst_rtype = result_type_of_handle(method_handle); + break; + + case MethodHandles::_adapter_check_cast: + { + int arg_slot = + java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle); + oop arg = VMSLOTS_OBJECT(arg_slot); + if (arg != NULL) { + klassOop objKlassOop = arg->klass(); + klassOop klassOf = java_lang_Class::as_klassOop( + java_lang_invoke_AdapterMethodHandle::argument(method_handle)); + + if (objKlassOop != klassOf && + !objKlassOop->klass_part()->is_subtype_of(klassOf)) { + ResourceMark rm(THREAD); + const char* objName = Klass::cast(objKlassOop)->external_name(); + const char* klassName = Klass::cast(klassOf)->external_name(); + char* message = SharedRuntime::generate_class_cast_message( + objName, klassName); + + stack->set_sp(calculate_unwind_sp(stack, method_handle)); + CALL_VM_NOCHECK_NOFIX( + throw_exception( + thread, vmSymbols::java_lang_ClassCastException(), message)); + // NB all oops trashed! + assert(HAS_PENDING_EXCEPTION, "should do"); + return; + } + } + } + break; + + case MethodHandles::_adapter_dup_args: + { + int arg_slot = + java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle); + int conv = + java_lang_invoke_AdapterMethodHandle::conversion(method_handle); + int num_slots = -MethodHandles::adapter_conversion_stack_move(conv); + assert(num_slots > 0, "should be"); + + // Create the new slot(s) + intptr_t *unwind_sp = calculate_unwind_sp(stack, method_handle); + stack->overflow_check(num_slots, THREAD); + if (HAS_PENDING_EXCEPTION) { + // all oops trashed + stack->set_sp(unwind_sp); + return; + } + + // Duplicate the arguments + for (int i = num_slots - 1; i >= 0; i--) + stack->push(*VMSLOTS_SLOT(arg_slot + i)); + + vmslots = stack->sp(); // unused, but let the compiler figure that out + } + break; + + case MethodHandles::_adapter_drop_args: + { + int arg_slot = + java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle); + int conv = + java_lang_invoke_AdapterMethodHandle::conversion(method_handle); + int num_slots = MethodHandles::adapter_conversion_stack_move(conv); + assert(num_slots > 0, "should be"); + + remove_vmslots(arg_slot, num_slots, THREAD); // doesn't trap + vmslots = stack->sp(); // unused, but let the compiler figure that out + } + break; + + case MethodHandles::_adapter_opt_swap_1: + case MethodHandles::_adapter_opt_swap_2: + case MethodHandles::_adapter_opt_rot_1_up: + case MethodHandles::_adapter_opt_rot_1_down: + case MethodHandles::_adapter_opt_rot_2_up: + case MethodHandles::_adapter_opt_rot_2_down: + { + int arg1 = + java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle); + int conv = + java_lang_invoke_AdapterMethodHandle::conversion(method_handle); + int arg2 = MethodHandles::adapter_conversion_vminfo(conv); + + int swap_bytes = 0, rotate = 0; + MethodHandles::get_ek_adapter_opt_swap_rot_info( + entry_kind, swap_bytes, rotate); + int swap_slots = swap_bytes >> LogBytesPerWord; + + intptr_t tmp; + switch (rotate) { + case 0: // swap + for (int i = 0; i < swap_slots; i++) { + tmp = *VMSLOTS_SLOT(arg1 + i); + SET_VMSLOTS_SLOT(VMSLOTS_SLOT(arg2 + i), arg1 + i); + SET_VMSLOTS_SLOT(&tmp, arg2 + i); + } + break; + + case 1: // up + assert(arg1 - swap_slots > arg2, "should be"); + + tmp = *VMSLOTS_SLOT(arg1); + for (int i = arg1 - swap_slots; i >= arg2; i--) + SET_VMSLOTS_SLOT(VMSLOTS_SLOT(i), i + swap_slots); + SET_VMSLOTS_SLOT(&tmp, arg2); + + break; + + case -1: // down + assert(arg2 - swap_slots > arg1, "should be"); + + tmp = *VMSLOTS_SLOT(arg1); + for (int i = arg1 + swap_slots; i <= arg2; i++) + SET_VMSLOTS_SLOT(VMSLOTS_SLOT(i), i - swap_slots); + SET_VMSLOTS_SLOT(&tmp, arg2); + break; + + default: + ShouldNotReachHere(); + } + } + break; + + case MethodHandles::_adapter_opt_i2l: + { + int arg_slot = + java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle); + int arg = VMSLOTS_INT(arg_slot); + intptr_t *unwind_sp = calculate_unwind_sp(stack, method_handle); + insert_vmslots(arg_slot, 1, THREAD); + if (HAS_PENDING_EXCEPTION) { + // all oops trashed + stack->set_sp(unwind_sp); + return; + } + vmslots = stack->sp(); + arg_slot++; + SET_VMSLOTS_LONG(arg, arg_slot); + } + break; + + case MethodHandles::_adapter_opt_unboxi: + case MethodHandles::_adapter_opt_unboxl: + { + int arg_slot = + java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle); + oop arg = VMSLOTS_OBJECT(arg_slot); + jvalue arg_value; + BasicType arg_type = java_lang_boxing_object::get_value(arg, &arg_value); + if (arg_type == T_LONG || arg_type == T_DOUBLE) { + intptr_t *unwind_sp = calculate_unwind_sp(stack, method_handle); + insert_vmslots(arg_slot, 1, THREAD); + if (HAS_PENDING_EXCEPTION) { + // all oops trashed + stack->set_sp(unwind_sp); + return; + } + vmslots = stack->sp(); + arg_slot++; + } + switch (arg_type) { + case T_BOOLEAN: + SET_VMSLOTS_INT(arg_value.z, arg_slot); + break; + case T_CHAR: + SET_VMSLOTS_INT(arg_value.c, arg_slot); + break; + case T_BYTE: + SET_VMSLOTS_INT(arg_value.b, arg_slot); + break; + case T_SHORT: + SET_VMSLOTS_INT(arg_value.s, arg_slot); + break; + case T_INT: + SET_VMSLOTS_INT(arg_value.i, arg_slot); + break; + case T_FLOAT: + SET_VMSLOTS_FLOAT(arg_value.f, arg_slot); + break; + case T_LONG: + SET_VMSLOTS_LONG(arg_value.j, arg_slot); + break; + case T_DOUBLE: + SET_VMSLOTS_DOUBLE(arg_value.d, arg_slot); + break; + default: + tty->print_cr("unhandled type %s", type2name(arg_type)); + ShouldNotReachHere(); + } + } + break; + + default: + tty->print_cr("unhandled entry_kind %s", + MethodHandles::entry_name(entry_kind)); + ShouldNotReachHere(); + } + + // Continue along the chain + if (direct_to_method) { + if (method == NULL) { + method = + (methodOop) java_lang_invoke_MethodHandle::vmtarget(method_handle); + } + address entry_point = method->from_interpreted_entry(); + Interpreter::invoke_method(method, entry_point, THREAD); + } + else { + process_method_handle( + java_lang_invoke_MethodHandle::vmtarget(method_handle), THREAD); + } + // NB all oops now trashed + + // Adapt the result type, if necessary + if (src_rtype != dst_rtype && !HAS_PENDING_EXCEPTION) { + switch (dst_rtype) { + case T_VOID: + for (int i = 0; i < type2size[src_rtype]; i++) + stack->pop(); + return; + + case T_INT: + switch (src_rtype) { + case T_VOID: + stack->overflow_check(1, CHECK); + stack->push(0); + return; + + case T_BOOLEAN: + case T_CHAR: + case T_BYTE: + case T_SHORT: + return; + } + } + + tty->print_cr("unhandled conversion:"); + tty->print_cr("src_rtype = %s", type2name(src_rtype)); + tty->print_cr("dst_rtype = %s", type2name(dst_rtype)); + ShouldNotReachHere(); + } +} + +// The new slots will be inserted before slot insert_before. +// Slots < insert_before will have the same slot number after the insert. +// Slots >= insert_before will become old_slot + num_slots. +void CppInterpreter::insert_vmslots(int insert_before, int num_slots, TRAPS) { + JavaThread *thread = (JavaThread *) THREAD; + ZeroStack *stack = thread->zero_stack(); + + // Allocate the space + stack->overflow_check(num_slots, CHECK); + stack->alloc(num_slots * wordSize); + intptr_t *vmslots = stack->sp(); + + // Shuffle everything up + for (int i = 0; i < insert_before; i++) + SET_VMSLOTS_SLOT(VMSLOTS_SLOT(i + num_slots), i); +} + +void CppInterpreter::remove_vmslots(int first_slot, int num_slots, TRAPS) { + JavaThread *thread = (JavaThread *) THREAD; + ZeroStack *stack = thread->zero_stack(); + intptr_t *vmslots = stack->sp(); + + // Move everything down + for (int i = first_slot - 1; i >= 0; i--) + SET_VMSLOTS_SLOT(VMSLOTS_SLOT(i), i + num_slots); + + // Deallocate the space + stack->set_sp(stack->sp() + num_slots); +} + +BasicType CppInterpreter::result_type_of_handle(oop method_handle) { + oop method_type = java_lang_invoke_MethodHandle::type(method_handle); + oop return_type = java_lang_invoke_MethodType::rtype(method_type); + return java_lang_Class::as_BasicType(return_type, (klassOop *) NULL); +} + +intptr_t* CppInterpreter::calculate_unwind_sp(ZeroStack* stack, + oop method_handle) { + oop method_type = java_lang_invoke_MethodHandle::type(method_handle); + oop form = java_lang_invoke_MethodType::form(method_type); + int argument_slots = java_lang_invoke_MethodTypeForm::vmslots(form); + + return stack->sp() + argument_slots; +} + +IRT_ENTRY(void, CppInterpreter::throw_exception(JavaThread* thread, + Symbol* name, + char* message)) + THROW_MSG(name, message); +IRT_END + InterpreterFrame *InterpreterFrame::build(const methodOop method, TRAPS) { JavaThread *thread = (JavaThread *) THREAD; ZeroStack *stack = thread->zero_stack(); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/cpu/zero/vm/cppInterpreter_zero.hpp --- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2007, 2008, 2010 Red Hat, Inc. + * Copyright 2007, 2008, 2010, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,12 +36,22 @@ static int native_entry(methodOop method, intptr_t UNUSED, TRAPS); static int accessor_entry(methodOop method, intptr_t UNUSED, TRAPS); static int empty_entry(methodOop method, intptr_t UNUSED, TRAPS); + static int method_handle_entry(methodOop method, intptr_t UNUSED, TRAPS); public: // Main loop of normal_entry static void main_loop(int recurse, TRAPS); private: + // Helpers for method_handle_entry + static void process_method_handle(oop method_handle, TRAPS); + static void insert_vmslots(int insert_before, int num_slots, TRAPS); + static void remove_vmslots(int first_slot, int num_slots, TRAPS); + static BasicType result_type_of_handle(oop method_handle); + static intptr_t* calculate_unwind_sp(ZeroStack* stack, oop method_handle); + static void throw_exception(JavaThread* thread, Symbol* name,char *msg=NULL); + + private: // Fast result type determination static BasicType result_type_of(methodOop method); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/cpu/zero/vm/globals_zero.hpp --- a/hotspot/src/cpu/zero/vm/globals_zero.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/cpu/zero/vm/globals_zero.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -1,6 +1,6 @@ /* * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2007, 2008, 2009, 2010 Red Hat, Inc. + * Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,4 +54,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_ZERO_VM_GLOBALS_ZERO_HPP diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/cpu/zero/vm/interpreter_zero.cpp --- a/hotspot/src/cpu/zero/vm/interpreter_zero.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/cpu/zero/vm/interpreter_zero.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -1,6 +1,6 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2007, 2008, 2009, 2010 Red Hat, Inc. + * Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,6 +49,9 @@ #ifdef COMPILER1 #include "c1/c1_Runtime1.hpp" #endif +#ifdef CC_INTERP +#include "interpreter/cppInterpreter.hpp" +#endif address AbstractInterpreterGenerator::generate_slow_signature_handler() { _masm->advance(1); @@ -64,11 +67,15 @@ } address InterpreterGenerator::generate_abstract_entry() { - return ShouldNotCallThisEntry(); + return generate_entry((address) ShouldNotCallThisEntry()); } address InterpreterGenerator::generate_method_handle_entry() { - return ShouldNotCallThisEntry(); +#ifdef CC_INTERP + return generate_entry((address) CppInterpreter::method_handle_entry); +#else + return generate_entry((address) ShouldNotCallThisEntry()); +#endif // CC_INTERP } bool AbstractInterpreter::can_be_compiled(methodHandle m) { diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/cpu/zero/vm/methodHandles_zero.cpp --- a/hotspot/src/cpu/zero/vm/methodHandles_zero.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/cpu/zero/vm/methodHandles_zero.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2009, 2010 Red Hat, Inc. + * Copyright 2009, 2010, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,10 +29,21 @@ #include "prims/methodHandles.hpp" int MethodHandles::adapter_conversion_ops_supported_mask() { - ShouldNotCallThis(); + return ((1<generate_native_wrapper(masm, method, - in_sig_bt, + compile_id, + sig_bt, ret_type); #else ShouldNotCallThis(); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/os/linux/vm/os_linux.cpp --- a/hotspot/src/os/linux/vm/os_linux.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/os/linux/vm/os_linux.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -2648,45 +2648,39 @@ // writing thread stacks don't use growable mappings (i.e. those // creeated with MAP_GROWSDOWN), and aren't marked "[stack]", so this // only applies to the main thread. -static bool -get_stack_bounds(uintptr_t *bottom, uintptr_t *top) -{ - FILE *f = fopen("/proc/self/maps", "r"); - if (f == NULL) + +static +bool get_stack_bounds(uintptr_t *bottom, uintptr_t *top) { + + char buf[128]; + int fd, sz; + + if ((fd = ::open("/proc/self/maps", O_RDONLY)) < 0) { return false; - - while (!feof(f)) { - size_t dummy; - char *str = NULL; - ssize_t len = getline(&str, &dummy, f); - if (len == -1) { - fclose(f); - return false; - } - - if (len > 0 && str[len-1] == '\n') { - str[len-1] = 0; - len--; - } - - static const char *stack_str = "[stack]"; - if (len > (ssize_t)strlen(stack_str) - && (strcmp(str + len - strlen(stack_str), stack_str) == 0)) { - if (sscanf(str, "%" SCNxPTR "-%" SCNxPTR, bottom, top) == 2) { - uintptr_t sp = (uintptr_t)__builtin_frame_address(0); - if (sp >= *bottom && sp <= *top) { - free(str); - fclose(f); - return true; + } + + const char kw[] = "[stack]"; + const int kwlen = sizeof(kw)-1; + + // Address part of /proc/self/maps couldn't be more than 128 bytes + while ((sz = os::get_line_chars(fd, buf, sizeof(buf))) > 0) { + if (sz > kwlen && ::memcmp(buf+sz-kwlen, kw, kwlen) == 0) { + // Extract addresses + if (sscanf(buf, "%" SCNxPTR "-%" SCNxPTR, bottom, top) == 2) { + uintptr_t sp = (uintptr_t) __builtin_frame_address(0); + if (sp >= *bottom && sp <= *top) { + ::close(fd); + return true; + } } - } - } - free(str); + } } - fclose(f); + + ::close(fd); return false; } + // If the (growable) stack mapping already extends beyond the point // where we're going to put our guard pages, truncate the mapping at // that point by munmap()ping it. This ensures that when we later diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/tools/ProjectCreator/WinGammaPlatformVC10.java --- a/hotspot/src/share/tools/ProjectCreator/WinGammaPlatformVC10.java Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/tools/ProjectCreator/WinGammaPlatformVC10.java Wed Jul 05 17:41:25 2017 +0200 @@ -497,6 +497,9 @@ addAttr(rv, "TargetMachine", "MachineX64"); } + // We always want the /DEBUG option to get full symbol information in the pdb files + addAttr(rv, "GenerateDebugInformation", "true"); + return rv; } @@ -504,8 +507,7 @@ Vector getDebugLinkerFlags() { Vector rv = new Vector(); - // /DEBUG option - addAttr(rv, "GenerateDebugInformation", "true"); + // Empty now that /DEBUG option is used by all configs return rv; } diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/c1/c1_GraphBuilder.cpp --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -2824,7 +2824,7 @@ int idx = 0; if (!method()->is_static()) { // we should always see the receiver - state->store_local(idx, new Local(objectType, idx)); + state->store_local(idx, new Local(method()->holder(), objectType, idx)); idx = 1; } @@ -2836,7 +2836,7 @@ // don't allow T_ARRAY to propagate into locals types if (basic_type == T_ARRAY) basic_type = T_OBJECT; ValueType* vt = as_ValueType(basic_type); - state->store_local(idx, new Local(vt, idx)); + state->store_local(idx, new Local(type, vt, idx)); idx += type->size(); } diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/c1/c1_Instruction.cpp --- a/hotspot/src/share/vm/c1/c1_Instruction.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/c1/c1_Instruction.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -135,6 +135,33 @@ } +ciType* Local::exact_type() const { + ciType* type = declared_type(); + + // for primitive arrays, the declared type is the exact type + if (type->is_type_array_klass()) { + return type; + } else if (type->is_instance_klass()) { + ciInstanceKlass* ik = (ciInstanceKlass*)type; + if (ik->is_loaded() && ik->is_final() && !ik->is_interface()) { + return type; + } + } else if (type->is_obj_array_klass()) { + ciObjArrayKlass* oak = (ciObjArrayKlass*)type; + ciType* base = oak->base_element_type(); + if (base->is_instance_klass()) { + ciInstanceKlass* ik = base->as_instance_klass(); + if (ik->is_loaded() && ik->is_final()) { + return type; + } + } else if (base->is_primitive_type()) { + return type; + } + } + return NULL; +} + + ciType* LoadIndexed::exact_type() const { ciType* array_type = array()->exact_type(); if (array_type == NULL) { @@ -189,16 +216,21 @@ return ciTypeArrayKlass::make(elt_type()); } - ciType* NewObjectArray::exact_type() const { return ciObjArrayKlass::make(klass()); } +ciType* NewArray::declared_type() const { + return exact_type(); +} ciType* NewInstance::exact_type() const { return klass(); } +ciType* NewInstance::declared_type() const { + return exact_type(); +} ciType* CheckCast::declared_type() const { return klass(); @@ -349,6 +381,11 @@ if (state() != NULL) state()->values_do(f); } +ciType* Invoke::declared_type() const { + ciType *t = _target->signature()->return_type(); + assert(t->basic_type() != T_VOID, "need return value of void method?"); + return t; +} // Implementation of Contant intx Constant::hash() const { diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/c1/c1_Instruction.hpp --- a/hotspot/src/share/vm/c1/c1_Instruction.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/c1/c1_Instruction.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -621,16 +621,21 @@ LEAF(Local, Instruction) private: int _java_index; // the local index within the method to which the local belongs + ciType* _declared_type; public: // creation - Local(ValueType* type, int index) + Local(ciType* declared, ValueType* type, int index) : Instruction(type) , _java_index(index) + , _declared_type(declared) {} // accessors int java_index() const { return _java_index; } + ciType* declared_type() const { return _declared_type; } + ciType* exact_type() const; + // generic virtual void input_values_do(ValueVisitor* f) { /* no values */ } }; @@ -1146,6 +1151,8 @@ BasicTypeList* signature() const { return _signature; } ciMethod* target() const { return _target; } + ciType* declared_type() const; + // Returns false if target is not loaded bool target_is_final() const { return check_flag(TargetIsFinalFlag); } bool target_is_loaded() const { return check_flag(TargetIsLoadedFlag); } @@ -1187,6 +1194,7 @@ // generic virtual bool can_trap() const { return true; } ciType* exact_type() const; + ciType* declared_type() const; }; @@ -1208,6 +1216,8 @@ virtual bool needs_exception_state() const { return false; } + ciType* declared_type() const; + // generic virtual bool can_trap() const { return true; } virtual void input_values_do(ValueVisitor* f) { StateSplit::input_values_do(f); f->visit(&_length); } @@ -1397,6 +1407,7 @@ vmIntrinsics::ID _id; Values* _args; Value _recv; + int _nonnull_state; // mask identifying which args are nonnull public: // preserves_state can be set to true for Intrinsics @@ -1417,6 +1428,7 @@ , _id(id) , _args(args) , _recv(NULL) + , _nonnull_state(AllBits) { assert(args != NULL, "args must exist"); ASSERT_VALUES @@ -1442,6 +1454,23 @@ Value receiver() const { assert(has_receiver(), "must have receiver"); return _recv; } bool preserves_state() const { return check_flag(PreservesStateFlag); } + bool arg_needs_null_check(int i) { + if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) { + return is_set_nth_bit(_nonnull_state, i); + } + return true; + } + + void set_arg_needs_null_check(int i, bool check) { + if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) { + if (check) { + _nonnull_state |= nth_bit(i); + } else { + _nonnull_state &= ~(nth_bit(i)); + } + } + } + // generic virtual bool can_trap() const { return check_flag(CanTrapFlag); } virtual void input_values_do(ValueVisitor* f) { diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/c1/c1_LIR.hpp --- a/hotspot/src/share/vm/c1/c1_LIR.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/c1/c1_LIR.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -1215,7 +1215,11 @@ src_range_check = 1 << 5, dst_range_check = 1 << 6, type_check = 1 << 7, - all_flags = (1 << 8) - 1 + overlapping = 1 << 8, + unaligned = 1 << 9, + src_objarray = 1 << 10, + dst_objarray = 1 << 11, + all_flags = (1 << 12) - 1 }; LIR_OpArrayCopy(LIR_Opr src, LIR_Opr src_pos, LIR_Opr dst, LIR_Opr dst_pos, LIR_Opr length, LIR_Opr tmp, diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/c1/c1_LIRAssembler.cpp --- a/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -836,6 +836,9 @@ _masm->verify_stack_oop(r->reg2stack() * VMRegImpl::stack_slot_size); } } + check_codespace(); + CHECK_BAILOUT(); + s.next(); } VerifyOops = v; diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/c1/c1_LIRGenerator.cpp --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -706,6 +706,38 @@ } } +static Value maxvalue(IfOp* ifop) { + switch (ifop->cond()) { + case If::eql: return NULL; + case If::neq: return NULL; + case If::lss: // x < y ? x : y + case If::leq: // x <= y ? x : y + if (ifop->x() == ifop->tval() && + ifop->y() == ifop->fval()) return ifop->y(); + return NULL; + + case If::gtr: // x > y ? y : x + case If::geq: // x >= y ? y : x + if (ifop->x() == ifop->tval() && + ifop->y() == ifop->fval()) return ifop->y(); + return NULL; + + } +} + +static ciType* phi_declared_type(Phi* phi) { + ciType* t = phi->operand_at(0)->declared_type(); + if (t == NULL) { + return NULL; + } + for(int i = 1; i < phi->operand_count(); i++) { + if (t != phi->operand_at(i)->declared_type()) { + return NULL; + } + } + return t; +} + void LIRGenerator::arraycopy_helper(Intrinsic* x, int* flagsp, ciArrayKlass** expected_typep) { Instruction* src = x->argument_at(0); Instruction* src_pos = x->argument_at(1); @@ -715,12 +747,20 @@ // first try to identify the likely type of the arrays involved ciArrayKlass* expected_type = NULL; - bool is_exact = false; + bool is_exact = false, src_objarray = false, dst_objarray = false; { ciArrayKlass* src_exact_type = as_array_klass(src->exact_type()); ciArrayKlass* src_declared_type = as_array_klass(src->declared_type()); + Phi* phi; + if (src_declared_type == NULL && (phi = src->as_Phi()) != NULL) { + src_declared_type = as_array_klass(phi_declared_type(phi)); + } ciArrayKlass* dst_exact_type = as_array_klass(dst->exact_type()); ciArrayKlass* dst_declared_type = as_array_klass(dst->declared_type()); + if (dst_declared_type == NULL && (phi = dst->as_Phi()) != NULL) { + dst_declared_type = as_array_klass(phi_declared_type(phi)); + } + if (src_exact_type != NULL && src_exact_type == dst_exact_type) { // the types exactly match so the type is fully known is_exact = true; @@ -744,17 +784,60 @@ if (expected_type == NULL) expected_type = dst_exact_type; if (expected_type == NULL) expected_type = src_declared_type; if (expected_type == NULL) expected_type = dst_declared_type; + + src_objarray = (src_exact_type && src_exact_type->is_obj_array_klass()) || (src_declared_type && src_declared_type->is_obj_array_klass()); + dst_objarray = (dst_exact_type && dst_exact_type->is_obj_array_klass()) || (dst_declared_type && dst_declared_type->is_obj_array_klass()); } // if a probable array type has been identified, figure out if any // of the required checks for a fast case can be elided. int flags = LIR_OpArrayCopy::all_flags; + + if (!src_objarray) + flags &= ~LIR_OpArrayCopy::src_objarray; + if (!dst_objarray) + flags &= ~LIR_OpArrayCopy::dst_objarray; + + if (!x->arg_needs_null_check(0)) + flags &= ~LIR_OpArrayCopy::src_null_check; + if (!x->arg_needs_null_check(2)) + flags &= ~LIR_OpArrayCopy::dst_null_check; + + if (expected_type != NULL) { - // try to skip null checks - if (src->as_NewArray() != NULL) + Value length_limit = NULL; + + IfOp* ifop = length->as_IfOp(); + if (ifop != NULL) { + // look for expressions like min(v, a.length) which ends up as + // x > y ? y : x or x >= y ? y : x + if ((ifop->cond() == If::gtr || ifop->cond() == If::geq) && + ifop->x() == ifop->fval() && + ifop->y() == ifop->tval()) { + length_limit = ifop->y(); + } + } + + // try to skip null checks and range checks + NewArray* src_array = src->as_NewArray(); + if (src_array != NULL) { flags &= ~LIR_OpArrayCopy::src_null_check; - if (dst->as_NewArray() != NULL) + if (length_limit != NULL && + src_array->length() == length_limit && + is_constant_zero(src_pos)) { + flags &= ~LIR_OpArrayCopy::src_range_check; + } + } + + NewArray* dst_array = dst->as_NewArray(); + if (dst_array != NULL) { flags &= ~LIR_OpArrayCopy::dst_null_check; + if (length_limit != NULL && + dst_array->length() == length_limit && + is_constant_zero(dst_pos)) { + flags &= ~LIR_OpArrayCopy::dst_range_check; + } + } // check from incoming constant values if (positive_constant(src_pos)) @@ -788,6 +871,28 @@ } } + IntConstant* src_int = src_pos->type()->as_IntConstant(); + IntConstant* dst_int = dst_pos->type()->as_IntConstant(); + if (src_int && dst_int) { + int s_offs = src_int->value(); + int d_offs = dst_int->value(); + if (src_int->value() >= dst_int->value()) { + flags &= ~LIR_OpArrayCopy::overlapping; + } + if (expected_type != NULL) { + BasicType t = expected_type->element_type()->basic_type(); + int element_size = type2aelembytes(t); + if (((arrayOopDesc::base_offset_in_bytes(t) + s_offs * element_size) % HeapWordSize == 0) && + ((arrayOopDesc::base_offset_in_bytes(t) + d_offs * element_size) % HeapWordSize == 0)) { + flags &= ~LIR_OpArrayCopy::unaligned; + } + } + } else if (src_pos == dst_pos || is_constant_zero(dst_pos)) { + // src and dest positions are the same, or dst is zero so assume + // nonoverlapping copy. + flags &= ~LIR_OpArrayCopy::overlapping; + } + if (src == dst) { // moving within a single array so no type checks are needed if (flags & LIR_OpArrayCopy::type_check) { @@ -1351,7 +1456,7 @@ if (addr->is_address()) { LIR_Address* address = addr->as_address_ptr(); - LIR_Opr ptr = new_register(T_OBJECT); + LIR_Opr ptr = new_pointer_register(); if (!address->index()->is_valid() && address->disp() == 0) { __ move(address->base(), ptr); } else { @@ -1403,7 +1508,9 @@ LIR_Const* card_table_base = new LIR_Const(((CardTableModRefBS*)_bs)->byte_map_base); if (addr->is_address()) { LIR_Address* address = addr->as_address_ptr(); - LIR_Opr ptr = new_register(T_OBJECT); + // ptr cannot be an object because we use this barrier for array card marks + // and addr can point in the middle of an array. + LIR_Opr ptr = new_pointer_register(); if (!address->index()->is_valid() && address->disp() == 0) { __ move(address->base(), ptr); } else { diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/c1/c1_Optimizer.cpp --- a/hotspot/src/share/vm/c1/c1_Optimizer.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/c1/c1_Optimizer.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -644,7 +644,7 @@ void NullCheckVisitor::do_InstanceOf (InstanceOf* x) {} void NullCheckVisitor::do_MonitorEnter (MonitorEnter* x) { nce()->handle_AccessMonitor(x); } void NullCheckVisitor::do_MonitorExit (MonitorExit* x) { nce()->handle_AccessMonitor(x); } -void NullCheckVisitor::do_Intrinsic (Intrinsic* x) { nce()->clear_last_explicit_null_check(); } +void NullCheckVisitor::do_Intrinsic (Intrinsic* x) { nce()->handle_Intrinsic(x); } void NullCheckVisitor::do_BlockBegin (BlockBegin* x) {} void NullCheckVisitor::do_Goto (Goto* x) {} void NullCheckVisitor::do_If (If* x) {} @@ -1023,6 +1023,12 @@ void NullCheckEliminator::handle_Intrinsic(Intrinsic* x) { if (!x->has_receiver()) { + if (x->id() == vmIntrinsics::_arraycopy) { + for (int i = 0; i < x->number_of_arguments(); i++) { + x->set_arg_needs_null_check(i, !set_contains(x->argument_at(i))); + } + } + // Be conservative clear_last_explicit_null_check(); return; diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/c1/c1_Runtime1.cpp --- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -103,7 +103,10 @@ int Runtime1::_generic_arraycopy_cnt = 0; int Runtime1::_primitive_arraycopy_cnt = 0; int Runtime1::_oop_arraycopy_cnt = 0; +int Runtime1::_generic_arraycopystub_cnt = 0; int Runtime1::_arraycopy_slowcase_cnt = 0; +int Runtime1::_arraycopy_checkcast_cnt = 0; +int Runtime1::_arraycopy_checkcast_attempt_cnt = 0; int Runtime1::_new_type_array_slowcase_cnt = 0; int Runtime1::_new_object_array_slowcase_cnt = 0; int Runtime1::_new_instance_slowcase_cnt = 0; @@ -119,6 +122,32 @@ int Runtime1::_throw_incompatible_class_change_error_count = 0; int Runtime1::_throw_array_store_exception_count = 0; int Runtime1::_throw_count = 0; + +static int _byte_arraycopy_cnt = 0; +static int _short_arraycopy_cnt = 0; +static int _int_arraycopy_cnt = 0; +static int _long_arraycopy_cnt = 0; +static int _oop_arraycopy_cnt = 0; + +address Runtime1::arraycopy_count_address(BasicType type) { + switch (type) { + case T_BOOLEAN: + case T_BYTE: return (address)&_byte_arraycopy_cnt; + case T_CHAR: + case T_SHORT: return (address)&_short_arraycopy_cnt; + case T_FLOAT: + case T_INT: return (address)&_int_arraycopy_cnt; + case T_DOUBLE: + case T_LONG: return (address)&_long_arraycopy_cnt; + case T_ARRAY: + case T_OBJECT: return (address)&_oop_arraycopy_cnt; + default: + ShouldNotReachHere(); + return NULL; + } +} + + #endif // Simple helper to see if the caller of a runtime stub which @@ -1229,9 +1258,17 @@ tty->print_cr(" _handle_wrong_method_cnt: %d", SharedRuntime::_wrong_method_ctr); tty->print_cr(" _ic_miss_cnt: %d", SharedRuntime::_ic_miss_ctr); tty->print_cr(" _generic_arraycopy_cnt: %d", _generic_arraycopy_cnt); + tty->print_cr(" _generic_arraycopystub_cnt: %d", _generic_arraycopystub_cnt); + tty->print_cr(" _byte_arraycopy_cnt: %d", _byte_arraycopy_cnt); + tty->print_cr(" _short_arraycopy_cnt: %d", _short_arraycopy_cnt); + tty->print_cr(" _int_arraycopy_cnt: %d", _int_arraycopy_cnt); + tty->print_cr(" _long_arraycopy_cnt: %d", _long_arraycopy_cnt); tty->print_cr(" _primitive_arraycopy_cnt: %d", _primitive_arraycopy_cnt); - tty->print_cr(" _oop_arraycopy_cnt: %d", _oop_arraycopy_cnt); + tty->print_cr(" _oop_arraycopy_cnt (C): %d", Runtime1::_oop_arraycopy_cnt); + tty->print_cr(" _oop_arraycopy_cnt (stub): %d", _oop_arraycopy_cnt); tty->print_cr(" _arraycopy_slowcase_cnt: %d", _arraycopy_slowcase_cnt); + tty->print_cr(" _arraycopy_checkcast_cnt: %d", _arraycopy_checkcast_cnt); + tty->print_cr(" _arraycopy_checkcast_attempt_cnt:%d", _arraycopy_checkcast_attempt_cnt); tty->print_cr(" _new_type_array_slowcase_cnt: %d", _new_type_array_slowcase_cnt); tty->print_cr(" _new_object_array_slowcase_cnt: %d", _new_object_array_slowcase_cnt); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/c1/c1_Runtime1.hpp --- a/hotspot/src/share/vm/c1/c1_Runtime1.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/c1/c1_Runtime1.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -94,7 +94,10 @@ static int _generic_arraycopy_cnt; static int _primitive_arraycopy_cnt; static int _oop_arraycopy_cnt; + static int _generic_arraycopystub_cnt; static int _arraycopy_slowcase_cnt; + static int _arraycopy_checkcast_cnt; + static int _arraycopy_checkcast_attempt_cnt; static int _new_type_array_slowcase_cnt; static int _new_object_array_slowcase_cnt; static int _new_instance_slowcase_cnt; @@ -174,7 +177,8 @@ static void trace_block_entry(jint block_id); #ifndef PRODUCT - static address throw_count_address() { return (address)&_throw_count; } + static address throw_count_address() { return (address)&_throw_count; } + static address arraycopy_count_address(BasicType type); #endif // directly accessible leaf routine diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/ci/ciInstance.cpp --- a/hotspot/src/share/vm/ci/ciInstance.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/ci/ciInstance.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -66,8 +66,8 @@ "invalid access"); VM_ENTRY_MARK; ciConstant result; - oop obj = get_oop(); - assert(obj != NULL, "bad oop"); + Handle obj = get_oop(); + assert(!obj.is_null(), "bad oop"); BasicType field_btype = field->type()->basic_type(); int offset = field->offset(); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/ci/ciMethodHandle.cpp --- a/hotspot/src/share/vm/ci/ciMethodHandle.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/ci/ciMethodHandle.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -42,9 +42,20 @@ methodHandle callee(_callee->get_methodOop()); // We catch all exceptions here that could happen in the method // handle compiler and stop the VM. - MethodHandleCompiler mhc(h, callee, is_invokedynamic, CATCH); - methodHandle m = mhc.compile(CATCH); - return CURRENT_ENV->get_object(m())->as_method(); + MethodHandleCompiler mhc(h, callee, is_invokedynamic, THREAD); + if (!HAS_PENDING_EXCEPTION) { + methodHandle m = mhc.compile(THREAD); + if (!HAS_PENDING_EXCEPTION) { + return CURRENT_ENV->get_object(m())->as_method(); + } + } + if (PrintMiscellaneous && (Verbose || WizardMode)) { + tty->print("*** ciMethodHandle::get_adapter => "); + PENDING_EXCEPTION->print(); + tty->print("*** get_adapter (%s): ", is_invokedynamic ? "indy" : "mh"); ((ciObject*)this)->print(); //@@ + } + CLEAR_PENDING_EXCEPTION; + return NULL; } diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/ci/ciTypeFlow.hpp --- a/hotspot/src/share/vm/ci/ciTypeFlow.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/ci/ciTypeFlow.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -34,6 +34,7 @@ #include "ci/ciEnv.hpp" #include "ci/ciKlass.hpp" #include "ci/ciMethodBlocks.hpp" +#include "shark/shark_globals.hpp" #endif diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/classfile/classFileParser.cpp --- a/hotspot/src/share/vm/classfile/classFileParser.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -170,7 +170,6 @@ ShouldNotReachHere(); } break; - case JVM_CONSTANT_InvokeDynamicTrans : // this tag appears only in old classfiles case JVM_CONSTANT_InvokeDynamic : { if (_major_version < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) { @@ -186,14 +185,6 @@ cfs->guarantee_more(5, CHECK); // bsm_index, nt, tag/access_flags u2 bootstrap_specifier_index = cfs->get_u2_fast(); u2 name_and_type_index = cfs->get_u2_fast(); - if (tag == JVM_CONSTANT_InvokeDynamicTrans) { - if (!AllowTransitionalJSR292) - classfile_parse_error( - "This JVM does not support transitional InvokeDynamic tag %u in class file %s", - tag, CHECK); - cp->invoke_dynamic_trans_at_put(index, bootstrap_specifier_index, name_and_type_index); - break; - } if (_max_bootstrap_specifier_index < (int) bootstrap_specifier_index) _max_bootstrap_specifier_index = (int) bootstrap_specifier_index; // collect for later cp->invoke_dynamic_at_put(index, bootstrap_specifier_index, name_and_type_index); @@ -492,7 +483,6 @@ ref_index, CHECK_(nullHandle)); } break; - case JVM_CONSTANT_InvokeDynamicTrans : case JVM_CONSTANT_InvokeDynamic : { int name_and_type_ref_index = cp->invoke_dynamic_name_and_type_ref_index_at(index); @@ -501,14 +491,6 @@ "Invalid constant pool index %u in class file %s", name_and_type_ref_index, CHECK_(nullHandle)); - if (tag == JVM_CONSTANT_InvokeDynamicTrans) { - int bootstrap_method_ref_index = cp->invoke_dynamic_bootstrap_method_ref_index_at(index); - check_property(valid_cp_range(bootstrap_method_ref_index, length) && - cp->tag_at(bootstrap_method_ref_index).is_method_handle(), - "Invalid constant pool index %u in class file %s", - bootstrap_method_ref_index, - CHECK_(nullHandle)); - } // bootstrap specifier index must be checked later, when BootstrapMethods attr is available break; } @@ -578,6 +560,7 @@ } break; } + case JVM_CONSTANT_InvokeDynamic: case JVM_CONSTANT_Fieldref: case JVM_CONSTANT_Methodref: case JVM_CONSTANT_InterfaceMethodref: { @@ -2783,7 +2766,6 @@ } } - if (AllowTransitionalJSR292 && word_sig_index == 0) return; if (word_sig_index == 0) THROW_MSG(vmSymbols::java_lang_VirtualMachineError(), "missing I or J signature (for vmentry) in java.lang.invoke.MethodHandle"); @@ -2823,7 +2805,6 @@ } } - if (AllowTransitionalJSR292 && !found_vmentry) return; if (!found_vmentry) THROW_MSG(vmSymbols::java_lang_VirtualMachineError(), "missing vmentry byte field in java.lang.invoke.MethodHandle"); @@ -3194,15 +3175,6 @@ 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 && - EnableInvokeDynamic && class_name == vmSymbols::java_dyn_MethodHandle() && class_loader.is_null()) { - java_lang_invoke_MethodHandle_fix_pre(cp, fields, &fac, CHECK_(nullHandle)); - } - if (AllowTransitionalJSR292 && - 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)); - } // Add a fake "discovered" field if it is not present // for compatibility with earlier jdk's. diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/classfile/javaClasses.cpp --- a/hotspot/src/share/vm/classfile/javaClasses.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -67,28 +67,6 @@ return ik->find_local_field(name_symbol, signature_symbol, fd); } -static bool find_hacked_field(instanceKlass* ik, - Symbol* name_symbol, Symbol* signature_symbol, - fieldDescriptor* fd, - bool allow_super = false) { - bool found = find_field(ik, name_symbol, signature_symbol, fd, allow_super); - if (!found && AllowTransitionalJSR292) { - Symbol* backup_sig = SystemDictionary::find_backup_signature(signature_symbol); - if (backup_sig != NULL) { - found = find_field(ik, name_symbol, backup_sig, fd, allow_super); - if (TraceMethodHandles) { - ResourceMark rm; - tty->print_cr("MethodHandles: %s.%s: backup for %s => %s%s", - ik->name()->as_C_string(), name_symbol->as_C_string(), - signature_symbol->as_C_string(), backup_sig->as_C_string(), - (found ? "" : " (NOT FOUND)")); - } - } - } - return found; -} -#define find_field find_hacked_field /* remove after AllowTransitionalJSR292 */ - // Helpful routine for computing field offsets at run time rather than hardcoding them static void compute_offset(int &dest_offset, @@ -1453,32 +1431,41 @@ } } #ifdef ASSERT - assert(st_method() == method && st.bci() == bci, - "Wrong stack trace"); - st.next(); - // vframeStream::method isn't GC-safe so store off a copy - // of the methodOop in case we GC. - if (!st.at_end()) { - st_method = st.method(); - } + assert(st_method() == method && st.bci() == bci, + "Wrong stack trace"); + st.next(); + // vframeStream::method isn't GC-safe so store off a copy + // of the methodOop in case we GC. + if (!st.at_end()) { + st_method = st.method(); + } #endif + + // the format of the stacktrace will be: + // - 1 or more fillInStackTrace frames for the exception class (skipped) + // - 0 or more methods for the exception class (skipped) + // - rest of the stack + if (!skip_fillInStackTrace_check) { - // check "fillInStackTrace" only once, so we negate the flag - // after the first time check. - skip_fillInStackTrace_check = true; - if (method->name() == vmSymbols::fillInStackTrace_name()) { + if ((method->name() == vmSymbols::fillInStackTrace_name() || + method->name() == vmSymbols::fillInStackTrace0_name()) && + throwable->is_a(method->method_holder())) { continue; } + else { + skip_fillInStackTrace_check = true; // gone past them all + } } - // skip methods of the exceptions klass. If there is methods - // that belongs to a superclass of the exception we are going to skipping - // them in stack trace. This is simlar to classic VM. if (!skip_throwableInit_check) { + assert(skip_fillInStackTrace_check, "logic error in backtrace filtering"); + + // skip methods of the exception class and superclasses + // This is simlar to classic VM. if (method->name() == vmSymbols::object_initializer_name() && throwable->is_a(method->method_holder())) { continue; } else { - // if no "Throwable.init()" method found, we stop checking it next time. + // there are none or we've seen them all - either way stop checking skip_throwableInit_check = true; } } @@ -2333,7 +2320,6 @@ klassOop k = SystemDictionary::MethodHandle_klass(); 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); compute_offset(_vmtarget_offset, k, vmSymbols::vmtarget_name(), vmSymbols::object_signature(), allow_super); compute_offset(_vmentry_offset, k, vmSymbols::vmentry_name(), vmSymbols::machine_word_signature(), allow_super); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/classfile/stackMapFrame.cpp --- a/hotspot/src/share/vm/classfile/stackMapFrame.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/classfile/stackMapFrame.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -208,8 +208,10 @@ return true; } -bool StackMapFrame::is_assignable_to(const StackMapFrame* target, TRAPS) const { - if (_max_locals != target->max_locals() || _stack_size != target->stack_size()) { +bool StackMapFrame::is_assignable_to( + const StackMapFrame* target, bool is_exception_handler, TRAPS) const { + if (_max_locals != target->max_locals() || + _stack_size != target->stack_size()) { return false; } // Only need to compare type elements up to target->locals() or target->stack(). @@ -222,7 +224,7 @@ bool match_flags = (_flags | target->flags()) == target->flags(); return match_locals && match_stack && - (match_flags || has_flag_match_exception(target)); + (match_flags || (is_exception_handler && has_flag_match_exception(target))); } VerificationType StackMapFrame::pop_stack_ex(VerificationType type, TRAPS) { diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/classfile/stackMapFrame.hpp --- a/hotspot/src/share/vm/classfile/stackMapFrame.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/classfile/stackMapFrame.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -134,7 +134,8 @@ void copy_stack(const StackMapFrame* src); // Return true if this stack map frame is assignable to target. - bool is_assignable_to(const StackMapFrame* target, TRAPS) const; + bool is_assignable_to(const StackMapFrame* target, + bool is_exception_handler, TRAPS) const; // Push type into stack type array. inline void push_stack(VerificationType type, TRAPS) { diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/classfile/stackMapTable.cpp --- a/hotspot/src/share/vm/classfile/stackMapTable.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/classfile/stackMapTable.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -98,10 +98,13 @@ bool result = true; StackMapFrame *stackmap_frame = _frame_array[frame_index]; if (match) { + // when checking handler target, match == true && update == false + bool is_exception_handler = !update; // Has direct control flow from last instruction, need to match the two // frames. result = frame->is_assignable_to( - stackmap_frame, CHECK_VERIFY_(frame->verifier(), false)); + stackmap_frame, is_exception_handler, + CHECK_VERIFY_(frame->verifier(), false)); } if (update) { // Use the frame in stackmap table as current frame diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/classfile/systemDictionary.cpp --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -1887,99 +1887,27 @@ 0 }; -Symbol* SystemDictionary::find_backup_symbol(Symbol* symbol, - const char* from_prefix, - const char* to_prefix) { - assert(AllowTransitionalJSR292, ""); // delete this subroutine - Symbol* backup_symbol = NULL; - size_t from_len = strlen(from_prefix); - if (strncmp((const char*) symbol->base(), from_prefix, from_len) != 0) - return NULL; - char buf[100]; - size_t to_len = strlen(to_prefix); - size_t tail_len = symbol->utf8_length() - from_len; - size_t new_len = to_len + tail_len; - guarantee(new_len < sizeof(buf), "buf too small"); - memcpy(buf, to_prefix, to_len); - memcpy(buf + to_len, symbol->base() + from_len, tail_len); - buf[new_len] = '\0'; - vmSymbols::SID backup_sid = vmSymbols::find_sid(buf); - if (backup_sid != vmSymbols::NO_SID) { - backup_symbol = vmSymbols::symbol_at(backup_sid); - } - return backup_symbol; -} - -Symbol* SystemDictionary::find_backup_class_name(Symbol* symbol) { - assert(AllowTransitionalJSR292, ""); // delete this subroutine - if (symbol == NULL) return NULL; - Symbol* backup_symbol = find_backup_symbol(symbol, "java/lang/invoke/", "java/dyn/"); // AllowTransitionalJSR292 ONLY - if (backup_symbol == NULL) - backup_symbol = find_backup_symbol(symbol, "java/dyn/", "sun/dyn/"); // AllowTransitionalJSR292 ONLY - return backup_symbol; -} - -Symbol* SystemDictionary::find_backup_signature(Symbol* symbol) { - assert(AllowTransitionalJSR292, ""); // delete this subroutine - if (symbol == NULL) return NULL; - return find_backup_symbol(symbol, "Ljava/lang/invoke/", "Ljava/dyn/"); -} - bool SystemDictionary::initialize_wk_klass(WKID id, int init_opt, TRAPS) { assert(id >= (int)FIRST_WKID && id < (int)WKID_LIMIT, "oob"); int info = wk_init_info[id - FIRST_WKID]; int sid = (info >> CEIL_LG_OPTION_LIMIT); Symbol* symbol = vmSymbols::symbol_at((vmSymbols::SID)sid); klassOop* klassp = &_well_known_klasses[id]; - bool pre_load = (init_opt < SystemDictionary::Opt); - bool try_load = true; + bool must_load = (init_opt < SystemDictionary::Opt); + bool try_load = true; if (init_opt == SystemDictionary::Opt_Kernel) { #ifndef KERNEL try_load = false; #endif //KERNEL } - Symbol* backup_symbol = NULL; // symbol to try if the current symbol fails - if (init_opt == SystemDictionary::Pre_JSR292) { - 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) { - while (backup_symbol != NULL) { - (*klassp) = resolve_or_null(backup_symbol, CHECK_0); // try backup early - if (TraceMethodHandles) { - ResourceMark rm; - tty->print_cr("MethodHandles: try backup first for %s => %s (%s)", - symbol->as_C_string(), backup_symbol->as_C_string(), - ((*klassp) == NULL) ? "no such class" : "backup load succeeded"); - } - if ((*klassp) != NULL) return true; - backup_symbol = find_backup_class_name(backup_symbol); // find next backup - } - } - } - } - if ((*klassp) != NULL) return true; - if (!try_load) return false; - while (symbol != NULL) { - bool must_load = (pre_load && (backup_symbol == NULL)); + if ((*klassp) == NULL && try_load) { if (must_load) { (*klassp) = resolve_or_fail(symbol, true, CHECK_0); // load required class } else { (*klassp) = resolve_or_null(symbol, CHECK_0); // load optional klass } - if ((*klassp) != NULL) return true; - // Go around again. Example of long backup sequence: - // java.lang.invoke.MemberName, java.dyn.MemberName, sun.dyn.MemberName, ONLY if AllowTransitionalJSR292 - if (TraceMethodHandles && (backup_symbol != NULL)) { - ResourceMark rm; - tty->print_cr("MethodHandles: backup for %s => %s", - symbol->as_C_string(), backup_symbol->as_C_string()); - } - symbol = backup_symbol; - if (AllowTransitionalJSR292) - backup_symbol = find_backup_class_name(symbol); } - return false; + return ((*klassp) != NULL); } void SystemDictionary::initialize_wk_klasses_until(WKID limit_id, WKID &start_id, TRAPS) { @@ -2409,9 +2337,7 @@ // Must create lots of stuff here, but outside of the SystemDictionary lock. if (THREAD->is_Compiler_thread()) return NULL; // do not attempt from within compiler - bool for_invokeGeneric = (name_id == vmSymbols::VM_SYMBOL_ENUM_NAME(invokeGeneric_name)); - if (AllowInvokeForInvokeGeneric && name_id == vmSymbols::VM_SYMBOL_ENUM_NAME(invoke_name)) - for_invokeGeneric = true; + bool for_invokeGeneric = (name_id != vmSymbols::VM_SYMBOL_ENUM_NAME(invokeExact_name)); bool found_on_bcp = false; Handle mt = find_method_handle_type(signature, accessing_klass, for_invokeGeneric, @@ -2498,14 +2424,10 @@ JavaCallArguments args(Handle(THREAD, rt())); args.push_oop(pts()); JavaValue result(T_OBJECT); - Symbol* findMethodHandleType_signature = vmSymbols::findMethodHandleType_signature(); - if (AllowTransitionalJSR292 && SystemDictionaryHandles::MethodType_klass()->name() == vmSymbols::java_dyn_MethodType()) { - findMethodHandleType_signature = vmSymbols::findMethodHandleType_TRANS_signature(); - } JavaCalls::call_static(&result, SystemDictionary::MethodHandleNatives_klass(), vmSymbols::findMethodHandleType_name(), - findMethodHandleType_signature, + vmSymbols::findMethodHandleType_signature(), &args, CHECK_(empty)); Handle method_type(THREAD, (oop) result.get_jobject()); @@ -2513,14 +2435,10 @@ // call java.lang.invoke.MethodHandleNatives::notifyGenericMethodType(MethodType) -> void JavaCallArguments args(Handle(THREAD, method_type())); JavaValue no_result(T_VOID); - Symbol* notifyGenericMethodType_signature = vmSymbols::notifyGenericMethodType_signature(); - if (AllowTransitionalJSR292 && SystemDictionaryHandles::MethodType_klass()->name() == vmSymbols::java_dyn_MethodType()) { - notifyGenericMethodType_signature = vmSymbols::notifyGenericMethodType_TRANS_signature(); - } JavaCalls::call_static(&no_result, SystemDictionary::MethodHandleNatives_klass(), vmSymbols::notifyGenericMethodType_name(), - notifyGenericMethodType_signature, + vmSymbols::notifyGenericMethodType_signature(), &args, THREAD); if (HAS_PENDING_EXCEPTION) { // If the notification fails, just kill it. @@ -2569,14 +2487,10 @@ args.push_oop(name()); args.push_oop(type()); JavaValue result(T_OBJECT); - Symbol* linkMethodHandleConstant_signature = vmSymbols::linkMethodHandleConstant_signature(); - if (AllowTransitionalJSR292 && SystemDictionaryHandles::MethodHandle_klass()->name() == vmSymbols::java_dyn_MethodHandle()) { - linkMethodHandleConstant_signature = vmSymbols::linkMethodHandleConstant_TRANS_signature(); - } JavaCalls::call_static(&result, SystemDictionary::MethodHandleNatives_klass(), vmSymbols::linkMethodHandleConstant_name(), - linkMethodHandleConstant_signature, + vmSymbols::linkMethodHandleConstant_signature(), &args, CHECK_(empty)); return Handle(THREAD, (oop) result.get_jobject()); } @@ -2607,17 +2521,10 @@ args.push_oop(caller_mname()); args.push_int(caller_bci); JavaValue result(T_OBJECT); - Symbol* makeDynamicCallSite_signature = vmSymbols::makeDynamicCallSite_signature(); - if (AllowTransitionalJSR292 && SystemDictionaryHandles::MethodHandleNatives_klass()->name() == vmSymbols::sun_dyn_MethodHandleNatives()) { - makeDynamicCallSite_signature = vmSymbols::makeDynamicCallSite_TRANS_signature(); - } - if (AllowTransitionalJSR292 && SystemDictionaryHandles::MethodHandleNatives_klass()->name() == vmSymbols::java_dyn_MethodHandleNatives()) { - makeDynamicCallSite_signature = vmSymbols::makeDynamicCallSite_TRANS2_signature(); - } JavaCalls::call_static(&result, SystemDictionary::MethodHandleNatives_klass(), vmSymbols::makeDynamicCallSite_name(), - makeDynamicCallSite_signature, + vmSymbols::makeDynamicCallSite_signature(), &args, CHECK_(empty)); oop call_site_oop = (oop) result.get_jobject(); assert(call_site_oop->is_oop() @@ -2698,28 +2605,10 @@ argument_info_result = argument_info; // return argument_info to caller return bsm; } - // else null BSM; fall through - } else if (tag.is_name_and_type()) { - // JSR 292 EDR does not have JVM_CONSTANT_InvokeDynamic - // a bare name&type defaults its BSM to null, so fall through... } else { ShouldNotReachHere(); // verifier does not allow this } - // Fall through to pick up the per-class bootstrap method. - // This mechanism may go away in the PFD. - assert(AllowTransitionalJSR292, "else the verifier should have stopped us already"); - argument_info_result = empty; // return no argument_info to caller - oop bsm_oop = instanceKlass::cast(caller_method->method_holder())->bootstrap_method(); - if (bsm_oop != NULL) { - if (TraceMethodHandles) { - tty->print_cr("bootstrap method for "PTR_FORMAT" registered as "PTR_FORMAT":", - (intptr_t) caller_method(), (intptr_t) bsm_oop); - } - assert(bsm_oop->is_oop(), "must be sane"); - return Handle(THREAD, bsm_oop); - } - return empty; } diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/classfile/systemDictionary.hpp --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -146,7 +146,6 @@ /* support for dynamic typing; it's OK if these are NULL in earlier JDKs */ \ template(MethodHandle_klass, java_lang_invoke_MethodHandle, Pre_JSR292) \ template(MemberName_klass, java_lang_invoke_MemberName, Pre_JSR292) \ - template(MethodHandleImpl_klass, sun_dyn_MethodHandleImpl, Opt) /* AllowTransitionalJSR292 ONLY */ \ template(MethodHandleNatives_klass, java_lang_invoke_MethodHandleNatives, Pre_JSR292) \ template(AdapterMethodHandle_klass, java_lang_invoke_AdapterMethodHandle, Pre_JSR292) \ template(BoundMethodHandle_klass, java_lang_invoke_BoundMethodHandle, Pre_JSR292) \ @@ -154,7 +153,6 @@ template(MethodType_klass, java_lang_invoke_MethodType, Pre_JSR292) \ template(MethodTypeForm_klass, java_lang_invoke_MethodTypeForm, Pre_JSR292) \ template(WrongMethodTypeException_klass, java_lang_invoke_WrongMethodTypeException, Pre_JSR292) \ - template(Linkage_klass, java_lang_invoke_Linkage, Opt) /* AllowTransitionalJSR292 ONLY */ \ template(CallSite_klass, java_lang_invoke_CallSite, Pre_JSR292) \ /* Note: MethodHandle must be first, and CallSite last in group */ \ \ @@ -422,8 +420,6 @@ initialize_wk_klasses_until((WKID) limit, start_id, THREAD); } - static Symbol* find_backup_symbol(Symbol* symbol, const char* from_prefix, const char* to_prefix); - public: #define WK_KLASS_DECLARE(name, ignore_symbol, option) \ static klassOop name() { return check_klass_##option(_well_known_klasses[WK_KLASS_ENUM_NAME(name)]); } @@ -445,9 +441,6 @@ static void load_abstract_ownable_synchronizer_klass(TRAPS); - static Symbol* find_backup_class_name(Symbol* class_name_symbol); - static Symbol* find_backup_signature(Symbol* signature_symbol); - private: // Tells whether ClassLoader.loadClassInternal is present static bool has_loadClassInternal() { return _has_loadClassInternal; } diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/classfile/verifier.cpp --- a/hotspot/src/share/vm/classfile/verifier.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/classfile/verifier.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -1671,19 +1671,13 @@ VerificationType::long_type(), VerificationType::long2_type(), CHECK_VERIFY(this)); } else if (tag.is_method_handle()) { - Symbol* methodHandle_name = vmSymbols::java_lang_invoke_MethodHandle(); - if (AllowTransitionalJSR292 && !Universe::is_bootstrapping()) - methodHandle_name = SystemDictionaryHandles::MethodHandle_klass()->name(); current_frame->push_stack( VerificationType::reference_type( - methodHandle_name), CHECK_VERIFY(this)); + vmSymbols::java_lang_invoke_MethodHandle()), CHECK_VERIFY(this)); } else if (tag.is_method_type()) { - Symbol* methodType_name = vmSymbols::java_lang_invoke_MethodType(); - if (AllowTransitionalJSR292 && !Universe::is_bootstrapping()) - methodType_name = SystemDictionaryHandles::MethodType_klass()->name(); current_frame->push_stack( VerificationType::reference_type( - methodType_name), CHECK_VERIFY(this)); + vmSymbols::java_lang_invoke_MethodType()), CHECK_VERIFY(this)); } else { verify_error(bci, "Invalid index in ldc"); return; @@ -1950,8 +1944,7 @@ unsigned int types = (opcode == Bytecodes::_invokeinterface ? 1 << JVM_CONSTANT_InterfaceMethodref : opcode == Bytecodes::_invokedynamic - ? ((AllowTransitionalJSR292 ? 1 << JVM_CONSTANT_NameAndType : 0) - |1 << JVM_CONSTANT_InvokeDynamic) + ? 1 << JVM_CONSTANT_InvokeDynamic : 1 << JVM_CONSTANT_Methodref); verify_cp_type(index, cp, types, CHECK_VERIFY(this)); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/classfile/vmSymbols.hpp --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -245,44 +245,15 @@ template(java_lang_invoke_AdapterMethodHandle, "java/lang/invoke/AdapterMethodHandle") \ template(java_lang_invoke_BoundMethodHandle, "java/lang/invoke/BoundMethodHandle") \ template(java_lang_invoke_DirectMethodHandle, "java/lang/invoke/DirectMethodHandle") \ - /* temporary transitional public names from 6839872: */ \ - template(java_dyn_InvokeDynamic, "java/dyn/InvokeDynamic") /* AllowTransitionalJSR292 ONLY */ \ - template(java_dyn_Linkage, "java/dyn/Linkage") /* AllowTransitionalJSR292 ONLY */ \ - template(java_dyn_CallSite, "java/dyn/CallSite") /* AllowTransitionalJSR292 ONLY */ \ - template(java_dyn_MethodHandle, "java/dyn/MethodHandle") /* AllowTransitionalJSR292 ONLY */ \ - template(java_dyn_MethodType, "java/dyn/MethodType") /* AllowTransitionalJSR292 ONLY */ \ - template(java_dyn_WrongMethodTypeException, "java/dyn/WrongMethodTypeException") /* AllowTransitionalJSR292 ONLY */ \ - template(java_dyn_MethodType_signature, "Ljava/dyn/MethodType;") /* AllowTransitionalJSR292 ONLY */ \ - template(java_dyn_MethodHandle_signature, "Ljava/dyn/MethodHandle;") /* AllowTransitionalJSR292 ONLY */ \ - /* temporary transitional internal names from 6839872: */ \ - template(java_dyn_MethodTypeForm, "java/dyn/MethodTypeForm") /* AllowTransitionalJSR292 ONLY */ \ - template(java_dyn_MethodTypeForm_signature, "Ljava/dyn/MethodTypeForm;") /* AllowTransitionalJSR292 ONLY */ \ - template(java_dyn_MemberName, "java/dyn/MemberName") /* AllowTransitionalJSR292 ONLY */ \ - template(java_dyn_MethodHandleNatives, "java/dyn/MethodHandleNatives") /* AllowTransitionalJSR292 ONLY */ \ - template(java_dyn_AdapterMethodHandle, "java/dyn/AdapterMethodHandle") /* AllowTransitionalJSR292 ONLY */ \ - template(java_dyn_BoundMethodHandle, "java/dyn/BoundMethodHandle") /* AllowTransitionalJSR292 ONLY */ \ - template(java_dyn_DirectMethodHandle, "java/dyn/DirectMethodHandle") /* AllowTransitionalJSR292 ONLY */ \ - /* temporary transitional internal names from EDR: */ \ - template(sun_dyn_MemberName, "sun/dyn/MemberName") /* AllowTransitionalJSR292 ONLY */ \ - template(sun_dyn_MethodHandleImpl, "sun/dyn/MethodHandleImpl") /* AllowTransitionalJSR292 ONLY */ \ - template(sun_dyn_MethodHandleNatives, "sun/dyn/MethodHandleNatives") /* AllowTransitionalJSR292 ONLY */ \ - template(sun_dyn_AdapterMethodHandle, "sun/dyn/AdapterMethodHandle") /* AllowTransitionalJSR292 ONLY */ \ - template(sun_dyn_BoundMethodHandle, "sun/dyn/BoundMethodHandle") /* AllowTransitionalJSR292 ONLY */ \ - template(sun_dyn_DirectMethodHandle, "sun/dyn/DirectMethodHandle") /* AllowTransitionalJSR292 ONLY */ \ /* internal up-calls made only by the JVM, via class sun.invoke.MethodHandleNatives: */ \ template(findMethodHandleType_name, "findMethodHandleType") \ template(findMethodHandleType_signature, "(Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/invoke/MethodType;") \ - template(findMethodHandleType_TRANS_signature, "(Ljava/lang/Class;[Ljava/lang/Class;)Ljava/dyn/MethodType;") /* AllowTransitionalJSR292 ONLY */ \ template(notifyGenericMethodType_name, "notifyGenericMethodType") \ template(notifyGenericMethodType_signature, "(Ljava/lang/invoke/MethodType;)V") \ - template(notifyGenericMethodType_TRANS_signature, "(Ljava/dyn/MethodType;)V") /* AllowTransitionalJSR292 ONLY */ \ template(linkMethodHandleConstant_name, "linkMethodHandleConstant") \ template(linkMethodHandleConstant_signature, "(Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/invoke/MethodHandle;") \ - template(linkMethodHandleConstant_TRANS_signature, "(Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/String;Ljava/lang/Object;)Ljava/dyn/MethodHandle;") /* AllowTransitionalJSR292 ONLY */ \ template(makeDynamicCallSite_name, "makeDynamicCallSite") \ template(makeDynamicCallSite_signature, "(Ljava/lang/invoke/MethodHandle;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/Object;Ljava/lang/invoke/MemberName;I)Ljava/lang/invoke/CallSite;") \ - template(makeDynamicCallSite_TRANS_signature, "(Ljava/dyn/MethodHandle;Ljava/lang/String;Ljava/dyn/MethodType;Ljava/lang/Object;Lsun/dyn/MemberName;I)Ljava/dyn/CallSite;") /* AllowTransitionalJSR292 ONLY */ \ - template(makeDynamicCallSite_TRANS2_signature, "(Ljava/dyn/MethodHandle;Ljava/lang/String;Ljava/dyn/MethodType;Ljava/lang/Object;Ljava/dyn/MemberName;I)Ljava/dyn/CallSite;") /* AllowTransitionalJSR292 ONLY */ \ NOT_LP64( do_alias(machine_word_signature, int_signature) ) \ LP64_ONLY( do_alias(machine_word_signature, long_signature) ) \ \ @@ -330,6 +301,7 @@ template(dispatch_name, "dispatch") \ template(getSystemClassLoader_name, "getSystemClassLoader") \ template(fillInStackTrace_name, "fillInStackTrace") \ + template(fillInStackTrace0_name, "fillInStackTrace0") \ template(getCause_name, "getCause") \ template(initCause_name, "initCause") \ template(setProperty_name, "setProperty") \ @@ -910,8 +882,6 @@ do_intrinsic(_invoke, java_lang_reflect_Method, invoke_name, object_object_array_object_signature, F_R) \ /* (symbols invoke_name and invoke_signature defined above) */ \ do_intrinsic(_checkSpreadArgument, java_lang_invoke_MethodHandleNatives, checkSpreadArgument_name, checkSpreadArgument_signature, F_S) \ - do_intrinsic(_checkSpreadArgument_TRANS,sun_dyn_MethodHandleImpl, checkSpreadArgument_name, checkSpreadArgument_signature, F_S) /* AllowTransitionalJSR292 ONLY */ \ - do_intrinsic(_checkSpreadArgument_TRANS2,java_dyn_MethodHandleNatives, checkSpreadArgument_name, checkSpreadArgument_signature, F_S) /* AllowTransitionalJSR292 ONLY */ \ do_name( checkSpreadArgument_name, "checkSpreadArgument") \ do_name( checkSpreadArgument_signature, "(Ljava/lang/Object;I)V") \ do_intrinsic(_invokeExact, java_lang_invoke_MethodHandle, invokeExact_name, object_array_object_signature, F_RN) \ diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/code/codeCache.cpp --- a/hotspot/src/share/vm/code/codeCache.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/code/codeCache.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -964,3 +964,14 @@ nof_blobs(), nof_nmethods(), nof_adapters(), unallocated_capacity(), largest_free_block()); } + +size_t CodeCache::largest_free_block() { + // This is called both with and without CodeCache_lock held so + // handle both cases. + if (CodeCache_lock->owned_by_self()) { + return _heap->largest_free_block(); + } else { + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + return _heap->largest_free_block(); + } +} diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/code/codeCache.hpp --- a/hotspot/src/share/vm/code/codeCache.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/code/codeCache.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -160,7 +160,7 @@ static size_t capacity() { return _heap->capacity(); } static size_t max_capacity() { return _heap->max_capacity(); } static size_t unallocated_capacity() { return _heap->unallocated_capacity(); } - static size_t largest_free_block() { return _heap->largest_free_block(); } + static size_t largest_free_block(); static bool needs_flushing() { return largest_free_block() < CodeCacheFlushingMinimumFreeSpace; } static bool needs_cache_clean() { return _needs_cache_clean; } diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/code/relocInfo.cpp --- a/hotspot/src/share/vm/code/relocInfo.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/code/relocInfo.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -472,20 +472,14 @@ return itr._rh; } - -static inline bool is_index(intptr_t index) { - return 0 < index && index < os::vm_page_size(); -} - - int32_t Relocation::runtime_address_to_index(address runtime_address) { - assert(!is_index((intptr_t)runtime_address), "must not look like an index"); + assert(!is_reloc_index((intptr_t)runtime_address), "must not look like an index"); if (runtime_address == NULL) return 0; StubCodeDesc* p = StubCodeDesc::desc_for(runtime_address); if (p != NULL && p->begin() == runtime_address) { - assert(is_index(p->index()), "there must not be too many stubs"); + assert(is_reloc_index(p->index()), "there must not be too many stubs"); return (int32_t)p->index(); } else { // Known "miscellaneous" non-stub pointers: @@ -506,7 +500,7 @@ address Relocation::index_to_runtime_address(int32_t index) { if (index == 0) return NULL; - if (is_index(index)) { + if (is_reloc_index(index)) { StubCodeDesc* p = StubCodeDesc::desc_for_index(index); assert(p != NULL, "there must be a stub for this index"); return p->begin(); @@ -634,7 +628,7 @@ #ifndef _LP64 p = pack_1_int_to(p, index); #else - if (is_index(index)) { + if (is_reloc_index(index)) { p = pack_2_ints_to(p, index, 0); } else { jlong t = (jlong) _target; @@ -642,7 +636,7 @@ int32_t hi = high(t); p = pack_2_ints_to(p, lo, hi); DEBUG_ONLY(jlong t1 = jlong_from(hi, lo)); - assert(!is_index(t1) && (address) t1 == _target, "not symmetric"); + assert(!is_reloc_index(t1) && (address) t1 == _target, "not symmetric"); } #endif /* _LP64 */ dest->set_locs_end((relocInfo*) p); @@ -656,7 +650,7 @@ int32_t lo, hi; unpack_2_ints(lo, hi); jlong t = jlong_from(hi, lo);; - if (is_index(t)) { + if (is_reloc_index(t)) { _target = index_to_runtime_address(t); } else { _target = (address) t; diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/code/relocInfo.hpp --- a/hotspot/src/share/vm/code/relocInfo.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/code/relocInfo.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -703,6 +703,10 @@ assert(datalen()==0 || type()==relocInfo::none, "no data here"); } + static bool is_reloc_index(intptr_t index) { + return 0 < index && index < os::vm_page_size(); + } + protected: // Helper functions for pack_data_to() and unpack_data(). @@ -1127,6 +1131,12 @@ return rh; } + // Some address looking values aren't safe to treat as relocations + // and should just be treated as constants. + static bool can_be_relocated(address target) { + return target != NULL && !is_reloc_index((intptr_t)target); + } + private: address _target; // address in runtime diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/compiler/compileBroker.cpp --- a/hotspot/src/share/vm/compiler/compileBroker.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -847,9 +847,9 @@ // Initialize the compilation queue void CompileBroker::init_compiler_threads(int c1_compiler_count, int c2_compiler_count) { EXCEPTION_MARK; -#ifndef ZERO +#if !defined(ZERO) && !defined(SHARK) assert(c2_compiler_count > 0 || c1_compiler_count > 0, "No compilers?"); -#endif // !ZERO +#endif // !ZERO && !SHARK if (c2_compiler_count > 0) { _c2_method_queue = new CompileQueue("C2MethodQueue", MethodCompileQueue_lock); } @@ -1118,7 +1118,7 @@ assert(!HAS_PENDING_EXCEPTION, "No exception should be present"); // some prerequisites that are compiler specific - if (compiler(comp_level)->is_c2()) { + if (compiler(comp_level)->is_c2() || compiler(comp_level)->is_shark()) { method->constants()->resolve_string_constants(CHECK_0); // Resolve all classes seen in the signature of the method // we are compiling. @@ -1736,8 +1736,14 @@ UseInterpreter = true; if (UseCompiler || AlwaysCompileLoopMethods ) { if (xtty != NULL) { + stringStream s; + // Dump code cache state into a buffer before locking the tty, + // because log_state() will use locks causing lock conflicts. + CodeCache::log_state(&s); + // Lock to prevent tearing + ttyLocker ttyl; xtty->begin_elem("code_cache_full"); - CodeCache::log_state(xtty); + xtty->print(s.as_string()); xtty->stamp(); xtty->end_elem(); } diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -554,7 +554,7 @@ /* 0xB0 */ &&opc_areturn, &&opc_return, &&opc_getstatic, &&opc_putstatic, /* 0xB4 */ &&opc_getfield, &&opc_putfield, &&opc_invokevirtual,&&opc_invokespecial, -/* 0xB8 */ &&opc_invokestatic,&&opc_invokeinterface,&&opc_default, &&opc_new, +/* 0xB8 */ &&opc_invokestatic,&&opc_invokeinterface,&&opc_invokedynamic,&&opc_new, /* 0xBC */ &&opc_newarray, &&opc_anewarray, &&opc_arraylength, &&opc_athrow, /* 0xC0 */ &&opc_checkcast, &&opc_instanceof, &&opc_monitorenter, &&opc_monitorexit, @@ -568,7 +568,7 @@ /* 0xDC */ &&opc_default, &&opc_default, &&opc_default, &&opc_default, /* 0xE0 */ &&opc_default, &&opc_default, &&opc_default, &&opc_default, -/* 0xE4 */ &&opc_default, &&opc_return_register_finalizer, &&opc_default, &&opc_default, +/* 0xE4 */ &&opc_default, &&opc_fast_aldc, &&opc_fast_aldc_w, &&opc_return_register_finalizer, /* 0xE8 */ &&opc_default, &&opc_default, &&opc_default, &&opc_default, /* 0xEC */ &&opc_default, &&opc_default, &&opc_default, &&opc_default, @@ -1718,8 +1718,7 @@ } // Need to throw illegal monitor state exception CALL_VM(InterpreterRuntime::throw_illegal_monitor_state_exception(THREAD), handle_exception); - // Should never reach here... - assert(false, "Should have thrown illegal monitor exception"); + ShouldNotReachHere(); } /* All of the non-quick opcodes. */ @@ -2147,6 +2146,74 @@ UPDATE_PC_AND_TOS_AND_CONTINUE(3, 2); } + CASE(_fast_aldc_w): + CASE(_fast_aldc): { + 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(InterpreterRuntime::throw_IncompatibleClassChangeError(THREAD), + handle_exception); + ShouldNotReachHere(); + } + + u2 index; + int incr; + if (opcode == Bytecodes::_fast_aldc) { + index = pc[1]; + incr = 2; + } else { + index = Bytes::get_native_u2(pc+1); + incr = 3; + } + + // We are resolved if the f1 field contains a non-null object (CallSite, etc.) + // This kind of CP cache entry does not need to match the flags byte, because + // there is a 1-1 relation between bytecode type and CP entry type. + ConstantPoolCacheEntry* cache = cp->entry_at(index); + if (cache->is_f1_null()) { + CALL_VM(InterpreterRuntime::resolve_ldc(THREAD, (Bytecodes::Code) opcode), + handle_exception); + } + + VERIFY_OOP(cache->f1()); + SET_STACK_OBJECT(cache->f1(), 0); + UPDATE_PC_AND_TOS_AND_CONTINUE(incr, 1); + } + + CASE(_invokedynamic): { + 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(InterpreterRuntime::throw_IncompatibleClassChangeError(THREAD), + handle_exception); + ShouldNotReachHere(); + } + + int index = Bytes::get_native_u4(pc+1); + + // We are resolved if the f1 field contains a non-null object (CallSite, etc.) + // This kind of CP cache entry does not need to match the flags byte, because + // there is a 1-1 relation between bytecode type and CP entry type. + assert(constantPoolCacheOopDesc::is_secondary_index(index), "incorrect format"); + ConstantPoolCacheEntry* cache = cp->secondary_entry_at(index); + if (cache->is_f1_null()) { + CALL_VM(InterpreterRuntime::resolve_invokedynamic(THREAD), + handle_exception); + } + + VERIFY_OOP(cache->f1()); + oop method_handle = java_lang_invoke_CallSite::target(cache->f1()); + CHECK_NULL(method_handle); + + istate->set_msg(call_method_handle); + istate->set_callee((methodOop) method_handle); + istate->set_bcp_advance(5); + + UPDATE_PC_AND_RETURN(0); // I'll be back... + } + CASE(_invokeinterface): { u2 index = Bytes::get_native_u2(pc+1); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/interpreter/bytecodeInterpreter.hpp --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -107,6 +107,7 @@ rethrow_exception, // unwinding and throwing exception // requests to frame manager from C++ interpreter call_method, // request for new frame from interpreter, manager responds with method_entry + call_method_handle, // like the above, except the callee is a method handle return_from_method, // request from interpreter to unwind, manager responds with method_continue more_monitors, // need a new monitor throwing_exception, // unwind stack and rethrow diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/interpreter/bytecodeTracer.cpp --- a/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -345,7 +345,6 @@ break; case JVM_CONSTANT_NameAndType: case JVM_CONSTANT_InvokeDynamic: - case JVM_CONSTANT_InvokeDynamicTrans: has_klass = false; break; default: diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/interpreter/interpreterRuntime.cpp --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -369,10 +369,7 @@ } // create exception - Symbol* java_lang_invoke_WrongMethodTypeException = vmSymbols::java_lang_invoke_WrongMethodTypeException(); - if (AllowTransitionalJSR292) - java_lang_invoke_WrongMethodTypeException = SystemDictionaryHandles::WrongMethodTypeException_klass()->name(); - THROW_MSG(java_lang_invoke_WrongMethodTypeException, message); + THROW_MSG(vmSymbols::java_lang_invoke_WrongMethodTypeException(), message); } IRT_END diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/interpreter/linkResolver.cpp --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -221,9 +221,7 @@ // Make sure the Java part of the runtime has been booted up. klassOop natives = SystemDictionary::MethodHandleNatives_klass(); if (natives == NULL || instanceKlass::cast(natives)->is_not_initialized()) { - Symbol* natives_name = vmSymbols::java_lang_invoke_MethodHandleNatives(); - if (natives != NULL && AllowTransitionalJSR292) natives_name = Klass::cast(natives)->name(); - SystemDictionary::resolve_or_fail(natives_name, + SystemDictionary::resolve_or_fail(vmSymbols::java_lang_invoke_MethodHandleNatives(), Handle(), Handle(), true, diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/interpreter/rewriter.cpp --- a/hotspot/src/share/vm/interpreter/rewriter.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/interpreter/rewriter.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -52,7 +52,6 @@ case JVM_CONSTANT_MethodHandle : // fall through case JVM_CONSTANT_MethodType : // fall through case JVM_CONSTANT_InvokeDynamic : // fall through - case JVM_CONSTANT_InvokeDynamicTrans: // fall through add_cp_cache_entry(i); break; } @@ -62,7 +61,6 @@ "all cp cache indexes fit in a u2"); _have_invoke_dynamic = ((tag_mask & (1 << JVM_CONSTANT_InvokeDynamic)) != 0); - _have_invoke_dynamic |= ((tag_mask & (1 << JVM_CONSTANT_InvokeDynamicTrans)) != 0); } @@ -81,16 +79,10 @@ if (pool_index >= 0 && _pool->tag_at(pool_index).is_invoke_dynamic()) { int bsm_index = _pool->invoke_dynamic_bootstrap_method_ref_index_at(pool_index); - if (bsm_index != 0) { - assert(_pool->tag_at(bsm_index).is_method_handle(), "must be a MH constant"); - // There is a CP cache entry holding the BSM for these calls. - int bsm_cache_index = cp_entry_to_cp_cache(bsm_index); - cache->entry_at(i)->initialize_bootstrap_method_index_in_cache(bsm_cache_index); - } else { - // There is no CP cache entry holding the BSM for these calls. - // We will need to look for a class-global BSM, later. - guarantee(AllowTransitionalJSR292, ""); - } + assert(_pool->tag_at(bsm_index).is_method_handle(), "must be a MH constant"); + // There is a CP cache entry holding the BSM for these calls. + int bsm_cache_index = cp_entry_to_cp_cache(bsm_index); + cache->entry_at(i)->initialize_bootstrap_method_index_in_cache(bsm_cache_index); } } } diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/oops/constantPoolKlass.cpp --- a/hotspot/src/share/vm/oops/constantPoolKlass.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/oops/constantPoolKlass.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -381,7 +381,6 @@ case JVM_CONSTANT_MethodType : st->print("signature_index=%d", cp->method_type_index_at(index)); break; - case JVM_CONSTANT_InvokeDynamicTrans : case JVM_CONSTANT_InvokeDynamic : { st->print("bootstrap_method_index=%d", cp->invoke_dynamic_bootstrap_method_ref_index_at(index)); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/oops/constantPoolOop.cpp --- a/hotspot/src/share/vm/oops/constantPoolOop.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/oops/constantPoolOop.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -284,17 +284,13 @@ if (constantPoolCacheOopDesc::is_secondary_index(which)) { // Invokedynamic index. int pool_index = cache()->main_entry_at(which)->constant_pool_index(); - if (!AllowTransitionalJSR292 || tag_at(pool_index).is_invoke_dynamic()) - pool_index = invoke_dynamic_name_and_type_ref_index_at(pool_index); + pool_index = invoke_dynamic_name_and_type_ref_index_at(pool_index); assert(tag_at(pool_index).is_name_and_type(), ""); return pool_index; } // change byte-ordering and go via cache i = remap_instruction_operand_from_cache(which); } else { - if (AllowTransitionalJSR292 && tag_at(which).is_name_and_type()) - // invokedynamic index is a simple name-and-type - return which; if (tag_at(which).is_invoke_dynamic()) { int pool_index = invoke_dynamic_name_and_type_ref_index_at(which); assert(tag_at(pool_index).is_name_and_type(), ""); @@ -953,7 +949,6 @@ } break; case JVM_CONSTANT_InvokeDynamic: - case JVM_CONSTANT_InvokeDynamicTrans: { int k1 = invoke_dynamic_bootstrap_method_ref_index_at(index1); int k2 = cp2->invoke_dynamic_bootstrap_method_ref_index_at(index2); @@ -1227,13 +1222,6 @@ to_cp->method_handle_index_at_put(to_i, k1, k2); } break; - case JVM_CONSTANT_InvokeDynamicTrans: - { - int k1 = from_cp->invoke_dynamic_bootstrap_method_ref_index_at(from_i); - int k2 = from_cp->invoke_dynamic_name_and_type_ref_index_at(from_i); - to_cp->invoke_dynamic_trans_at_put(to_i, k1, k2); - } break; - case JVM_CONSTANT_InvokeDynamic: { int k1 = from_cp->invoke_dynamic_bootstrap_specifier_index(from_i); @@ -1459,7 +1447,6 @@ return 5; case JVM_CONSTANT_InvokeDynamic: - case JVM_CONSTANT_InvokeDynamicTrans: // u1 tag, u2 bsm, u2 nt return 5; @@ -1674,7 +1661,6 @@ DBG(printf("JVM_CONSTANT_MethodType: %hd", idx1)); break; } - case JVM_CONSTANT_InvokeDynamicTrans: case JVM_CONSTANT_InvokeDynamic: { *bytes = tag; idx1 = extract_low_short_from_int(*int_at_addr(idx)); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/oops/constantPoolOop.hpp --- a/hotspot/src/share/vm/oops/constantPoolOop.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/oops/constantPoolOop.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -244,12 +244,6 @@ *int_at_addr(which) = ((jint) name_and_type_index<<16) | bootstrap_specifier_index; } - void invoke_dynamic_trans_at_put(int which, int bootstrap_method_index, int name_and_type_index) { - tag_at_put(which, JVM_CONSTANT_InvokeDynamicTrans); - *int_at_addr(which) = ((jint) name_and_type_index<<16) | bootstrap_method_index; - assert(AllowTransitionalJSR292, ""); - } - // Temporary until actual use void unresolved_string_at_put(int which, Symbol* s) { release_tag_at_put(which, JVM_CONSTANT_UnresolvedString); @@ -570,15 +564,11 @@ }; int invoke_dynamic_bootstrap_method_ref_index_at(int which) { assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool"); - if (tag_at(which).value() == JVM_CONSTANT_InvokeDynamicTrans) - return extract_low_short_from_int(*int_at_addr(which)); int op_base = invoke_dynamic_operand_base(which); return operands()->short_at(op_base + _indy_bsm_offset); } int invoke_dynamic_argument_count_at(int which) { assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool"); - if (tag_at(which).value() == JVM_CONSTANT_InvokeDynamicTrans) - return 0; int op_base = invoke_dynamic_operand_base(which); int argc = operands()->short_at(op_base + _indy_argc_offset); DEBUG_ONLY(int end_offset = op_base + _indy_argv_offset + argc; diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/oops/cpCacheOop.cpp --- a/hotspot/src/share/vm/oops/cpCacheOop.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/oops/cpCacheOop.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -185,7 +185,7 @@ this->print(tty, 0); } assert(method->can_be_statically_bound(), "must be a MH invoker method"); - assert(AllowTransitionalJSR292 || _f2 >= constantPoolOopDesc::CPCACHE_INDEX_TAG, "BSM index initialized"); + assert(_f2 >= constantPoolOopDesc::CPCACHE_INDEX_TAG, "BSM index initialized"); // SystemDictionary::find_method_handle_invoke only caches // methods which signature classes are on the boot classpath, // otherwise the newly created method is returned. To avoid diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/oops/instanceKlass.hpp --- a/hotspot/src/share/vm/oops/instanceKlass.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -191,8 +191,6 @@ typeArrayOop _inner_classes; // Implementors of this interface (not valid if it overflows) klassOop _implementors[implementors_limit]; - // invokedynamic bootstrap method (a java.lang.invoke.MethodHandle) - oop _bootstrap_method; // AllowTransitionalJSR292 ONLY // Annotations for this class, or null if none. typeArrayOop _class_annotations; // Annotation objects (byte arrays) for fields, or null if no annotations. @@ -526,10 +524,6 @@ u2 method_index) { _enclosing_method_class_index = class_index; _enclosing_method_method_index = method_index; } - // JSR 292 support - oop bootstrap_method() const { return _bootstrap_method; } // AllowTransitionalJSR292 ONLY - void set_bootstrap_method(oop mh) { oop_store(&_bootstrap_method, mh); } - // jmethodID support static jmethodID get_jmethod_id(instanceKlassHandle ik_h, methodHandle method_h); @@ -793,7 +787,6 @@ oop* adr_signers() const { return (oop*)&this->_signers;} oop* adr_inner_classes() const { return (oop*)&this->_inner_classes;} oop* adr_implementors() const { return (oop*)&this->_implementors[0];} - oop* adr_bootstrap_method() const { return (oop*)&this->_bootstrap_method;} // AllowTransitionalJSR292 ONLY oop* adr_methods_jmethod_ids() const { return (oop*)&this->_methods_jmethod_ids;} oop* adr_methods_cached_itable_indices() const { return (oop*)&this->_methods_cached_itable_indices;} oop* adr_class_annotations() const { return (oop*)&this->_class_annotations;} diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/oops/instanceKlassKlass.cpp --- a/hotspot/src/share/vm/oops/instanceKlassKlass.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/oops/instanceKlassKlass.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -105,7 +105,6 @@ MarkSweep::mark_and_push(ik->adr_protection_domain()); MarkSweep::mark_and_push(ik->adr_host_klass()); MarkSweep::mark_and_push(ik->adr_signers()); - MarkSweep::mark_and_push(ik->adr_bootstrap_method()); MarkSweep::mark_and_push(ik->adr_class_annotations()); MarkSweep::mark_and_push(ik->adr_fields_annotations()); MarkSweep::mark_and_push(ik->adr_methods_annotations()); @@ -142,7 +141,6 @@ PSParallelCompact::mark_and_push(cm, ik->adr_protection_domain()); PSParallelCompact::mark_and_push(cm, ik->adr_host_klass()); PSParallelCompact::mark_and_push(cm, ik->adr_signers()); - PSParallelCompact::mark_and_push(cm, ik->adr_bootstrap_method()); PSParallelCompact::mark_and_push(cm, ik->adr_class_annotations()); PSParallelCompact::mark_and_push(cm, ik->adr_fields_annotations()); PSParallelCompact::mark_and_push(cm, ik->adr_methods_annotations()); @@ -185,7 +183,6 @@ for (int i = 0; i < instanceKlass::implementors_limit; i++) { blk->do_oop(&ik->adr_implementors()[i]); } - blk->do_oop(ik->adr_bootstrap_method()); blk->do_oop(ik->adr_class_annotations()); blk->do_oop(ik->adr_fields_annotations()); blk->do_oop(ik->adr_methods_annotations()); @@ -239,8 +236,6 @@ for (int i = 0; i < instanceKlass::implementors_limit; i++) { if (mr.contains(&adr[i])) blk->do_oop(&adr[i]); } - adr = ik->adr_bootstrap_method(); - if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_class_annotations(); if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_fields_annotations(); @@ -281,7 +276,6 @@ for (int i = 0; i < instanceKlass::implementors_limit; i++) { MarkSweep::adjust_pointer(&ik->adr_implementors()[i]); } - MarkSweep::adjust_pointer(ik->adr_bootstrap_method()); MarkSweep::adjust_pointer(ik->adr_class_annotations()); MarkSweep::adjust_pointer(ik->adr_fields_annotations()); MarkSweep::adjust_pointer(ik->adr_methods_annotations()); @@ -317,11 +311,6 @@ pm->claim_or_forward_depth(sg_addr); } - oop* bsm_addr = ik->adr_bootstrap_method(); - if (PSScavenge::should_scavenge(bsm_addr)) { - pm->claim_or_forward_depth(bsm_addr); - } - klassKlass::oop_push_contents(pm, obj); } @@ -420,7 +409,6 @@ ik->set_breakpoints(NULL); ik->init_previous_versions(); ik->set_generic_signature(NULL); - ik->set_bootstrap_method(NULL); ik->release_set_methods_jmethod_ids(NULL); ik->release_set_methods_cached_itable_indices(NULL); ik->set_class_annotations(NULL); @@ -542,11 +530,6 @@ } // pvw is cleaned up } // rm is cleaned up - if (ik->bootstrap_method() != NULL) { - st->print(BULLET"bootstrap method: "); - ik->bootstrap_method()->print_value_on(st); - st->cr(); - } if (ik->generic_signature() != NULL) { st->print(BULLET"generic signature: "); ik->generic_signature()->print_value_on(st); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/oops/methodOop.cpp --- a/hotspot/src/share/vm/oops/methodOop.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/oops/methodOop.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -852,11 +852,11 @@ bool methodOopDesc::is_method_handle_invoke_name(vmSymbols::SID name_sid) { switch (name_sid) { case vmSymbols::VM_SYMBOL_ENUM_NAME(invokeExact_name): - case vmSymbols::VM_SYMBOL_ENUM_NAME(invokeGeneric_name): + case vmSymbols::VM_SYMBOL_ENUM_NAME(invoke_name): return true; } - if ((AllowTransitionalJSR292 || AllowInvokeForInvokeGeneric) - && name_sid == vmSymbols::VM_SYMBOL_ENUM_NAME(invoke_name)) + if (AllowInvokeGeneric + && name_sid == vmSymbols::VM_SYMBOL_ENUM_NAME(invokeGeneric_name)) return true; return false; } @@ -921,6 +921,10 @@ tty->cr(); } + // invariant: cp->symbol_at_put is preceded by a refcount increment (more usually a lookup) + name->increment_refcount(); + signature->increment_refcount(); + constantPoolHandle cp; { constantPoolOop cp_oop = oopFactory::new_constantPool(_imcp_limit, IsSafeConc, CHECK_(empty)); @@ -1092,7 +1096,6 @@ if (name_id == vmSymbols::NO_SID) return; vmSymbols::SID sig_id = vmSymbols::find_sid(signature()); if (klass_id != vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_MethodHandle) - && !(klass_id == vmSymbols::VM_SYMBOL_ENUM_NAME(java_dyn_MethodHandle) && AllowTransitionalJSR292) && sig_id == vmSymbols::NO_SID) return; jshort flags = access_flags().as_short(); @@ -1118,20 +1121,17 @@ break; // Signature-polymorphic methods: MethodHandle.invoke*, InvokeDynamic.*. - case vmSymbols::VM_SYMBOL_ENUM_NAME(java_dyn_MethodHandle): // AllowTransitionalJSR292 ONLY case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_MethodHandle): if (is_static() || !is_native()) break; switch (name_id) { case vmSymbols::VM_SYMBOL_ENUM_NAME(invokeGeneric_name): + if (!AllowInvokeGeneric) break; + case vmSymbols::VM_SYMBOL_ENUM_NAME(invoke_name): id = vmIntrinsics::_invokeGeneric; break; case vmSymbols::VM_SYMBOL_ENUM_NAME(invokeExact_name): id = vmIntrinsics::_invokeExact; break; - case vmSymbols::VM_SYMBOL_ENUM_NAME(invoke_name): - if (AllowInvokeForInvokeGeneric) id = vmIntrinsics::_invokeGeneric; - else if (AllowTransitionalJSR292) id = vmIntrinsics::_invokeExact; - break; } break; case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_InvokeDynamic): diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/callGenerator.cpp --- a/hotspot/src/share/vm/opto/callGenerator.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/opto/callGenerator.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -978,31 +978,19 @@ return head; } -WarmCallInfo* WarmCallInfo::_always_hot = NULL; -WarmCallInfo* WarmCallInfo::_always_cold = NULL; +WarmCallInfo WarmCallInfo::_always_hot(WarmCallInfo::MAX_VALUE(), WarmCallInfo::MAX_VALUE(), + WarmCallInfo::MIN_VALUE(), WarmCallInfo::MIN_VALUE()); +WarmCallInfo WarmCallInfo::_always_cold(WarmCallInfo::MIN_VALUE(), WarmCallInfo::MIN_VALUE(), + WarmCallInfo::MAX_VALUE(), WarmCallInfo::MAX_VALUE()); WarmCallInfo* WarmCallInfo::always_hot() { - if (_always_hot == NULL) { - static double bits[sizeof(WarmCallInfo) / sizeof(double) + 1] = {0}; - WarmCallInfo* ci = (WarmCallInfo*) bits; - ci->_profit = ci->_count = MAX_VALUE(); - ci->_work = ci->_size = MIN_VALUE(); - _always_hot = ci; - } - assert(_always_hot->is_hot(), "must always be hot"); - return _always_hot; + assert(_always_hot.is_hot(), "must always be hot"); + return &_always_hot; } WarmCallInfo* WarmCallInfo::always_cold() { - if (_always_cold == NULL) { - static double bits[sizeof(WarmCallInfo) / sizeof(double) + 1] = {0}; - WarmCallInfo* ci = (WarmCallInfo*) bits; - ci->_profit = ci->_count = MIN_VALUE(); - ci->_work = ci->_size = MAX_VALUE(); - _always_cold = ci; - } - assert(_always_cold->is_cold(), "must always be cold"); - return _always_cold; + assert(_always_cold.is_cold(), "must always be cold"); + return &_always_cold; } diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/callGenerator.hpp --- a/hotspot/src/share/vm/opto/callGenerator.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/opto/callGenerator.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -215,8 +215,20 @@ WarmCallInfo* next() const { return _next; } void set_next(WarmCallInfo* n) { _next = n; } - static WarmCallInfo* _always_hot; - static WarmCallInfo* _always_cold; + static WarmCallInfo _always_hot; + static WarmCallInfo _always_cold; + + // Constructor intitialization of always_hot and always_cold + WarmCallInfo(float c, float p, float w, float s) { + _call = NULL; + _hot_cg = NULL; + _next = NULL; + _count = c; + _profit = p; + _work = w; + _size = s; + _heat = 0; + } public: // Because WarmInfo objects live over the entire lifetime of the diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/cfgnode.cpp --- a/hotspot/src/share/vm/opto/cfgnode.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/opto/cfgnode.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -1349,9 +1349,17 @@ static void split_once(PhaseIterGVN *igvn, Node *phi, Node *val, Node *n, Node *newn) { igvn->hash_delete(n); // Remove from hash before hacking edges + Node* predicate_proj = NULL; uint j = 1; - for( uint i = phi->req()-1; i > 0; i-- ) { - if( phi->in(i) == val ) { // Found a path with val? + for (uint i = phi->req()-1; i > 0; i--) { + if (phi->in(i) == val) { // Found a path with val? + if (n->is_Region()) { + Node* proj = PhaseIdealLoop::find_predicate(n->in(i)); + if (proj != NULL) { + assert(predicate_proj == NULL, "only one predicate entry expected"); + predicate_proj = proj; + } + } // Add to NEW Region/Phi, no DU info newn->set_req( j++, n->in(i) ); // Remove from OLD Region/Phi @@ -1362,6 +1370,12 @@ // Register the new node but do not transform it. Cannot transform until the // entire Region/Phi conglomerate has been hacked as a single huge transform. igvn->register_new_node_with_optimizer( newn ); + + // Clone loop predicates + if (predicate_proj != NULL) { + newn = igvn->clone_loop_predicates(predicate_proj, newn); + } + // Now I can point to the new node. n->add_req(newn); igvn->_worklist.push(n); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/compile.cpp --- a/hotspot/src/share/vm/opto/compile.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/opto/compile.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -1632,7 +1632,6 @@ igvn.replace_node(n, n->in(1)); } assert(predicate_count()==0, "should be clean!"); - igvn.optimize(); } //------------------------------Optimize--------------------------------------- @@ -1689,7 +1688,7 @@ if((loop_opts_cnt > 0) && (has_loops() || has_split_ifs())) { { TracePhase t2("idealLoop", &_t_idealLoop, true); - PhaseIdealLoop ideal_loop( igvn, true, UseLoopPredicate); + PhaseIdealLoop ideal_loop( igvn, true ); loop_opts_cnt--; if (major_progress()) print_method("PhaseIdealLoop 1", 2); if (failing()) return; @@ -1697,7 +1696,7 @@ // Loop opts pass if partial peeling occurred in previous pass if(PartialPeelLoop && major_progress() && (loop_opts_cnt > 0)) { TracePhase t3("idealLoop", &_t_idealLoop, true); - PhaseIdealLoop ideal_loop( igvn, false, UseLoopPredicate); + PhaseIdealLoop ideal_loop( igvn, false ); loop_opts_cnt--; if (major_progress()) print_method("PhaseIdealLoop 2", 2); if (failing()) return; @@ -1705,7 +1704,7 @@ // Loop opts pass for loop-unrolling before CCP if(major_progress() && (loop_opts_cnt > 0)) { TracePhase t4("idealLoop", &_t_idealLoop, true); - PhaseIdealLoop ideal_loop( igvn, false, UseLoopPredicate); + PhaseIdealLoop ideal_loop( igvn, false ); loop_opts_cnt--; if (major_progress()) print_method("PhaseIdealLoop 3", 2); } @@ -1743,21 +1742,13 @@ // peeling, unrolling, etc. if(loop_opts_cnt > 0) { debug_only( int cnt = 0; ); - bool loop_predication = UseLoopPredicate; while(major_progress() && (loop_opts_cnt > 0)) { TracePhase t2("idealLoop", &_t_idealLoop, true); assert( cnt++ < 40, "infinite cycle in loop optimization" ); - PhaseIdealLoop ideal_loop( igvn, true, loop_predication); + PhaseIdealLoop ideal_loop( igvn, true); loop_opts_cnt--; if (major_progress()) print_method("PhaseIdealLoop iterations", 2); if (failing()) return; - // Perform loop predication optimization during first iteration after CCP. - // After that switch it off and cleanup unused loop predicates. - if (loop_predication) { - loop_predication = false; - cleanup_loop_predicates(igvn); - if (failing()) return; - } } } diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/compile.hpp --- a/hotspot/src/share/vm/opto/compile.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/opto/compile.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -489,6 +489,9 @@ // remove the opaque nodes that protect the predicates so that the unused checks and // uncommon traps will be eliminated from the graph. void cleanup_loop_predicates(PhaseIterGVN &igvn); + bool is_predicate_opaq(Node * n) { + return _predicate_opaqs->contains(n); + } // Compilation environment. Arena* comp_arena() { return &_comp_arena; } diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/doCall.cpp --- a/hotspot/src/share/vm/opto/doCall.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/opto/doCall.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -63,6 +63,7 @@ JVMState* jvms, bool allow_inline, float prof_factor) { CallGenerator* cg; + guarantee(call_method != NULL, "failed method resolution"); // Dtrace currently doesn't work unless all calls are vanilla if (env()->dtrace_method_probes()) { @@ -130,8 +131,9 @@ // Get an adapter for the MethodHandle. ciMethod* target_method = method_handle->get_method_handle_adapter(); - - CallGenerator* hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor); + CallGenerator* hit_cg = NULL; + if (target_method != NULL) + hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor); if (hit_cg != NULL && hit_cg->is_inline()) return hit_cg; } @@ -152,8 +154,9 @@ // Get an adapter for the MethodHandle. ciMethod* target_method = method_handle->get_invokedynamic_adapter(); - - CallGenerator* hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor); + CallGenerator* hit_cg = NULL; + if (target_method != NULL) + hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor); if (hit_cg != NULL && hit_cg->is_inline()) { CallGenerator* miss_cg = CallGenerator::for_dynamic_call(call_method); return CallGenerator::for_predicted_dynamic_call(method_handle, miss_cg, hit_cg, prof_factor); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/escape.cpp --- a/hotspot/src/share/vm/opto/escape.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/opto/escape.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -594,7 +594,7 @@ // // Create a new version of orig_phi if necessary. Returns either the newly -// created phi or an existing phi. Sets create_new to indicate wheter a new +// created phi or an existing phi. Sets create_new to indicate whether a new // phi was created. Cache the last newly created phi in the node map. // PhiNode *ConnectionGraph::create_split_phi(PhiNode *orig_phi, int alias_idx, GrowableArray &orig_phi_worklist, PhaseGVN *igvn, bool &new_created) { @@ -649,7 +649,7 @@ } // -// Return a new version of Memory Phi "orig_phi" with the inputs having the +// Return a new version of Memory Phi "orig_phi" with the inputs having the // specified alias index. // PhiNode *ConnectionGraph::split_memory_phi(PhiNode *orig_phi, int alias_idx, GrowableArray &orig_phi_worklist, PhaseGVN *igvn) { @@ -828,11 +828,15 @@ break; // hit one of our sentinels if (result->is_Mem()) { const Type *at = phase->type(result->in(MemNode::Address)); - if (at != Type::TOP) { - assert (at->isa_ptr() != NULL, "pointer type required."); - int idx = C->get_alias_index(at->is_ptr()); - if (idx == alias_idx) - break; + if (at == Type::TOP) + break; // Dead + assert (at->isa_ptr() != NULL, "pointer type required."); + int idx = C->get_alias_index(at->is_ptr()); + if (idx == alias_idx) + break; // Found + if (!is_instance && (at->isa_oopptr() == NULL || + !at->is_oopptr()->is_known_instance())) { + break; // Do not skip store to general memory slice. } result = result->in(MemNode::Memory); } @@ -902,13 +906,13 @@ PhiNode *mphi = result->as_Phi(); assert(mphi->bottom_type() == Type::MEMORY, "memory phi required"); const TypePtr *t = mphi->adr_type(); - if (C->get_alias_index(t) != alias_idx) { - // Create a new Phi with the specified alias index type. - result = split_memory_phi(mphi, alias_idx, orig_phis, phase); - } else if (!is_instance) { + if (!is_instance) { // Push all non-instance Phis on the orig_phis worklist to update inputs // during Phase 4 if needed. orig_phis.append_if_missing(mphi); + } else if (C->get_alias_index(t) != alias_idx) { + // Create a new Phi with the specified alias index type. + result = split_memory_phi(mphi, alias_idx, orig_phis, phase); } } // the result is either MemNode, PhiNode, InitializeNode. diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/graphKit.cpp --- a/hotspot/src/share/vm/opto/graphKit.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/opto/graphKit.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -3385,10 +3385,15 @@ #define __ ideal. void GraphKit::sync_kit(IdealKit& ideal) { + set_all_memory(__ merged_memory()); + set_i_o(__ i_o()); + set_control(__ ctrl()); +} + +void GraphKit::final_sync(IdealKit& ideal) { // Final sync IdealKit and graphKit. __ drain_delay_transform(); - set_all_memory(__ merged_memory()); - set_control(__ ctrl()); + sync_kit(ideal); } // vanilla/CMS post barrier @@ -3435,7 +3440,7 @@ // (Else it's an array (or unknown), and we want more precise card marks.) assert(adr != NULL, ""); - IdealKit ideal(gvn(), control(), merged_memory(), true); + IdealKit ideal(this, true); // Convert the pointer to an int prior to doing math on it Node* cast = __ CastPX(__ ctrl(), adr); @@ -3461,7 +3466,7 @@ } // Final sync IdealKit and GraphKit. - sync_kit(ideal); + final_sync(ideal); } // G1 pre/post barriers @@ -3471,7 +3476,7 @@ Node* val, const TypeOopPtr* val_type, BasicType bt) { - IdealKit ideal(gvn(), control(), merged_memory(), true); + IdealKit ideal(this, true); Node* tls = __ thread(); // ThreadLocalStorage @@ -3548,7 +3553,7 @@ } __ end_if(); // (!marking) // Final sync IdealKit and GraphKit. - sync_kit(ideal); + final_sync(ideal); } // @@ -3614,7 +3619,7 @@ // (Else it's an array (or unknown), and we want more precise card marks.) assert(adr != NULL, ""); - IdealKit ideal(gvn(), control(), merged_memory(), true); + IdealKit ideal(this, true); Node* tls = __ thread(); // ThreadLocalStorage @@ -3688,6 +3693,6 @@ } // Final sync IdealKit and GraphKit. - sync_kit(ideal); + final_sync(ideal); } #undef __ diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/graphKit.hpp --- a/hotspot/src/share/vm/opto/graphKit.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/opto/graphKit.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -662,7 +662,9 @@ && Universe::heap()->can_elide_tlab_store_barriers()); } + // Sync Ideal and Graph kits. void sync_kit(IdealKit& ideal); + void final_sync(IdealKit& ideal); // vanilla/CMS post barrier void write_barrier_post(Node *store, Node* obj, diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/idealKit.cpp --- a/hotspot/src/share/vm/opto/idealKit.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/opto/idealKit.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -38,15 +38,16 @@ const uint IdealKit::first_var = TypeFunc::Parms + 1; //----------------------------IdealKit----------------------------------------- -IdealKit::IdealKit(PhaseGVN &gvn, Node* control, Node* mem, bool delay_all_transforms, bool has_declarations) : - _gvn(gvn), C(gvn.C) { - _initial_ctrl = control; - _initial_memory = mem; +IdealKit::IdealKit(GraphKit* gkit, bool delay_all_transforms, bool has_declarations) : + _gvn(gkit->gvn()), C(gkit->C) { + _initial_ctrl = gkit->control(); + _initial_memory = gkit->merged_memory(); + _initial_i_o = gkit->i_o(); _delay_all_transforms = delay_all_transforms; _var_ct = 0; _cvstate = NULL; // We can go memory state free or else we need the entire memory state - assert(mem == NULL || mem->Opcode() == Op_MergeMem, "memory must be pre-split"); + assert(_initial_memory == NULL || _initial_memory->Opcode() == Op_MergeMem, "memory must be pre-split"); int init_size = 5; _pending_cvstates = new (C->node_arena()) GrowableArray(C->node_arena(), init_size, 0, 0); _delay_transform = new (C->node_arena()) GrowableArray(C->node_arena(), init_size, 0, 0); @@ -56,6 +57,13 @@ } } +//----------------------------sync_kit----------------------------------------- +void IdealKit::sync_kit(GraphKit* gkit) { + set_all_memory(gkit->merged_memory()); + set_i_o(gkit->i_o()); + set_ctrl(gkit->control()); +} + //-------------------------------if_then------------------------------------- // Create: if(left relop right) // / \ @@ -156,16 +164,14 @@ // onto the stack. 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()); - + if (UseLoopPredicate) { + // Sync IdealKit and graphKit. + gkit->sync_kit(*this); + // Add loop predicate. + gkit->add_predicate(nargs); + // Update IdealKit memory. + sync_kit(gkit); + } set(iv, init); Node* head = make_label(1); bind(head); @@ -280,6 +286,7 @@ _cvstate = new_cvstate(); // initialize current cvstate set_ctrl(_initial_ctrl); // initialize control in current cvstate set_all_memory(_initial_memory);// initialize memory in current cvstate + set_i_o(_initial_i_o); // initialize i_o in current cvstate DEBUG_ONLY(_state->push(BlockS)); } @@ -421,6 +428,9 @@ // Get the region for the join state Node* join_region = join->in(TypeFunc::Control); assert(join_region != NULL, "join region must exist"); + if (join->in(TypeFunc::I_O) == NULL ) { + join->set_req(TypeFunc::I_O, merging->in(TypeFunc::I_O)); + } if (join->in(TypeFunc::Memory) == NULL ) { join->set_req(TypeFunc::Memory, merging->in(TypeFunc::Memory)); return; @@ -467,6 +477,20 @@ mms.set_memory(phi); } } + + Node* join_io = join->in(TypeFunc::I_O); + Node* merging_io = merging->in(TypeFunc::I_O); + if (join_io != merging_io) { + PhiNode* phi; + if (join_io->is_Phi() && join_io->as_Phi()->region() == join_region) { + phi = join_io->as_Phi(); + } else { + phi = PhiNode::make(join_region, join_io, Type::ABIO); + phi = (PhiNode*) delay_transform(phi); + join->set_req(TypeFunc::I_O, phi); + } + phi->set_req(slot, merging_io); + } } @@ -477,7 +501,8 @@ const char *leaf_name, Node* parm0, Node* parm1, - Node* parm2) { + Node* parm2, + Node* parm3) { // We only handle taking in RawMem and modifying RawMem const TypePtr* adr_type = TypeRawPtr::BOTTOM; @@ -498,6 +523,7 @@ if (parm0 != NULL) call->init_req(TypeFunc::Parms+0, parm0); if (parm1 != NULL) call->init_req(TypeFunc::Parms+1, parm1); if (parm2 != NULL) call->init_req(TypeFunc::Parms+2, parm2); + if (parm3 != NULL) call->init_req(TypeFunc::Parms+3, parm3); // Node *c = _gvn.transform(call); call = (CallNode *) _gvn.transform(call); @@ -516,3 +542,51 @@ assert(C->alias_type(call->adr_type()) == C->alias_type(adr_type), "call node must be constructed correctly"); } + + +void IdealKit::make_leaf_call_no_fp(const TypeFunc *slow_call_type, + address slow_call, + const char *leaf_name, + const TypePtr* adr_type, + Node* parm0, + Node* parm1, + Node* parm2, + Node* parm3) { + + // We only handle taking in RawMem and modifying RawMem + uint adr_idx = C->get_alias_index(adr_type); + + // Slow-path leaf call + int size = slow_call_type->domain()->cnt(); + CallNode *call = (CallNode*)new (C, size) CallLeafNoFPNode( slow_call_type, slow_call, leaf_name, adr_type); + + // Set fixed predefined input arguments + call->init_req( TypeFunc::Control, ctrl() ); + call->init_req( TypeFunc::I_O , top() ) ; // does no i/o + // Narrow memory as only memory input + call->init_req( TypeFunc::Memory , memory(adr_idx)); + call->init_req( TypeFunc::FramePtr, top() /* frameptr() */ ); + call->init_req( TypeFunc::ReturnAdr, top() ); + + if (parm0 != NULL) call->init_req(TypeFunc::Parms+0, parm0); + if (parm1 != NULL) call->init_req(TypeFunc::Parms+1, parm1); + if (parm2 != NULL) call->init_req(TypeFunc::Parms+2, parm2); + if (parm3 != NULL) call->init_req(TypeFunc::Parms+3, parm3); + + // Node *c = _gvn.transform(call); + call = (CallNode *) _gvn.transform(call); + Node *c = call; // dbx gets confused with call call->dump() + + // Slow leaf call has no side-effects, sets few values + + set_ctrl(transform( new (C, 1) ProjNode(call,TypeFunc::Control) )); + + // Make memory for the call + Node* mem = _gvn.transform( new (C, 1) ProjNode(call, TypeFunc::Memory) ); + + // Set the RawPtr memory state only. + set_memory(mem, adr_idx); + + assert(C->alias_type(call->adr_type()) == C->alias_type(adr_type), + "call node must be constructed correctly"); +} diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/idealKit.hpp --- a/hotspot/src/share/vm/opto/idealKit.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/opto/idealKit.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -108,6 +108,7 @@ bool _delay_all_transforms; // flag forcing all transforms to be delayed Node* _initial_ctrl; // saves initial control until variables declared Node* _initial_memory; // saves initial memory until variables declared + Node* _initial_i_o; // saves initial i_o until variables declared PhaseGVN& gvn() const { return _gvn; } // Create a new cvstate filled with nulls @@ -142,17 +143,21 @@ Node* memory(uint alias_idx); public: - IdealKit(PhaseGVN &gvn, Node* control, Node* memory, bool delay_all_transforms = false, bool has_declarations = false); + IdealKit(GraphKit* gkit, bool delay_all_transforms = false, bool has_declarations = false); ~IdealKit() { stop(); drain_delay_transform(); } + void sync_kit(GraphKit* gkit); + // Control Node* ctrl() { return _cvstate->in(TypeFunc::Control); } void set_ctrl(Node* ctrl) { _cvstate->set_req(TypeFunc::Control, ctrl); } Node* top() { return C->top(); } MergeMemNode* merged_memory() { return _cvstate->in(TypeFunc::Memory)->as_MergeMem(); } void set_all_memory(Node* mem) { _cvstate->set_req(TypeFunc::Memory, mem); } + Node* i_o() { return _cvstate->in(TypeFunc::I_O); } + void set_i_o(Node* c) { _cvstate->set_req(TypeFunc::I_O, c); } void set(IdealVariable& v, Node* rhs) { _cvstate->set_req(first_var + v.id(), rhs); } Node* value(IdealVariable& v) { return _cvstate->in(first_var + v.id()); } void dead(IdealVariable& v) { set(v, (Node*)NULL); } @@ -239,7 +244,18 @@ const char *leaf_name, Node* parm0, Node* parm1 = NULL, - Node* parm2 = NULL); + Node* parm2 = NULL, + Node* parm3 = NULL); + + void make_leaf_call_no_fp(const TypeFunc *slow_call_type, + address slow_call, + const char *leaf_name, + const TypePtr* adr_type, + Node* parm0, + Node* parm1, + Node* parm2, + Node* parm3); + }; #endif // SHARE_VM_OPTO_IDEALKIT_HPP diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/ifnode.cpp --- a/hotspot/src/share/vm/opto/ifnode.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/opto/ifnode.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -27,6 +27,7 @@ #include "opto/addnode.hpp" #include "opto/cfgnode.hpp" #include "opto/connode.hpp" +#include "opto/loopnode.hpp" #include "opto/phaseX.hpp" #include "opto/runtime.hpp" #include "opto/subnode.hpp" @@ -222,22 +223,35 @@ // Make a region merging constants and a region merging the rest uint req_c = 0; + Node* predicate_proj = NULL; for (uint ii = 1; ii < r->req(); ii++) { - if( phi->in(ii) == con1 ) { + if (phi->in(ii) == con1) { req_c++; } + Node* proj = PhaseIdealLoop::find_predicate(r->in(ii)); + if (proj != NULL) { + assert(predicate_proj == NULL, "only one predicate entry expected"); + predicate_proj = proj; + } } + Node* predicate_c = NULL; + Node* predicate_x = NULL; + Node *region_c = new (igvn->C, req_c + 1) RegionNode(req_c + 1); Node *phi_c = con1; uint len = r->req(); - Node *region_x = new (igvn->C, len - req_c + 1) RegionNode(len - req_c + 1); + Node *region_x = new (igvn->C, len - req_c) RegionNode(len - req_c); Node *phi_x = PhiNode::make_blank(region_x, phi); for (uint i = 1, i_c = 1, i_x = 1; i < len; i++) { - if( phi->in(i) == con1 ) { + if (phi->in(i) == con1) { region_c->init_req( i_c++, r ->in(i) ); + if (r->in(i) == predicate_proj) + predicate_c = predicate_proj; } else { region_x->init_req( i_x, r ->in(i) ); phi_x ->init_req( i_x++, phi->in(i) ); + if (r->in(i) == predicate_proj) + predicate_x = predicate_proj; } } @@ -277,8 +291,20 @@ // Make the true/false arms Node *iff_c_t = phase->transform(new (igvn->C, 1) IfTrueNode (iff_c)); Node *iff_c_f = phase->transform(new (igvn->C, 1) IfFalseNode(iff_c)); + if (predicate_c != NULL) { + assert(predicate_x == NULL, "only one predicate entry expected"); + // Clone loop predicates to each path + iff_c_t = igvn->clone_loop_predicates(predicate_c, iff_c_t); + iff_c_f = igvn->clone_loop_predicates(predicate_c, iff_c_f); + } Node *iff_x_t = phase->transform(new (igvn->C, 1) IfTrueNode (iff_x)); Node *iff_x_f = phase->transform(new (igvn->C, 1) IfFalseNode(iff_x)); + if (predicate_x != NULL) { + assert(predicate_c == NULL, "only one predicate entry expected"); + // Clone loop predicates to each path + iff_x_t = igvn->clone_loop_predicates(predicate_x, iff_x_t); + iff_x_f = igvn->clone_loop_predicates(predicate_x, iff_x_f); + } // Merge the TRUE paths Node *region_s = new (igvn->C, 3) RegionNode(3); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/library_call.cpp --- a/hotspot/src/share/vm/opto/library_call.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/opto/library_call.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -1120,7 +1120,7 @@ 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); - IdealKit kit(gvn(), control(), merged_memory(), false, true); + IdealKit kit(this, false, true); #define __ kit. Node* zero = __ ConI(0); Node* one = __ ConI(1); @@ -1171,7 +1171,7 @@ __ bind(return_); // Final sync IdealKit and GraphKit. - sync_kit(kit); + final_sync(kit); Node* result = __ value(rtn); #undef __ C->set_has_loops(true); @@ -2318,22 +2318,20 @@ // of it. So we need to emit code to conditionally do the proper type of // store. - IdealKit ideal(gvn(), control(), merged_memory()); + IdealKit ideal(this); #define __ ideal. // QQQ who knows what probability is here?? __ if_then(heap_base_oop, BoolTest::ne, null(), PROB_UNLIKELY(0.999)); { // Sync IdealKit and graphKit. - set_all_memory( __ merged_memory()); - set_control(__ ctrl()); + sync_kit(ideal); Node* st = store_oop_to_unknown(control(), heap_base_oop, adr, adr_type, val, type); // Update IdealKit memory. - __ set_all_memory(merged_memory()); - __ set_ctrl(control()); + __ sync_kit(this); } __ else_(); { __ store(__ ctrl(), adr, val, type, alias_type->index(), is_volatile); } __ end_if(); // Final sync IdealKit and GraphKit. - sync_kit(ideal); + final_sync(ideal); #undef __ } } @@ -4294,81 +4292,6 @@ return true; } - -// constants for computing the copy function -enum { - COPYFUNC_UNALIGNED = 0, - COPYFUNC_ALIGNED = 1, // src, dest aligned to HeapWordSize - COPYFUNC_CONJOINT = 0, - COPYFUNC_DISJOINT = 2 // src != dest, or transfer can descend -}; - -// Note: The condition "disjoint" applies also for overlapping copies -// where an descending copy is permitted (i.e., dest_offset <= src_offset). -static address -select_arraycopy_function(BasicType t, bool aligned, bool disjoint, const char* &name, bool dest_uninitialized) { - int selector = - (aligned ? COPYFUNC_ALIGNED : COPYFUNC_UNALIGNED) + - (disjoint ? COPYFUNC_DISJOINT : COPYFUNC_CONJOINT); - -#define RETURN_STUB(xxx_arraycopy) { \ - name = #xxx_arraycopy; \ - return StubRoutines::xxx_arraycopy(); } - -#define RETURN_STUB_PARM(xxx_arraycopy, parm) { \ - name = #xxx_arraycopy; \ - return StubRoutines::xxx_arraycopy(parm); } - - switch (t) { - case T_BYTE: - case T_BOOLEAN: - switch (selector) { - case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jbyte_arraycopy); - case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jbyte_arraycopy); - case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jbyte_disjoint_arraycopy); - case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jbyte_disjoint_arraycopy); - } - case T_CHAR: - case T_SHORT: - switch (selector) { - case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jshort_arraycopy); - case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jshort_arraycopy); - case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jshort_disjoint_arraycopy); - case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jshort_disjoint_arraycopy); - } - case T_INT: - case T_FLOAT: - switch (selector) { - case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jint_arraycopy); - case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jint_arraycopy); - case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jint_disjoint_arraycopy); - case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jint_disjoint_arraycopy); - } - case T_DOUBLE: - case T_LONG: - switch (selector) { - case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jlong_arraycopy); - case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jlong_arraycopy); - case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jlong_disjoint_arraycopy); - case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jlong_disjoint_arraycopy); - } - case T_ARRAY: - case T_OBJECT: - switch (selector) { - case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB_PARM(oop_arraycopy, dest_uninitialized); - case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB_PARM(arrayof_oop_arraycopy, dest_uninitialized); - case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB_PARM(oop_disjoint_arraycopy, dest_uninitialized); - case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB_PARM(arrayof_oop_disjoint_arraycopy, dest_uninitialized); - } - default: - ShouldNotReachHere(); - return NULL; - } - -#undef RETURN_STUB -#undef RETURN_STUB_PARM -} - //------------------------------basictype2arraycopy---------------------------- address LibraryCallKit::basictype2arraycopy(BasicType t, Node* src_offset, @@ -4401,7 +4324,7 @@ disjoint = true; } - return select_arraycopy_function(t, aligned, disjoint, name, dest_uninitialized); + return StubRoutines::select_arraycopy_function(t, aligned, disjoint, name, dest_uninitialized); } diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/loopPredicate.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/opto/loopPredicate.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -0,0 +1,960 @@ +/* + * 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 "opto/loopnode.hpp" +#include "opto/addnode.hpp" +#include "opto/callnode.hpp" +#include "opto/connode.hpp" +#include "opto/loopnode.hpp" +#include "opto/mulnode.hpp" +#include "opto/rootnode.hpp" +#include "opto/subnode.hpp" + +/* + * The general idea of Loop Predication is to insert a predicate on the entry + * path to a loop, and raise a uncommon trap if the check of the condition fails. + * The condition checks are promoted from inside the loop body, and thus + * the checks inside the loop could be eliminated. Currently, loop predication + * optimization has been applied to remove array range check and loop invariant + * checks (such as null checks). +*/ + +//-------------------------------is_uncommon_trap_proj---------------------------- +// Return true if proj is the form of "proj->[region->..]call_uct" +bool PhaseIdealLoop::is_uncommon_trap_proj(ProjNode* proj, Deoptimization::DeoptReason reason) { + int path_limit = 10; + assert(proj, "invalid argument"); + Node* out = proj; + for (int ct = 0; ct < path_limit; ct++) { + out = out->unique_ctrl_out(); + if (out == NULL) + return false; + if (out->is_CallStaticJava()) { + int req = out->as_CallStaticJava()->uncommon_trap_request(); + if (req != 0) { + Deoptimization::DeoptReason trap_reason = Deoptimization::trap_request_reason(req); + if (trap_reason == reason || reason == Deoptimization::Reason_none) { + return true; + } + } + return false; // don't do further after call + } + if (out->Opcode() != Op_Region) + return false; + } + return false; +} + +//-------------------------------is_uncommon_trap_if_pattern------------------------- +// Return true for "if(test)-> proj -> ... +// | +// V +// other_proj->[region->..]call_uct" +// +// "must_reason_predicate" means the uct reason must be Reason_predicate +bool PhaseIdealLoop::is_uncommon_trap_if_pattern(ProjNode *proj, Deoptimization::DeoptReason reason) { + Node *in0 = proj->in(0); + if (!in0->is_If()) return false; + // Variation of a dead If node. + if (in0->outcnt() < 2) return false; + IfNode* iff = in0->as_If(); + + // we need "If(Conv2B(Opaque1(...)))" pattern for reason_predicate + if (reason != Deoptimization::Reason_none) { + if (iff->in(1)->Opcode() != Op_Conv2B || + iff->in(1)->in(1)->Opcode() != Op_Opaque1) { + return false; + } + } + + ProjNode* other_proj = iff->proj_out(1-proj->_con)->as_Proj(); + if (is_uncommon_trap_proj(other_proj, reason)) { + assert(reason == Deoptimization::Reason_none || + Compile::current()->is_predicate_opaq(iff->in(1)->in(1)), "should be on the list"); + return true; + } + return false; +} + +//-------------------------------register_control------------------------- +void PhaseIdealLoop::register_control(Node* n, IdealLoopTree *loop, Node* pred) { + assert(n->is_CFG(), "must be control node"); + _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------------------------ +// create a new if above the uct_if_pattern for the predicate to be promoted. +// +// before after +// ---------- ---------- +// ctrl ctrl +// | | +// | | +// v v +// iff new_iff +// / \ / \ +// / \ / \ +// v v v v +// uncommon_proj cont_proj if_uct if_cont +// \ | | | | +// \ | | | | +// v v v | v +// rgn loop | iff +// | | / \ +// | | / \ +// v | v v +// uncommon_trap | uncommon_proj cont_proj +// \ \ | | +// \ \ | | +// v v v v +// rgn loop +// | +// | +// v +// uncommon_trap +// +// +// We will create a region to guard the uct call if there is no one there. +// The true projecttion (if_cont) of the new_iff is returned. +// This code is also used to clone predicates to clonned loops. +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); + Node *rgn = uncommon_proj->unique_ctrl_out(); + assert(rgn->is_Region() || rgn->is_Call(), "must be a region or call uct"); + + uint proj_index = 1; // region's edge corresponding to uncommon_proj + 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); + rgn->add_req(uncommon_proj); + 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)); + } + } else { + // Find region's edge corresponding to uncommon_proj + for (; proj_index < rgn->req(); proj_index++) + if (rgn->in(proj_index) == uncommon_proj) break; + assert(proj_index < rgn->req(), "sanity"); + } + + Node* entry = iff->in(0); + if (new_entry != NULL) { + // Clonning the predicate to new location. + entry = new_entry; + } + // Create new_iff + IdealLoopTree* lp = get_loop(entry); + IfNode *new_iff = iff->clone()->as_If(); + new_iff->set_req(0, entry); + 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_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); + // 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)); + } + + // If rgn has phis add new edges which has the same + // value as on original uncommon_proj pass. + assert(rgn->in(rgn->req() -1) == if_uct, "new edge should be last"); + bool has_phi = false; + for (DUIterator_Fast imax, i = rgn->fast_outs(imax); i < imax; i++) { + Node* use = rgn->fast_out(i); + if (use->is_Phi() && use->outcnt() > 0) { + assert(use->in(0) == rgn, ""); + _igvn.hash_delete(use); + use->add_req(use->in(proj_index)); + _igvn._worklist.push(use); + has_phi = true; + } + } + assert(!has_phi || rgn->req() > 3, "no phis when region is created"); + + 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(); +} + +//------------------------------create_new_if_for_predicate------------------------ +// Create a new if below new_entry for the predicate to be cloned (IGVN optimization) +ProjNode* PhaseIterGVN::create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry, + Deoptimization::DeoptReason reason) { + assert(new_entry != 0, "only used for clone predicate"); + assert(PhaseIdealLoop::is_uncommon_trap_if_pattern(cont_proj, reason), "must be a uct if pattern!"); + IfNode* iff = cont_proj->in(0)->as_If(); + + ProjNode *uncommon_proj = iff->proj_out(1 - cont_proj->_con); + Node *rgn = uncommon_proj->unique_ctrl_out(); + assert(rgn->is_Region() || rgn->is_Call(), "must be a region or call uct"); + + uint proj_index = 1; // region's edge corresponding to uncommon_proj + if (!rgn->is_Region()) { // create a region to guard the call + assert(rgn->is_Call(), "must be call uct"); + CallNode* call = rgn->as_Call(); + rgn = new (C, 1) RegionNode(1); + register_new_node_with_optimizer(rgn); + rgn->add_req(uncommon_proj); + hash_delete(call); + call->set_req(0, rgn); + } else { + // Find region's edge corresponding to uncommon_proj + for (; proj_index < rgn->req(); proj_index++) + if (rgn->in(proj_index) == uncommon_proj) break; + assert(proj_index < rgn->req(), "sanity"); + } + + // Create new_iff in new location. + IfNode *new_iff = iff->clone()->as_If(); + new_iff->set_req(0, new_entry); + + register_new_node_with_optimizer(new_iff); + 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_new_node_with_optimizer(if_cont); + register_new_node_with_optimizer(if_uct); + + // if_uct to rgn + hash_delete(rgn); + rgn->add_req(if_uct); + + // If rgn has phis add corresponding new edges which has the same + // value as on original uncommon_proj pass. + assert(rgn->in(rgn->req() -1) == if_uct, "new edge should be last"); + bool has_phi = false; + for (DUIterator_Fast imax, i = rgn->fast_outs(imax); i < imax; i++) { + Node* use = rgn->fast_out(i); + if (use->is_Phi() && use->outcnt() > 0) { + hash_delete(use); + use->add_req(use->in(proj_index)); + _worklist.push(use); + has_phi = true; + } + } + assert(!has_phi || rgn->req() > 3, "no phis when region is created"); + + return if_cont->as_Proj(); +} + +//--------------------------clone_predicate----------------------- +ProjNode* PhaseIdealLoop::clone_predicate(ProjNode* predicate_proj, Node* new_entry, + Deoptimization::DeoptReason reason, + PhaseIdealLoop* loop_phase, + PhaseIterGVN* igvn) { + ProjNode* new_predicate_proj; + if (loop_phase != NULL) { + new_predicate_proj = loop_phase->create_new_if_for_predicate(predicate_proj, new_entry, reason); + } else { + new_predicate_proj = igvn->create_new_if_for_predicate(predicate_proj, new_entry, reason); + } + IfNode* iff = new_predicate_proj->in(0)->as_If(); + Node* ctrl = iff->in(0); + + // Match original condition since predicate's projections could be swapped. + assert(predicate_proj->in(0)->in(1)->in(1)->Opcode()==Op_Opaque1, "must be"); + Node* opq = new (igvn->C, 2) Opaque1Node(igvn->C, predicate_proj->in(0)->in(1)->in(1)->in(1)); + igvn->C->add_predicate_opaq(opq); + + Node* bol = new (igvn->C, 2) Conv2BNode(opq); + if (loop_phase != NULL) { + loop_phase->register_new_node(opq, ctrl); + loop_phase->register_new_node(bol, ctrl); + } else { + igvn->register_new_node_with_optimizer(opq); + igvn->register_new_node_with_optimizer(bol); + } + igvn->hash_delete(iff); + iff->set_req(1, bol); + return new_predicate_proj; +} + +//--------------------------move_predicate----------------------- +// Cut predicate from old place and move it to new. +ProjNode* PhaseIdealLoop::move_predicate(ProjNode* predicate_proj, Node* new_entry, + Deoptimization::DeoptReason reason, + PhaseIdealLoop* loop_phase, + PhaseIterGVN* igvn) { + assert(new_entry != NULL, "must be"); + assert(predicate_proj->in(0)->in(1)->in(1)->Opcode()==Op_Opaque1, "must be"); + IfNode* iff = predicate_proj->in(0)->as_If(); + Node* old_entry = iff->in(0); + + // Cut predicate from old place. + Node* old = predicate_proj; + igvn->_worklist.push(old); + for (DUIterator_Last imin, i = old->last_outs(imin); i >= imin; ) { + Node* use = old->last_out(i); // for each use... + igvn->hash_delete(use); + igvn->_worklist.push(use); + // Update use-def info + uint uses_found = 0; + for (uint j = 0; j < use->req(); j++) { + if (use->in(j) == old) { + use->set_req(j, old_entry); + uses_found++; + if (loop_phase != NULL) { + if (use->is_CFG()) { + // When called from beautify_loops() idom is not constructed yet. + if (loop_phase->_idom != NULL) + loop_phase->set_idom(use, old_entry, loop_phase->dom_depth(use)); + } else { + loop_phase->set_ctrl(use, old_entry); + } + } + } + } + i -= uses_found; // we deleted 1 or more copies of this edge + } + + // Move predicate. + igvn->hash_delete(iff); + iff->set_req(0, new_entry); + igvn->_worklist.push(iff); + + if (loop_phase != NULL) { + // Fix up idom and ctrl. + loop_phase->set_ctrl(iff->in(1), new_entry); + loop_phase->set_ctrl(iff->in(1)->in(1), new_entry); + // When called from beautify_loops() idom is not constructed yet. + if (loop_phase->_idom != NULL) + loop_phase->set_idom(iff, new_entry, loop_phase->dom_depth(iff)); + } + + return predicate_proj; +} + +//--------------------------clone_loop_predicates----------------------- +// Interface from IGVN +Node* PhaseIterGVN::clone_loop_predicates(Node* old_entry, Node* new_entry) { + return PhaseIdealLoop::clone_loop_predicates(old_entry, new_entry, false, NULL, this); +} +Node* PhaseIterGVN::move_loop_predicates(Node* old_entry, Node* new_entry) { + return PhaseIdealLoop::clone_loop_predicates(old_entry, new_entry, true, NULL, this); +} + +// Interface from PhaseIdealLoop +Node* PhaseIdealLoop::clone_loop_predicates(Node* old_entry, Node* new_entry) { + return clone_loop_predicates(old_entry, new_entry, false, this, &this->_igvn); +} +Node* PhaseIdealLoop::move_loop_predicates(Node* old_entry, Node* new_entry) { + return clone_loop_predicates(old_entry, new_entry, true, this, &this->_igvn); +} + +// Clone loop predicates to cloned loops (peeled, unswitched, split_if). +Node* PhaseIdealLoop::clone_loop_predicates(Node* old_entry, Node* new_entry, + bool move_predicates, + PhaseIdealLoop* loop_phase, + PhaseIterGVN* igvn) { +#ifdef ASSERT + if (new_entry == NULL || !(new_entry->is_Proj() || new_entry->is_Region() || new_entry->is_SafePoint())) { + if (new_entry != NULL) + new_entry->dump(); + assert(false, "not IfTrue, IfFalse, Region or SafePoint"); + } +#endif + // Search original predicates + Node* entry = old_entry; + if (UseLoopPredicate) { + ProjNode* predicate_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate); + 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"); + if (move_predicates) { + new_entry = move_predicate(predicate_proj, new_entry, + Deoptimization::Reason_predicate, + loop_phase, igvn); + assert(new_entry == predicate_proj, "old predicate fall through projection"); + } else { + // clone predicate + new_entry = clone_predicate(predicate_proj, new_entry, + Deoptimization::Reason_predicate, + loop_phase, igvn); + assert(new_entry != NULL && new_entry->is_Proj(), "IfTrue or IfFalse after clone predicate"); + } + if (TraceLoopPredicate) { + tty->print_cr("Loop Predicate %s: ", move_predicates ? "moved" : "cloned"); + debug_only( new_entry->in(0)->dump(); ) + } + } + } + return new_entry; +} + +//--------------------------eliminate_loop_predicates----------------------- +void PhaseIdealLoop::eliminate_loop_predicates(Node* entry) { + if (UseLoopPredicate) { + ProjNode* predicate_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate); + if (predicate_proj != NULL) { // right pattern that can be used by loop predication + Node* n = entry->in(0)->in(1)->in(1); + assert(n->Opcode()==Op_Opaque1, "must be"); + // Remove Opaque1 node from predicates list. + // IGVN will remove this predicate check. + _igvn.replace_node(n, n->in(1)); + } + } +} + +//--------------------------skip_loop_predicates------------------------------ +// Skip related predicates. +Node* PhaseIdealLoop::skip_loop_predicates(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->is_Proj() && entry->in(0)->in(1)->in(1)->Opcode()==Op_Opaque1, "must be"); + IfNode* iff = entry->in(0)->as_If(); + ProjNode* uncommon_proj = iff->proj_out(1 - entry->as_Proj()->_con); + Node* rgn = uncommon_proj->unique_ctrl_out(); + assert(rgn->is_Region() || rgn->is_Call(), "must be a region or call uct"); + entry = entry->in(0)->in(0); + while (entry != NULL && entry->is_Proj() && entry->in(0)->is_If()) { + uncommon_proj = entry->in(0)->as_If()->proj_out(1 - entry->as_Proj()->_con); + if (uncommon_proj->unique_ctrl_out() != rgn) + break; + entry = entry->in(0)->in(0); + } + } + } + return entry; +} + +//--------------------------find_predicate_insertion_point------------------- +// Find a good location to insert a predicate +ProjNode* PhaseIdealLoop::find_predicate_insertion_point(Node* start_c, Deoptimization::DeoptReason reason) { + if (start_c == NULL || !start_c->is_Proj()) + return NULL; + if (is_uncommon_trap_if_pattern(start_c->as_Proj(), reason)) { + 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. +class Invariance : public StackObj { + VectorSet _visited, _invariant; + Node_Stack _stack; + VectorSet _clone_visited; + Node_List _old_new; // map of old to new (clone) + IdealLoopTree* _lpt; + PhaseIdealLoop* _phase; + + // Helper function to set up the invariance for invariance computation + // If n is a known invariant, set up directly. Otherwise, look up the + // the possibility to push n onto the stack for further processing. + void visit(Node* use, Node* n) { + if (_lpt->is_invariant(n)) { // known invariant + _invariant.set(n->_idx); + } else if (!n->is_CFG()) { + Node *n_ctrl = _phase->ctrl_or_self(n); + Node *u_ctrl = _phase->ctrl_or_self(use); // self if use is a CFG + if (_phase->is_dominator(n_ctrl, u_ctrl)) { + _stack.push(n, n->in(0) == NULL ? 1 : 0); + } + } + } + + // Compute invariance for "the_node" and (possibly) all its inputs recursively + // on the fly + void compute_invariance(Node* n) { + assert(_visited.test(n->_idx), "must be"); + visit(n, n); + while (_stack.is_nonempty()) { + Node* n = _stack.node(); + uint idx = _stack.index(); + if (idx == n->req()) { // all inputs are processed + _stack.pop(); + // n is invariant if it's inputs are all invariant + bool all_inputs_invariant = true; + for (uint i = 0; i < n->req(); i++) { + Node* in = n->in(i); + if (in == NULL) continue; + assert(_visited.test(in->_idx), "must have visited input"); + if (!_invariant.test(in->_idx)) { // bad guy + all_inputs_invariant = false; + break; + } + } + if (all_inputs_invariant) { + _invariant.set(n->_idx); // I am a invariant too + } + } else { // process next input + _stack.set_index(idx + 1); + Node* m = n->in(idx); + if (m != NULL && !_visited.test_set(m->_idx)) { + visit(n, m); + } + } + } + } + + // Helper function to set up _old_new map for clone_nodes. + // If n is a known invariant, set up directly ("clone" of n == n). + // Otherwise, push n onto the stack for real cloning. + void clone_visit(Node* n) { + assert(_invariant.test(n->_idx), "must be invariant"); + if (_lpt->is_invariant(n)) { // known invariant + _old_new.map(n->_idx, n); + } else { // to be cloned + assert(!n->is_CFG(), "should not see CFG here"); + _stack.push(n, n->in(0) == NULL ? 1 : 0); + } + } + + // Clone "n" and (possibly) all its inputs recursively + void clone_nodes(Node* n, Node* ctrl) { + clone_visit(n); + while (_stack.is_nonempty()) { + Node* n = _stack.node(); + uint idx = _stack.index(); + if (idx == n->req()) { // all inputs processed, clone n! + _stack.pop(); + // clone invariant node + Node* n_cl = n->clone(); + _old_new.map(n->_idx, n_cl); + _phase->register_new_node(n_cl, ctrl); + for (uint i = 0; i < n->req(); i++) { + Node* in = n_cl->in(i); + if (in == NULL) continue; + n_cl->set_req(i, _old_new[in->_idx]); + } + } else { // process next input + _stack.set_index(idx + 1); + Node* m = n->in(idx); + if (m != NULL && !_clone_visited.test_set(m->_idx)) { + clone_visit(m); // visit the input + } + } + } + } + + public: + Invariance(Arena* area, IdealLoopTree* lpt) : + _lpt(lpt), _phase(lpt->_phase), + _visited(area), _invariant(area), _stack(area, 10 /* guess */), + _clone_visited(area), _old_new(area) + {} + + // Map old to n for invariance computation and clone + void map_ctrl(Node* old, Node* n) { + assert(old->is_CFG() && n->is_CFG(), "must be"); + _old_new.map(old->_idx, n); // "clone" of old is n + _invariant.set(old->_idx); // old is invariant + _clone_visited.set(old->_idx); + } + + // Driver function to compute invariance + bool is_invariant(Node* n) { + if (!_visited.test_set(n->_idx)) + compute_invariance(n); + return (_invariant.test(n->_idx) != 0); + } + + // Driver function to clone invariant + Node* clone(Node* n, Node* ctrl) { + assert(ctrl->is_CFG(), "must be"); + assert(_invariant.test(n->_idx), "must be an invariant"); + if (!_clone_visited.test(n->_idx)) + clone_nodes(n, ctrl); + return _old_new[n->_idx]; + } +}; + +//------------------------------is_range_check_if ----------------------------------- +// Returns true if the predicate of iff is in "scale*iv + offset u< load_range(ptr)" format +// Note: this function is particularly designed for loop predication. We require load_range +// and offset to be loop invariant computed on the fly by "invar" +bool IdealLoopTree::is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invariance& invar) const { + if (!is_loop_exit(iff)) { + return false; + } + if (!iff->in(1)->is_Bool()) { + return false; + } + const BoolNode *bol = iff->in(1)->as_Bool(); + if (bol->_test._test != BoolTest::lt) { + return false; + } + if (!bol->in(1)->is_Cmp()) { + return false; + } + const CmpNode *cmp = bol->in(1)->as_Cmp(); + if (cmp->Opcode() != Op_CmpU) { + return false; + } + Node* range = cmp->in(2); + if (range->Opcode() != Op_LoadRange) { + const TypeInt* tint = phase->_igvn.type(range)->isa_int(); + if (!OptimizeFill || tint == NULL || tint->empty() || tint->_lo < 0) { + // Allow predication on positive values that aren't LoadRanges. + // This allows optimization of loops where the length of the + // array is a known value and doesn't need to be loaded back + // from the array. + return false; + } + } + if (!invar.is_invariant(range)) { + return false; + } + Node *iv = _head->as_CountedLoop()->phi(); + int scale = 0; + Node *offset = NULL; + if (!phase->is_scaled_iv_plus_offset(cmp->in(1), iv, &scale, &offset)) { + return false; + } + if (offset && !invar.is_invariant(offset)) { // offset must be invariant + return false; + } + return true; +} + +//------------------------------rc_predicate----------------------------------- +// Create a range check predicate +// +// for (i = init; i < limit; i += stride) { +// a[scale*i+offset] +// } +// +// Compute max(scale*i + offset) for init <= i < limit and build the predicate +// as "max(scale*i + offset) u< a.length". +// +// There are two cases for max(scale*i + offset): +// (1) stride*scale > 0 +// max(scale*i + offset) = scale*(limit-stride) + offset +// (2) stride*scale < 0 +// max(scale*i + offset) = scale*init + offset +BoolNode* PhaseIdealLoop::rc_predicate(Node* ctrl, + int scale, Node* offset, + Node* init, Node* limit, Node* stride, + Node* range, bool upper) { + DEBUG_ONLY(ttyLocker ttyl); + if (TraceLoopPredicate) tty->print("rc_predicate "); + + Node* max_idx_expr = init; + int stride_con = stride->get_int(); + if ((stride_con > 0) == (scale > 0) == upper) { + max_idx_expr = new (C, 3) SubINode(limit, stride); + register_new_node(max_idx_expr, ctrl); + if (TraceLoopPredicate) tty->print("(limit - stride) "); + } else { + if (TraceLoopPredicate) tty->print("init "); + } + + if (scale != 1) { + ConNode* con_scale = _igvn.intcon(scale); + max_idx_expr = new (C, 3) MulINode(max_idx_expr, con_scale); + register_new_node(max_idx_expr, ctrl); + if (TraceLoopPredicate) tty->print("* %d ", scale); + } + + if (offset && (!offset->is_Con() || offset->get_int() != 0)){ + max_idx_expr = new (C, 3) AddINode(max_idx_expr, offset); + register_new_node(max_idx_expr, ctrl); + if (TraceLoopPredicate) + if (offset->is_Con()) tty->print("+ %d ", offset->get_int()); + else tty->print("+ offset "); + } + + CmpUNode* cmp = new (C, 3) CmpUNode(max_idx_expr, range); + register_new_node(cmp, ctrl); + BoolNode* bol = new (C, 2) BoolNode(cmp, BoolTest::lt); + register_new_node(bol, ctrl); + + if (TraceLoopPredicate) tty->print_cr("_head->is_Loop()) { + // Could be a simple region when irreducible loops are present. + 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(); + // do nothing for iteration-splitted loops + if (!cl->is_normal_loop()) return false; + } + + LoopNode *lpn = loop->_head->as_Loop(); + Node* entry = lpn->in(LoopNode::EntryControl); + + 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()); + + ResourceArea *area = Thread::current()->resource_area(); + Invariance invar(area, loop); + + // Create list of if-projs such that a newer proj dominates all older + // projs in the list, and they all dominate loop->tail() + Node_List if_proj_list(area); + LoopNode *head = loop->_head->as_Loop(); + Node *current_proj = loop->tail(); //start from tail + while (current_proj != head) { + if (loop == get_loop(current_proj) && // still in the loop ? + current_proj->is_Proj() && // is a projection ? + current_proj->in(0)->Opcode() == Op_If) { // is a if projection ? + if_proj_list.push(current_proj); + } + current_proj = idom(current_proj); + } + + bool hoisted = false; // true if at least one proj is promoted + while (if_proj_list.size() > 0) { + // Following are changed to nonnull when a predicate can be hoisted + ProjNode* new_predicate_proj = NULL; + + ProjNode* proj = if_proj_list.pop()->as_Proj(); + IfNode* iff = proj->in(0)->as_If(); + + if (!is_uncommon_trap_if_pattern(proj, Deoptimization::Reason_none)) { + if (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)). + break; + } else { + // Both arms are inside the loop. There are two cases: + // (1) there is one backward branch. In this case, any remaining proj + // in the if_proj list post-dominates "iff". So, the condition of "iff" + // does not determine the execution the remining projs directly, and we + // can safely continue. + // (2) both arms are forwarded, i.e. a diamond shape. In this case, "proj" + // does not dominate loop->tail(), so it can not be in the if_proj list. + continue; + } + } + + Node* test = iff->in(1); + if (!test->is_Bool()){ //Conv2B, ... + continue; + } + BoolNode* bol = test->as_Bool(); + if (invar.is_invariant(bol)) { + // Invariant test + 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(); + + // Negate test if necessary + bool negated = false; + if (proj->_con != predicate_proj->_con) { + new_predicate_bol = new (C, 2) BoolNode(new_predicate_bol->in(1), new_predicate_bol->_test.negate()); + register_new_node(new_predicate_bol, ctrl); + negated = true; + } + 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); +#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"); + + // Range check for counted loops + const Node* cmp = bol->in(1)->as_Cmp(); + Node* idx = cmp->in(1); + assert(!invar.is_invariant(idx), "index is variant"); + assert(cmp->in(2)->Opcode() == Op_LoadRange || OptimizeFill, "must be"); + Node* rng = cmp->in(2); + assert(invar.is_invariant(rng), "range must be invariant"); + int scale = 1; + Node* offset = zero; + bool ok = is_scaled_iv_plus_offset(idx, cl->phi(), &scale, &offset); + assert(ok, "must be index expression"); + + Node* init = cl->init_trip(); + Node* limit = cl->limit(); + Node* stride = cl->stride(); + + // Build if's for the upper and lower bound tests. The + // 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, 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); + + // Perform cloning to keep Invariance state correct since the + // late schedule will place invariant things in the loop. + rng = invar.clone(rng, ctrl); + if (offset && offset != zero) { + assert(invar.is_invariant(offset), "offset must be loop invariant"); + offset = invar.clone(offset, ctrl); + } + + // Test the lower bound + Node* lower_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, rng, false); + IfNode* lower_bound_iff = lower_bound_proj->in(0)->as_If(); + _igvn.hash_delete(lower_bound_iff); + lower_bound_iff->set_req(1, lower_bound_bol); + if (TraceLoopPredicate) tty->print_cr("lower bound check if: %d", lower_bound_iff->_idx); + + // Test the upper bound + Node* upper_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, rng, true); + IfNode* upper_bound_iff = upper_bound_proj->in(0)->as_If(); + _igvn.hash_delete(upper_bound_iff); + upper_bound_iff->set_req(1, upper_bound_bol); + if (TraceLoopPredicate) tty->print_cr("upper bound check if: %d", lower_bound_iff->_idx); + + // 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 { + // 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 + dominated_by( new_predicate_proj, iff, proj->_con != new_predicate_proj->_con ); + + hoisted = true; + C->set_major_progress(); + } // end while + +#ifndef PRODUCT + // report that the loop predication has been actually performed + // for this loop + if (TraceLoopPredicate && hoisted) { + tty->print("Loop Predication Performed:"); + loop->dump_head(); + } +#endif + + return hoisted; +} + +//------------------------------loop_predication-------------------------------- +// driver routine for loop predication optimization +bool IdealLoopTree::loop_predication( PhaseIdealLoop *phase) { + bool hoisted = false; + // Recursively promote predicates + if (_child) { + hoisted = _child->loop_predication( phase); + } + + // self + if (!_irreducible && !tail()->is_top()) { + hoisted |= phase->loop_predication_impl(this); + } + + if (_next) { //sibling + hoisted |= _next->loop_predication( phase); + } + + return hoisted; +} + diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/loopTransform.cpp --- a/hotspot/src/share/vm/opto/loopTransform.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/opto/loopTransform.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -63,6 +63,46 @@ } } +//------------------------------compute_exact_trip_count----------------------- +// Compute loop exact trip count if possible. Do not recalculate trip count for +// split loops (pre-main-post) which have their limits and inits behind Opaque node. +void IdealLoopTree::compute_exact_trip_count( PhaseIdealLoop *phase ) { + if (!_head->as_Loop()->is_valid_counted_loop()) { + return; + } + CountedLoopNode* cl = _head->as_CountedLoop(); + // Trip count may become nonexact for iteration split loops since + // RCE modifies limits. Note, _trip_count value is not reset since + // it is used to limit unrolling of main loop. + cl->set_nonexact_trip_count(); + + // Loop's test should be part of loop. + if (!phase->is_member(this, phase->get_ctrl(cl->loopexit()->in(CountedLoopEndNode::TestValue)))) + return; // Infinite loop + +#ifdef ASSERT + BoolTest::mask bt = cl->loopexit()->test_trip(); + assert(bt == BoolTest::lt || bt == BoolTest::gt || + bt == BoolTest::ne, "canonical test is expected"); +#endif + + Node* init_n = cl->init_trip(); + Node* limit_n = cl->limit(); + if (init_n != NULL && init_n->is_Con() && + limit_n != NULL && limit_n->is_Con()) { + // Use longs to avoid integer overflow. + int stride_con = cl->stride_con(); + long init_con = cl->init_trip()->get_int(); + long limit_con = cl->limit()->get_int(); + int stride_m = stride_con - (stride_con > 0 ? 1 : -1); + long trip_count = (limit_con - init_con + stride_m)/stride_con; + if (trip_count > 0 && (julong)trip_count < (julong)max_juint) { + // Set exact trip count. + cl->set_exact_trip_count((uint)trip_count); + } + } +} + //------------------------------compute_profile_trip_cnt---------------------------- // Compute loop trip count from profile data as // (backedge_count + loop_exit_count) / loop_exit_count @@ -301,6 +341,132 @@ // peeled-loop backedge has 2 users. // Step 3: Cut the backedge on the clone (so its not a loop) and remove the // extra backedge user. +// +// orig +// +// stmt1 +// | +// v +// loop predicate +// | +// v +// loop<----+ +// | | +// stmt2 | +// | | +// v | +// if ^ +// / \ | +// / \ | +// v v | +// false true | +// / \ | +// / ----+ +// | +// v +// exit +// +// +// after clone loop +// +// stmt1 +// | +// v +// loop predicate +// / \ +// clone / \ orig +// / \ +// / \ +// v v +// +---->loop clone loop<----+ +// | | | | +// | stmt2 clone stmt2 | +// | | | | +// | v v | +// ^ if clone If ^ +// | / \ / \ | +// | / \ / \ | +// | v v v v | +// | true false false true | +// | / \ / \ | +// +---- \ / ----+ +// \ / +// 1v v2 +// region +// | +// v +// exit +// +// +// after peel and predicate move +// +// stmt1 +// / +// / +// clone / orig +// / +// / +----------+ +// / | | +// / loop predicate | +// / | | +// v v | +// TOP-->loop clone loop<----+ | +// | | | | +// stmt2 clone stmt2 | | +// | | | ^ +// v v | | +// if clone If ^ | +// / \ / \ | | +// / \ / \ | | +// v v v v | | +// true false false true | | +// | \ / \ | | +// | \ / ----+ ^ +// | \ / | +// | 1v v2 | +// v region | +// | | | +// | v | +// | exit | +// | | +// +--------------->-----------------+ +// +// +// final graph +// +// stmt1 +// | +// v +// stmt2 clone +// | +// v +// if clone +// / | +// / | +// v v +// false true +// | | +// | v +// | loop predicate +// | | +// | v +// | loop<----+ +// | | | +// | stmt2 | +// | | | +// | v | +// v if ^ +// | / \ | +// | / \ | +// | v v | +// | false true | +// | | \ | +// v v --+ +// region +// | +// v +// exit +// void PhaseIdealLoop::do_peeling( IdealLoopTree *loop, Node_List &old_new ) { C->set_major_progress(); @@ -315,9 +481,10 @@ loop->dump_head(); } #endif - Node *h = loop->_head; - if (h->is_CountedLoop()) { - CountedLoopNode *cl = h->as_CountedLoop(); + Node* head = loop->_head; + bool counted_loop = head->is_CountedLoop(); + if (counted_loop) { + CountedLoopNode *cl = head->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()) { @@ -330,11 +497,11 @@ #endif } } + Node* entry = head->in(LoopNode::EntryControl); // Step 1: Clone the loop body. The clone becomes the peeled iteration. // The pre-loop illegally has 2 control users (old & new loops). - clone_loop( loop, old_new, dom_depth(loop->_head) ); - + clone_loop( loop, old_new, dom_depth(head) ); // Step 2: Make the old-loop fall-in edges point to the peeled iteration. // Do this by making the old-loop fall-in edges act as if they came @@ -342,12 +509,15 @@ // backedges) and then map to the new peeled iteration. This leaves // the pre-loop with only 1 user (the new peeled iteration), but the // peeled-loop backedge has 2 users. - for (DUIterator_Fast jmax, j = loop->_head->fast_outs(jmax); j < jmax; j++) { - Node* old = loop->_head->fast_out(j); - if( old->in(0) == loop->_head && old->req() == 3 && - (old->is_Loop() || old->is_Phi()) ) { - Node *new_exit_value = old_new[old->in(LoopNode::LoopBackControl)->_idx]; - if( !new_exit_value ) // Backedge value is ALSO loop invariant? + Node* new_exit_value = old_new[head->in(LoopNode::LoopBackControl)->_idx]; + new_exit_value = move_loop_predicates(entry, new_exit_value); + _igvn.hash_delete(head); + head->set_req(LoopNode::EntryControl, new_exit_value); + for (DUIterator_Fast jmax, j = head->fast_outs(jmax); j < jmax; j++) { + Node* old = head->fast_out(j); + if (old->in(0) == loop->_head && old->req() == 3 && old->is_Phi()) { + new_exit_value = old_new[old->in(LoopNode::LoopBackControl)->_idx]; + if (!new_exit_value ) // Backedge value is ALSO loop invariant? // Then loop body backedge value remains the same. new_exit_value = old->in(LoopNode::LoopBackControl); _igvn.hash_delete(old); @@ -358,12 +528,12 @@ // Step 3: Cut the backedge on the clone (so its not a loop) and remove the // extra backedge user. - Node *nnn = old_new[loop->_head->_idx]; - _igvn.hash_delete(nnn); - nnn->set_req(LoopNode::LoopBackControl, C->top()); - for (DUIterator_Fast j2max, j2 = nnn->fast_outs(j2max); j2 < j2max; j2++) { - Node* use = nnn->fast_out(j2); - if( use->in(0) == nnn && use->req() == 3 && use->is_Phi() ) { + Node* new_head = old_new[head->_idx]; + _igvn.hash_delete(new_head); + new_head->set_req(LoopNode::LoopBackControl, C->top()); + for (DUIterator_Fast j2max, j2 = new_head->fast_outs(j2max); j2 < j2max; j2++) { + Node* use = new_head->fast_out(j2); + if (use->in(0) == new_head && use->req() == 3 && use->is_Phi()) { _igvn.hash_delete(use); use->set_req(LoopNode::LoopBackControl, C->top()); } @@ -371,15 +541,15 @@ // Step 4: Correct dom-depth info. Set to loop-head depth. - int dd = dom_depth(loop->_head); - set_idom(loop->_head, loop->_head->in(1), dd); + int dd = dom_depth(head); + set_idom(head, head->in(1), dd); for (uint j3 = 0; j3 < loop->_body.size(); j3++) { Node *old = loop->_body.at(j3); Node *nnn = old_new[old->_idx]; if (!has_ctrl(nnn)) set_idom(nnn, idom(nnn), dd-1); // While we're at it, remove any SafePoints from the peeled code - if( old->Opcode() == Op_SafePoint ) { + if (old->Opcode() == Op_SafePoint) { Node *nnn = old_new[old->_idx]; lazy_replace(nnn,nnn->in(TypeFunc::Control)); } @@ -392,34 +562,26 @@ loop->record_for_igvn(); } +#define EMPTY_LOOP_SIZE 7 // number of nodes in an empty loop + //------------------------------policy_maximally_unroll------------------------ -// Return exact loop trip count, or 0 if not maximally unrolling +// Calculate exact loop trip count and return true if loop can be maximally +// unrolled. bool IdealLoopTree::policy_maximally_unroll( PhaseIdealLoop *phase ) const { CountedLoopNode *cl = _head->as_CountedLoop(); assert(cl->is_normal_loop(), ""); - - Node *init_n = cl->init_trip(); - Node *limit_n = cl->limit(); + if (!cl->is_valid_counted_loop()) + return false; // Malformed counted loop - // Non-constant bounds - 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()) { + if (!cl->has_exact_trip_count()) { + // Trip count is not exact. return false; } - int init = init_n->get_int(); - int limit = limit_n->get_int(); - int span = limit - init; - int stride = cl->stride_con(); - if (init >= limit || stride > span) { - // return a false (no maximally unroll) and the regular unroll/peel - // route will make a small mess which CCP will fold away. - return false; - } - uint trip_count = span/stride; // trip_count can be greater than 2 Gig. - assert( (int)trip_count*stride == span, "must divide evenly" ); + uint trip_count = cl->trip_count(); + // Note, max_juint is used to indicate unknown trip count. + assert(trip_count > 1, "one iteration loop should be optimized out already"); + assert(trip_count < max_juint, "exact trip_count should be less than max_uint."); // Real policy: if we maximally unroll, does it get too big? // Allow the unrolled mess to get larger than standard loop @@ -427,15 +589,29 @@ uint body_size = _body.size(); 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) { return false; } + // Take into account that after unroll conjoined heads and tails will fold, + // otherwise policy_unroll() may allow more unrolling than max unrolling. + uint new_body_size = EMPTY_LOOP_SIZE + (body_size - EMPTY_LOOP_SIZE) * trip_count; + uint tst_body_size = (new_body_size - EMPTY_LOOP_SIZE) / trip_count + EMPTY_LOOP_SIZE; + if (body_size != tst_body_size) // Check for int overflow + return false; + if (new_body_size > unroll_limit || + // Unrolling can result in a large amount of node construction + new_body_size >= MaxNodeLimit - phase->C->unique()) { + 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) + // Also fully unroll a loop with few iterations regardless next + // conditions since following loop optimizations will split + // such loop anyway (pre-main-post). + if (trip_count <= 3) return true; // Do not unroll a loop with String intrinsics code. @@ -452,17 +628,7 @@ } // 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 && - // Unrolling can result in a large amount of node construction - new_body_size < MaxNodeLimit - phase->C->unique()) { - return true; // maximally unroll - } - } - - return false; // Do not maximally unroll + return true; // Do maximally unroll } @@ -474,12 +640,15 @@ CountedLoopNode *cl = _head->as_CountedLoop(); 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->is_valid_counted_loop()) + return false; // Malformed counted loop // protect against over-unrolling if (cl->trip_count() <= 1) return false; + // Check for stride being a small enough constant + if (abs(cl->stride_con()) > (1<<3)) return false; + int future_unroll_ct = cl->unrolled_count() * 2; // Don't unroll if the next round of unrolling would push us @@ -560,9 +729,6 @@ return false; } - // Check for stride being a small enough constant - if (abs(cl->stride_con()) > (1<<3)) return false; - // Unroll once! (Each trip will soon do double iterations) return true; } @@ -956,7 +1122,11 @@ tty->print("Unrolling "); loop->dump_head(); } else if (TraceLoopOpts) { - tty->print("Unroll %d ", loop_head->unrolled_count()*2); + if (loop_head->trip_count() < (uint)LoopUnrollLimit) { + tty->print("Unroll %d(%2d) ", loop_head->unrolled_count()*2, loop_head->trip_count()); + } else { + tty->print("Unroll %d ", loop_head->unrolled_count()*2); + } loop->dump_head(); } #endif @@ -1631,7 +1801,7 @@ // 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*/) + if (_body.size() > EMPTY_LOOP_SIZE) return false; if (!_head->is_CountedLoop()) @@ -1658,8 +1828,19 @@ // main and post loops have explicitly created zero trip guard bool needs_guard = !cl->is_main_loop() && !cl->is_post_loop(); if (needs_guard) { + // Skip guard if values not overlap. + const TypeInt* init_t = phase->_igvn.type(cl->init_trip())->is_int(); + const TypeInt* limit_t = phase->_igvn.type(cl->limit())->is_int(); + int stride_con = cl->stride_con(); + if (stride_con > 0) { + needs_guard = (init_t->_hi >= limit_t->_lo); + } else { + needs_guard = (init_t->_lo <= limit_t->_hi); + } + } + if (needs_guard) { // Check for an obvious zero trip guard. - Node* inctrl = cl->in(LoopNode::EntryControl); + Node* inctrl = PhaseIdealLoop::skip_loop_predicates(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); @@ -1702,12 +1883,49 @@ return true; } +//------------------------------policy_do_one_iteration_loop------------------- +// Convert one iteration loop into normal code. +bool IdealLoopTree::policy_do_one_iteration_loop( PhaseIdealLoop *phase ) { + if (!_head->as_Loop()->is_valid_counted_loop()) + return false; // Only for counted loop + + CountedLoopNode *cl = _head->as_CountedLoop(); + if (!cl->has_exact_trip_count() || cl->trip_count() != 1) { + return false; + } + +#ifndef PRODUCT + if(TraceLoopOpts) { + tty->print("OneIteration "); + this->dump_head(); + } +#endif + + Node *init_n = cl->init_trip(); +#ifdef ASSERT + // Loop boundaries should be constant since trip count is exact. + assert(init_n->get_int() + cl->stride_con() >= cl->limit()->get_int(), "should be one iteration"); +#endif + // Replace the phi at loop head with the value of the init_trip. + // Then the CountedLoopEnd will collapse (backedge will not be taken) + // and all loop-invariant uses of the exit values will be correct. + phase->_igvn.replace_node(cl->phi(), cl->init_trip()); + phase->C->set_major_progress(); + return true; +} //============================================================================= //------------------------------iteration_split_impl--------------------------- bool IdealLoopTree::iteration_split_impl( PhaseIdealLoop *phase, Node_List &old_new ) { + // Compute exact loop trip count if possible. + compute_exact_trip_count(phase); + + // Convert one iteration loop into normal code. + if (policy_do_one_iteration_loop(phase)) + return true; + // Check and remove empty loops (spam micro-benchmarks) - if( policy_do_remove_empty_loop(phase) ) + if (policy_do_remove_empty_loop(phase)) return true; // Here we removed an empty loop bool should_peel = policy_peeling(phase); // Should we peel? @@ -1716,40 +1934,40 @@ // Non-counted loops may be peeled; exactly 1 iteration is peeled. // This removes loop-invariant tests (usually null checks). - if( !_head->is_CountedLoop() ) { // Non-counted loop + if (!_head->is_CountedLoop()) { // Non-counted loop if (PartialPeelLoop && phase->partial_peel(this, old_new)) { // Partial peel succeeded so terminate this round of loop opts return false; } - if( should_peel ) { // Should we peel? + if (should_peel) { // Should we peel? #ifndef PRODUCT if (PrintOpto) tty->print_cr("should_peel"); #endif phase->do_peeling(this,old_new); - } else if( should_unswitch ) { + } else if (should_unswitch) { phase->do_unswitching(this, old_new); } return true; } CountedLoopNode *cl = _head->as_CountedLoop(); - if( !cl->loopexit() ) return true; // Ignore various kinds of broken loops + if (!cl->loopexit()) return true; // Ignore various kinds of broken loops // Do nothing special to pre- and post- loops - if( cl->is_pre_loop() || cl->is_post_loop() ) return true; + if (cl->is_pre_loop() || cl->is_post_loop()) return true; // Compute loop trip count from profile data compute_profile_trip_cnt(phase); // Before attempting fancy unrolling, RCE or alignment, see if we want // to completely unroll this loop or do loop unswitching. - if( cl->is_normal_loop() ) { + if (cl->is_normal_loop()) { if (should_unswitch) { phase->do_unswitching(this, old_new); return true; } bool should_maximally_unroll = policy_maximally_unroll(phase); - if( should_maximally_unroll ) { + if (should_maximally_unroll) { // Here we did some unrolling and peeling. Eventually we will // completely unroll this loop and it will no longer be a loop. phase->do_maximally_unroll(this,old_new); @@ -1757,6 +1975,12 @@ } } + // Skip next optimizations if running low on nodes. Note that + // policy_unswitching and policy_maximally_unroll have this check. + uint nodes_left = MaxNodeLimit - phase->C->unique(); + if ((2 * _body.size()) > nodes_left) { + return true; + } // Counted loops may be peeled, may need some iterations run up // front for RCE, and may want to align loop refs to a cache @@ -1787,14 +2011,14 @@ // If we have any of these conditions (RCE, alignment, unrolling) met, then // we switch to the pre-/main-/post-loop model. This model also covers // peeling. - if( should_rce || should_align || should_unroll ) { - if( cl->is_normal_loop() ) // Convert to 'pre/main/post' loops + if (should_rce || should_align || should_unroll) { + if (cl->is_normal_loop()) // Convert to 'pre/main/post' loops phase->insert_pre_post_loops(this,old_new, !may_rce_align); // Adjust the pre- and main-loop limits to let the pre and post loops run // with full checks, but the main-loop with no checks. Remove said // checks from the main body. - if( should_rce ) + if (should_rce) phase->do_range_check(this,old_new); // Double loop body for unrolling. Adjust the minimum-trip test (will do @@ -1802,16 +2026,16 @@ // an even number of trips). If we are peeling, we might enable some RCE // and we'd rather unroll the post-RCE'd loop SO... do not unroll if // peeling. - if( should_unroll && !should_peel ) - phase->do_unroll(this,old_new, true); + if (should_unroll && !should_peel) + phase->do_unroll(this,old_new, true); // Adjust the pre-loop limits to align the main body // iterations. - if( should_align ) + if (should_align) Unimplemented(); } else { // Else we have an unchanged counted loop - if( should_peel ) // Might want to peel but do nothing else + if (should_peel) // Might want to peel but do nothing else phase->do_peeling(this,old_new); } return true; @@ -1861,651 +2085,8 @@ 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, Deoptimization::DeoptReason reason) { - int path_limit = 10; - assert(proj, "invalid argument"); - Node* out = proj; - for (int ct = 0; ct < path_limit; ct++) { - out = out->unique_ctrl_out(); - if (out == NULL || out->is_Root() || out->is_Start()) - return false; - if (out->is_CallStaticJava()) { - int req = out->as_CallStaticJava()->uncommon_trap_request(); - if (req != 0) { - Deoptimization::DeoptReason trap_reason = Deoptimization::trap_request_reason(req); - if (trap_reason == reason || reason == Deoptimization::Reason_none) { - return true; - } - } - return false; // don't do further after call - } - } - return false; -} -//-------------------------------is_uncommon_trap_if_pattern------------------------- -// Return true for "if(test)-> proj -> ... -// | -// V -// other_proj->[region->..]call_uct" -// -// "must_reason_predicate" means the uct reason must be Reason_predicate -bool PhaseIdealLoop::is_uncommon_trap_if_pattern(ProjNode *proj, Deoptimization::DeoptReason reason) { - Node *in0 = proj->in(0); - if (!in0->is_If()) return false; - // Variation of a dead If node. - if (in0->outcnt() < 2) return false; - IfNode* iff = in0->as_If(); - - // we need "If(Conv2B(Opaque1(...)))" pattern for reason_predicate - if (reason != Deoptimization::Reason_none) { - if (iff->in(1)->Opcode() != Op_Conv2B || - iff->in(1)->in(1)->Opcode() != Op_Opaque1) { - return false; - } - } - - ProjNode* other_proj = iff->proj_out(1-proj->_con)->as_Proj(); - 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------------------------ -// create a new if above the uct_if_pattern for the predicate to be promoted. -// -// before after -// ---------- ---------- -// ctrl ctrl -// | | -// | | -// v v -// iff new_iff -// / \ / \ -// / \ / \ -// v v v v -// uncommon_proj cont_proj if_uct if_cont -// \ | | | | -// \ | | | | -// v v v | v -// rgn loop | iff -// | | / \ -// | | / \ -// v | v v -// uncommon_trap | uncommon_proj cont_proj -// \ \ | | -// \ \ | | -// v v v v -// rgn loop -// | -// | -// v -// uncommon_trap -// -// -// We will create a region to guard the uct call if there is no one there. -// The true projecttion (if_cont) of the new_iff is returned. -// This code is also used to clone predicates to clonned loops. -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); - Node *rgn = uncommon_proj->unique_ctrl_out(); - assert(rgn->is_Region() || rgn->is_Call(), "must be a region or call uct"); - - 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); - rgn->add_req(uncommon_proj); - 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 - 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_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); - // 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 a good location to insert a predicate -ProjNode* PhaseIdealLoop::find_predicate_insertion_point(Node* start_c, Deoptimization::DeoptReason reason) { - if (start_c == NULL || !start_c->is_Proj()) - return NULL; - if (is_uncommon_trap_if_pattern(start_c->as_Proj(), reason)) { - 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. -class Invariance : public StackObj { - VectorSet _visited, _invariant; - Node_Stack _stack; - VectorSet _clone_visited; - Node_List _old_new; // map of old to new (clone) - IdealLoopTree* _lpt; - PhaseIdealLoop* _phase; - - // Helper function to set up the invariance for invariance computation - // If n is a known invariant, set up directly. Otherwise, look up the - // the possibility to push n onto the stack for further processing. - void visit(Node* use, Node* n) { - if (_lpt->is_invariant(n)) { // known invariant - _invariant.set(n->_idx); - } else if (!n->is_CFG()) { - Node *n_ctrl = _phase->ctrl_or_self(n); - Node *u_ctrl = _phase->ctrl_or_self(use); // self if use is a CFG - if (_phase->is_dominator(n_ctrl, u_ctrl)) { - _stack.push(n, n->in(0) == NULL ? 1 : 0); - } - } - } - - // Compute invariance for "the_node" and (possibly) all its inputs recursively - // on the fly - void compute_invariance(Node* n) { - assert(_visited.test(n->_idx), "must be"); - visit(n, n); - while (_stack.is_nonempty()) { - Node* n = _stack.node(); - uint idx = _stack.index(); - if (idx == n->req()) { // all inputs are processed - _stack.pop(); - // n is invariant if it's inputs are all invariant - bool all_inputs_invariant = true; - for (uint i = 0; i < n->req(); i++) { - Node* in = n->in(i); - if (in == NULL) continue; - assert(_visited.test(in->_idx), "must have visited input"); - if (!_invariant.test(in->_idx)) { // bad guy - all_inputs_invariant = false; - break; - } - } - if (all_inputs_invariant) { - _invariant.set(n->_idx); // I am a invariant too - } - } else { // process next input - _stack.set_index(idx + 1); - Node* m = n->in(idx); - if (m != NULL && !_visited.test_set(m->_idx)) { - visit(n, m); - } - } - } - } - - // Helper function to set up _old_new map for clone_nodes. - // If n is a known invariant, set up directly ("clone" of n == n). - // Otherwise, push n onto the stack for real cloning. - void clone_visit(Node* n) { - assert(_invariant.test(n->_idx), "must be invariant"); - if (_lpt->is_invariant(n)) { // known invariant - _old_new.map(n->_idx, n); - } else{ // to be cloned - assert (!n->is_CFG(), "should not see CFG here"); - _stack.push(n, n->in(0) == NULL ? 1 : 0); - } - } - - // Clone "n" and (possibly) all its inputs recursively - void clone_nodes(Node* n, Node* ctrl) { - clone_visit(n); - while (_stack.is_nonempty()) { - Node* n = _stack.node(); - uint idx = _stack.index(); - if (idx == n->req()) { // all inputs processed, clone n! - _stack.pop(); - // clone invariant node - Node* n_cl = n->clone(); - _old_new.map(n->_idx, n_cl); - _phase->register_new_node(n_cl, ctrl); - for (uint i = 0; i < n->req(); i++) { - Node* in = n_cl->in(i); - if (in == NULL) continue; - n_cl->set_req(i, _old_new[in->_idx]); - } - } else { // process next input - _stack.set_index(idx + 1); - Node* m = n->in(idx); - if (m != NULL && !_clone_visited.test_set(m->_idx)) { - clone_visit(m); // visit the input - } - } - } - } - - public: - Invariance(Arena* area, IdealLoopTree* lpt) : - _lpt(lpt), _phase(lpt->_phase), - _visited(area), _invariant(area), _stack(area, 10 /* guess */), - _clone_visited(area), _old_new(area) - {} - - // Map old to n for invariance computation and clone - void map_ctrl(Node* old, Node* n) { - assert(old->is_CFG() && n->is_CFG(), "must be"); - _old_new.map(old->_idx, n); // "clone" of old is n - _invariant.set(old->_idx); // old is invariant - _clone_visited.set(old->_idx); - } - - // Driver function to compute invariance - bool is_invariant(Node* n) { - if (!_visited.test_set(n->_idx)) - compute_invariance(n); - return (_invariant.test(n->_idx) != 0); - } - - // Driver function to clone invariant - Node* clone(Node* n, Node* ctrl) { - assert(ctrl->is_CFG(), "must be"); - assert(_invariant.test(n->_idx), "must be an invariant"); - if (!_clone_visited.test(n->_idx)) - clone_nodes(n, ctrl); - return _old_new[n->_idx]; - } -}; - -//------------------------------is_range_check_if ----------------------------------- -// Returns true if the predicate of iff is in "scale*iv + offset u< load_range(ptr)" format -// Note: this function is particularly designed for loop predication. We require load_range -// and offset to be loop invariant computed on the fly by "invar" -bool IdealLoopTree::is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invariance& invar) const { - if (!is_loop_exit(iff)) { - return false; - } - if (!iff->in(1)->is_Bool()) { - return false; - } - const BoolNode *bol = iff->in(1)->as_Bool(); - if (bol->_test._test != BoolTest::lt) { - return false; - } - if (!bol->in(1)->is_Cmp()) { - return false; - } - const CmpNode *cmp = bol->in(1)->as_Cmp(); - if (cmp->Opcode() != Op_CmpU ) { - return false; - } - Node* range = cmp->in(2); - if (range->Opcode() != Op_LoadRange) { - const TypeInt* tint = phase->_igvn.type(range)->isa_int(); - if (!OptimizeFill || tint == NULL || tint->empty() || tint->_lo < 0) { - // Allow predication on positive values that aren't LoadRanges. - // This allows optimization of loops where the length of the - // array is a known value and doesn't need to be loaded back - // from the array. - return false; - } - } - if (!invar.is_invariant(range)) { - return false; - } - Node *iv = _head->as_CountedLoop()->phi(); - int scale = 0; - Node *offset = NULL; - if (!phase->is_scaled_iv_plus_offset(cmp->in(1), iv, &scale, &offset)) { - return false; - } - if(offset && !invar.is_invariant(offset)) { // offset must be invariant - return false; - } - return true; -} - -//------------------------------rc_predicate----------------------------------- -// Create a range check predicate -// -// for (i = init; i < limit; i += stride) { -// a[scale*i+offset] -// } -// -// Compute max(scale*i + offset) for init <= i < limit and build the predicate -// as "max(scale*i + offset) u< a.length". -// -// There are two cases for max(scale*i + offset): -// (1) stride*scale > 0 -// max(scale*i + offset) = scale*(limit-stride) + offset -// (2) stride*scale < 0 -// max(scale*i + offset) = scale*init + offset -BoolNode* PhaseIdealLoop::rc_predicate(Node* ctrl, - int scale, Node* offset, - Node* init, Node* limit, Node* stride, - Node* range, bool upper) { - DEBUG_ONLY(ttyLocker ttyl); - if (TraceLoopPredicate) tty->print("rc_predicate "); - - Node* max_idx_expr = init; - int stride_con = stride->get_int(); - if ((stride_con > 0) == (scale > 0) == upper) { - max_idx_expr = new (C, 3) SubINode(limit, stride); - register_new_node(max_idx_expr, ctrl); - if (TraceLoopPredicate) tty->print("(limit - stride) "); - } else { - if (TraceLoopPredicate) tty->print("init "); - } - - if (scale != 1) { - ConNode* con_scale = _igvn.intcon(scale); - max_idx_expr = new (C, 3) MulINode(max_idx_expr, con_scale); - register_new_node(max_idx_expr, ctrl); - if (TraceLoopPredicate) tty->print("* %d ", scale); - } - - if (offset && (!offset->is_Con() || offset->get_int() != 0)){ - max_idx_expr = new (C, 3) AddINode(max_idx_expr, offset); - register_new_node(max_idx_expr, ctrl); - if (TraceLoopPredicate) - if (offset->is_Con()) tty->print("+ %d ", offset->get_int()); - else tty->print("+ offset "); - } - - CmpUNode* cmp = new (C, 3) CmpUNode(max_idx_expr, range); - register_new_node(cmp, ctrl); - BoolNode* bol = new (C, 2) BoolNode(cmp, BoolTest::lt); - register_new_node(bol, ctrl); - - if (TraceLoopPredicate) tty->print_cr("_head->is_Loop()) { - // Could be a simple region when irreducible loops are present. - 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(); - // do nothing for iteration-splitted loops - if (!cl->is_normal_loop()) return false; - } - - LoopNode *lpn = loop->_head->as_Loop(); - Node* entry = lpn->in(LoopNode::EntryControl); - - 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()); - - ResourceArea *area = Thread::current()->resource_area(); - Invariance invar(area, loop); - - // Create list of if-projs such that a newer proj dominates all older - // projs in the list, and they all dominate loop->tail() - Node_List if_proj_list(area); - LoopNode *head = loop->_head->as_Loop(); - Node *current_proj = loop->tail(); //start from tail - while ( current_proj != head ) { - if (loop == get_loop(current_proj) && // still in the loop ? - current_proj->is_Proj() && // is a projection ? - current_proj->in(0)->Opcode() == Op_If) { // is a if projection ? - if_proj_list.push(current_proj); - } - current_proj = idom(current_proj); - } - - bool hoisted = false; // true if at least one proj is promoted - while (if_proj_list.size() > 0) { - // Following are changed to nonnull when a predicate can be hoisted - ProjNode* new_predicate_proj = NULL; - - ProjNode* proj = if_proj_list.pop()->as_Proj(); - IfNode* iff = proj->in(0)->as_If(); - - if (!is_uncommon_trap_if_pattern(proj, Deoptimization::Reason_none)) { - if (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)). - break; - } else { - // Both arms are inside the loop. There are two cases: - // (1) there is one backward branch. In this case, any remaining proj - // in the if_proj list post-dominates "iff". So, the condition of "iff" - // does not determine the execution the remining projs directly, and we - // can safely continue. - // (2) both arms are forwarded, i.e. a diamond shape. In this case, "proj" - // does not dominate loop->tail(), so it can not be in the if_proj list. - continue; - } - } - - Node* test = iff->in(1); - if (!test->is_Bool()){ //Conv2B, ... - continue; - } - BoolNode* bol = test->as_Bool(); - if (invar.is_invariant(bol)) { - // Invariant test - 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(); - - // Negate test if necessary - bool negated = false; - if (proj->_con != predicate_proj->_con) { - new_predicate_bol = new (C, 2) BoolNode(new_predicate_bol->in(1), new_predicate_bol->_test.negate()); - register_new_node(new_predicate_bol, ctrl); - negated = true; - } - 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); -#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"); - - // Range check for counted loops - const Node* cmp = bol->in(1)->as_Cmp(); - Node* idx = cmp->in(1); - assert(!invar.is_invariant(idx), "index is variant"); - assert(cmp->in(2)->Opcode() == Op_LoadRange || OptimizeFill, "must be"); - Node* rng = cmp->in(2); - assert(invar.is_invariant(rng), "range must be invariant"); - int scale = 1; - Node* offset = zero; - bool ok = is_scaled_iv_plus_offset(idx, cl->phi(), &scale, &offset); - assert(ok, "must be index expression"); - - Node* init = cl->init_trip(); - Node* limit = cl->limit(); - Node* stride = cl->stride(); - - // Build if's for the upper and lower bound tests. The - // 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, 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); - - // Perform cloning to keep Invariance state correct since the - // late schedule will place invariant things in the loop. - rng = invar.clone(rng, ctrl); - if (offset && offset != zero) { - assert(invar.is_invariant(offset), "offset must be loop invariant"); - offset = invar.clone(offset, ctrl); - } - - // Test the lower bound - Node* lower_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, rng, false); - IfNode* lower_bound_iff = lower_bound_proj->in(0)->as_If(); - _igvn.hash_delete(lower_bound_iff); - lower_bound_iff->set_req(1, lower_bound_bol); - if (TraceLoopPredicate) tty->print_cr("lower bound check if: %d", lower_bound_iff->_idx); - - // Test the upper bound - Node* upper_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, rng, true); - IfNode* upper_bound_iff = upper_bound_proj->in(0)->as_If(); - _igvn.hash_delete(upper_bound_iff); - upper_bound_iff->set_req(1, upper_bound_bol); - if (TraceLoopPredicate) tty->print_cr("upper bound check if: %d", lower_bound_iff->_idx); - - // 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 { - // 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 - dominated_by( new_predicate_proj, iff, proj->_con != new_predicate_proj->_con ); - - hoisted = true; - C->set_major_progress(); - } // end while - -#ifndef PRODUCT - // report that the loop predication has been actually performed - // for this loop - if (TraceLoopPredicate && hoisted) { - tty->print("Loop Predication Performed:"); - loop->dump_head(); - } -#endif - - return hoisted; -} - -//------------------------------loop_predication-------------------------------- -// driver routine for loop predication optimization -bool IdealLoopTree::loop_predication( PhaseIdealLoop *phase) { - bool hoisted = false; - // Recursively promote predicates - if ( _child ) { - hoisted = _child->loop_predication( phase); - } - - // self - if (!_irreducible && !tail()->is_top()) { - hoisted |= phase->loop_predication_impl(this); - } - - if ( _next ) { //sibling - hoisted |= _next->loop_predication( phase); - } - - return hoisted; -} - - +//============================================================================= // Process all the loops in the loop tree and replace any fill // patterns with an intrisc version. bool PhaseIdealLoop::do_intrinsify_fill() { @@ -2625,9 +2206,12 @@ if (value != head->phi()) { msg = "unhandled shift in address"; } else { - found_index = true; - shift = n; - assert(type2aelembytes(store->as_Mem()->memory_type(), true) == 1 << shift->in(2)->get_int(), "scale should match"); + if (type2aelembytes(store->as_Mem()->memory_type(), true) != (1 << n->in(2)->get_int())) { + msg = "scale doesn't match"; + } else { + found_index = true; + shift = n; + } } } else if (n->Opcode() == Op_ConvI2L && conv == NULL) { if (n->in(1) == head->phi()) { @@ -2762,6 +2346,13 @@ return false; } +#ifndef PRODUCT + if (TraceLoopOpts) { + tty->print("ArrayFill "); + lpt->dump_head(); + } +#endif + // Now replace the whole loop body by a call to a fill routine that // covers the same region as the loop. Node* base = store->in(MemNode::Address)->as_AddP()->in(AddPNode::Base); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/loopUnswitch.cpp --- a/hotspot/src/share/vm/opto/loopUnswitch.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/opto/loopUnswitch.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -32,15 +32,17 @@ // // orig: transformed: // if (invariant-test) then +// predicate predicate // loop loop // stmt1 stmt1 // if (invariant-test) then stmt2 // stmt2 stmt4 // else endloop // stmt3 else -// endif loop [clone] -// stmt4 stmt1 [clone] -// endloop stmt3 +// endif predicate [clone] +// stmt4 loop [clone] +// endloop stmt1 [clone] +// stmt3 // stmt4 [clone] // endloop // endif @@ -124,8 +126,15 @@ ProjNode* proj_true = create_slow_version_of_loop(loop, old_new); - assert(proj_true->is_IfTrue() && proj_true->unique_ctrl_out() == head, "by construction"); - +#ifdef ASSERT + Node* uniqc = proj_true->unique_ctrl_out(); + Node* entry = head->in(LoopNode::EntryControl); + Node* predicate = find_predicate(entry); + if (predicate != NULL) predicate = predicate->in(0); + assert(proj_true->is_IfTrue() && + (predicate == NULL && uniqc == head || + predicate != NULL && uniqc == predicate), "by construction"); +#endif // Increment unswitch count LoopNode* head_clone = old_new[head->_idx]->as_Loop(); int nct = head->unswitch_count() + 1; @@ -227,21 +236,24 @@ register_node(ifslow, outer_loop, iff, dom_depth(iff)); // Clone the loop body. The clone becomes the fast loop. The - // original pre-header will (illegally) have 2 control users (old & new loops). + // original pre-header will (illegally) have 3 control users + // (old & new loops & new if). clone_loop(loop, old_new, dom_depth(head), iff); assert(old_new[head->_idx]->is_Loop(), "" ); // Fast (true) control + Node* iffast_pred = clone_loop_predicates(entry, iffast); _igvn.hash_delete(head); - head->set_req(LoopNode::EntryControl, iffast); - set_idom(head, iffast, dom_depth(head)); + head->set_req(LoopNode::EntryControl, iffast_pred); + set_idom(head, iffast_pred, dom_depth(head)); _igvn._worklist.push(head); // Slow (false) control + Node* ifslow_pred = move_loop_predicates(entry, ifslow); LoopNode* slow_head = old_new[head->_idx]->as_Loop(); _igvn.hash_delete(slow_head); - slow_head->set_req(LoopNode::EntryControl, ifslow); - set_idom(slow_head, ifslow, dom_depth(slow_head)); + slow_head->set_req(LoopNode::EntryControl, ifslow_pred); + set_idom(slow_head, ifslow_pred, dom_depth(slow_head)); _igvn._worklist.push(slow_head); recompute_dom_depth(); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/loopnode.cpp --- a/hotspot/src/share/vm/opto/loopnode.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/opto/loopnode.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -341,7 +341,12 @@ // assert(x->Opcode() == Op_Loop, "regular loops only"); C->print_method("Before CountedLoop", 3); - +#ifndef PRODUCT + if (TraceLoopOpts) { + tty->print("Counted "); + loop->dump_head(); + } +#endif // 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. @@ -864,8 +869,10 @@ Node *outer = new (phase->C, 3) LoopNode( ctl, _head->in(outer_idx) ); outer = igvn.register_new_node_with_optimizer(outer, _head); phase->set_created_loop_node(); + + Node* pred = phase->clone_loop_predicates(ctl, outer); // Outermost loop falls into '_head' loop - _head->set_req(LoopNode::EntryControl, outer); + _head->set_req(LoopNode::EntryControl, pred); _head->del_req(outer_idx); // Split all the Phis up between '_head' loop and 'outer' loop. for (DUIterator_Fast jmax, j = _head->fast_outs(jmax); j < jmax; j++) { @@ -1103,12 +1110,13 @@ // backedges into a private merge point and use the merge point as // the one true backedge. if( _head->req() > 3 ) { - // Merge the many backedges into a single backedge. + // Merge the many backedges into a single backedge but leave + // the hottest backedge as separate edge for the following peel. merge_many_backedges( phase ); result = true; } - // If I am a shared header (multiple backedges), peel off myself loop. + // If I have one hot backedge, peel off myself loop. // I better be the outermost loop. if( _head->req() > 3 ) { split_outer_loop( phase ); @@ -1433,15 +1441,30 @@ tty->print("Loop: N%d/N%d ",_head->_idx,_tail->_idx); 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)) { + Node* entry = PhaseIdealLoop::find_predicate_insertion_point(_head->in(LoopNode::EntryControl), + Deoptimization::Reason_predicate); + if (entry != NULL) { tty->print(" predicated"); } } if (_head->is_CountedLoop()) { CountedLoopNode *cl = _head->as_CountedLoop(); tty->print(" counted"); + + Node* init_n = cl->init_trip(); + if (init_n != NULL && init_n->is_Con()) + tty->print(" [%d,", cl->init_trip()->get_int()); + else + tty->print(" [int,"); + Node* limit_n = cl->limit(); + if (limit_n != NULL && limit_n->is_Con()) + tty->print("%d),", cl->limit()->get_int()); + else + tty->print("int),"); + int stride_con = cl->stride_con(); + if (stride_con > 0) tty->print("+"); + tty->print("%d", stride_con); + if (cl->is_pre_loop ()) tty->print(" pre" ); if (cl->is_main_loop()) tty->print(" main"); if (cl->is_post_loop()) tty->print(" post"); @@ -1541,7 +1564,7 @@ //----------------------------build_and_optimize------------------------------- // Create a PhaseLoop. Build the ideal Loop tree. Map each Ideal Node to // its corresponding LoopNode. If 'optimize' is true, do some loop cleanups. -void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool do_loop_pred) { +void PhaseIdealLoop::build_and_optimize(bool do_split_ifs) { ResourceMark rm; int old_progress = C->major_progress(); @@ -1573,6 +1596,13 @@ // Do not need a safepoint at the top level _ltree_root->_has_sfpt = 1; + // Initialize Dominators. + // Checked in clone_loop_predicate() during beautify_loops(). + _idom_size = 0; + _idom = NULL; + _dom_depth = NULL; + _dom_stk = NULL; + // Empty pre-order array allocate_preorders(); @@ -1698,8 +1728,9 @@ return; } - // some parser-inserted loop predicates could never be used by loop - // predication. Eliminate them before loop optimization + // Some parser-inserted loop predicates could never be used by loop + // predication or they were moved away from loop during some optimizations. + // For example, peeling. Eliminate them before next loop optimizations. if (UseLoopPredicate) { eliminate_useless_predicates(); } @@ -1750,7 +1781,7 @@ } // Perform loop predication before iteration splitting - if (do_loop_pred && C->has_loops() && !C->major_progress()) { + if (C->has_loops() && !C->major_progress() && (C->predicate_count() > 0)) { _ltree_root->_child->loop_predication(this); } @@ -1793,8 +1824,20 @@ C->set_major_progress(); } - // Convert scalar to superword operations + // Keep loop predicates and perform optimizations with them + // until no more loop optimizations could be done. + // After that switch predicates off and do more loop optimizations. + if (!C->major_progress() && (C->predicate_count() > 0)) { + C->cleanup_loop_predicates(_igvn); +#ifndef PRODUCT + if (TraceLoopOpts) { + tty->print_cr("PredicatesOff"); + } +#endif + C->set_major_progress(); + } + // Convert scalar to superword operations at the end of all loop opts. if (UseSuperWord && C->has_loops() && !C->major_progress()) { // SuperWord transform SuperWord sw(this); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/loopnode.hpp --- a/hotspot/src/share/vm/opto/loopnode.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/opto/loopnode.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -57,7 +57,12 @@ protected: short _loop_flags; // Names for flag bitfields - enum { pre_post_main=0, inner_loop=8, partial_peel_loop=16, partial_peel_failed=32 }; + enum { Normal=0, Pre=1, Main=2, Post=3, PreMainPostFlagsMask=3, + MainHasNoPreLoop=4, + HasExactTripCount=8, + InnerLoop=16, + PartialPeelLoop=32, + PartialPeelFailed=64 }; char _unswitch_count; enum { _unswitch_max=3 }; @@ -65,13 +70,13 @@ // Names for edge indices enum { Self=0, EntryControl, LoopBackControl }; - int is_inner_loop() const { return _loop_flags & inner_loop; } - void set_inner_loop() { _loop_flags |= inner_loop; } + int is_inner_loop() const { return _loop_flags & InnerLoop; } + void set_inner_loop() { _loop_flags |= InnerLoop; } - int is_partial_peel_loop() const { return _loop_flags & partial_peel_loop; } - void set_partial_peel_loop() { _loop_flags |= partial_peel_loop; } - int partial_peel_has_failed() const { return _loop_flags & partial_peel_failed; } - void mark_partial_peel_failed() { _loop_flags |= partial_peel_failed; } + int is_partial_peel_loop() const { return _loop_flags & PartialPeelLoop; } + void set_partial_peel_loop() { _loop_flags |= PartialPeelLoop; } + int partial_peel_has_failed() const { return _loop_flags & PartialPeelFailed; } + void mark_partial_peel_failed() { _loop_flags |= PartialPeelFailed; } int unswitch_max() { return _unswitch_max; } int unswitch_count() { return _unswitch_count; } @@ -137,8 +142,8 @@ // the Main CountedLoop. Used to assert that we understand the graph shape. node_idx_t _main_idx; - // Known trip count calculated by policy_maximally_unroll - int _trip_count; + // Known trip count calculated by compute_exact_trip_count() + uint _trip_count; // Expected trip count from profile data float _profile_trip_cnt; @@ -152,7 +157,7 @@ public: CountedLoopNode( Node *entry, Node *backedge ) - : LoopNode(entry, backedge), _trip_count(max_jint), + : LoopNode(entry, backedge), _main_idx(0), _trip_count(max_juint), _profile_trip_cnt(COUNT_UNKNOWN), _unrolled_count_log2(0), _node_count_before_unroll(0) { init_class_id(Class_CountedLoop); @@ -194,13 +199,12 @@ // A 'main' loop that is ONLY unrolled or peeled, never RCE'd or // Aligned, may be missing it's pre-loop. - enum { Normal=0, Pre=1, Main=2, Post=3, PrePostFlagsMask=3, Main_Has_No_Pre_Loop=4 }; - int is_normal_loop() const { return (_loop_flags&PrePostFlagsMask) == Normal; } - int is_pre_loop () const { return (_loop_flags&PrePostFlagsMask) == Pre; } - int is_main_loop () const { return (_loop_flags&PrePostFlagsMask) == Main; } - int is_post_loop () const { return (_loop_flags&PrePostFlagsMask) == Post; } - int is_main_no_pre_loop() const { return _loop_flags & Main_Has_No_Pre_Loop; } - void set_main_no_pre_loop() { _loop_flags |= Main_Has_No_Pre_Loop; } + int is_normal_loop() const { return (_loop_flags&PreMainPostFlagsMask) == Normal; } + int is_pre_loop () const { return (_loop_flags&PreMainPostFlagsMask) == Pre; } + int is_main_loop () const { return (_loop_flags&PreMainPostFlagsMask) == Main; } + int is_post_loop () const { return (_loop_flags&PreMainPostFlagsMask) == Post; } + int is_main_no_pre_loop() const { return _loop_flags & MainHasNoPreLoop; } + void set_main_no_pre_loop() { _loop_flags |= MainHasNoPreLoop; } int main_idx() const { return _main_idx; } @@ -208,10 +212,19 @@ void set_pre_loop (CountedLoopNode *main) { assert(is_normal_loop(),""); _loop_flags |= Pre ; _main_idx = main->_idx; } void set_main_loop ( ) { assert(is_normal_loop(),""); _loop_flags |= Main; } void set_post_loop (CountedLoopNode *main) { assert(is_normal_loop(),""); _loop_flags |= Post; _main_idx = main->_idx; } - void set_normal_loop( ) { _loop_flags &= ~PrePostFlagsMask; } + void set_normal_loop( ) { _loop_flags &= ~PreMainPostFlagsMask; } + + void set_trip_count(uint tc) { _trip_count = tc; } + uint trip_count() { return _trip_count; } - void set_trip_count(int tc) { _trip_count = tc; } - int trip_count() { return _trip_count; } + bool has_exact_trip_count() const { return (_loop_flags & HasExactTripCount) != 0; } + void set_exact_trip_count(uint tc) { + _trip_count = tc; + _loop_flags |= HasExactTripCount; + } + void set_nonexact_trip_count() { + _loop_flags &= ~HasExactTripCount; + } void set_profile_trip_cnt(float ptc) { _profile_trip_cnt = ptc; } float profile_trip_cnt() { return _profile_trip_cnt; } @@ -384,6 +397,9 @@ // Micro-benchmark spamming. Remove empty loops. bool policy_do_remove_empty_loop( PhaseIdealLoop *phase ); + // Convert one iteration loop into normal code. + bool policy_do_one_iteration_loop( PhaseIdealLoop *phase ); + // Return TRUE or FALSE if the loop should be peeled or not. Peel if we can // make some loop-invariant test (usually a null-check) happen before the // loop. @@ -412,6 +428,9 @@ // Return TRUE if "iff" is a range check. bool is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invariance& invar) const; + // Compute loop exact trip count if possible + void compute_exact_trip_count( PhaseIdealLoop *phase ); + // Compute loop trip count from profile data void compute_profile_trip_cnt( PhaseIdealLoop *phase ); @@ -706,11 +725,11 @@ _dom_lca_tags(arena()), // Thread::resource_area _verify_me(NULL), _verify_only(true) { - build_and_optimize(false, false); + build_and_optimize(false); } // build the loop tree and perform any requested optimizations - void build_and_optimize(bool do_split_if, bool do_loop_pred); + void build_and_optimize(bool do_split_if); public: // Dominators for the sea of nodes @@ -721,13 +740,13 @@ Node *dom_lca_internal( Node *n1, Node *n2 ) const; // Compute the Ideal Node to Loop mapping - PhaseIdealLoop( PhaseIterGVN &igvn, bool do_split_ifs, bool do_loop_pred) : + PhaseIdealLoop( PhaseIterGVN &igvn, bool do_split_ifs) : PhaseTransform(Ideal_Loop), _igvn(igvn), _dom_lca_tags(arena()), // Thread::resource_area _verify_me(NULL), _verify_only(false) { - build_and_optimize(do_split_ifs, do_loop_pred); + build_and_optimize(do_split_ifs); } // Verify that verify_me made the same decisions as a fresh run. @@ -737,7 +756,7 @@ _dom_lca_tags(arena()), // Thread::resource_area _verify_me(verify_me), _verify_only(false) { - build_and_optimize(false, false); + build_and_optimize(false); } // Build and verify the loop tree without modifying the graph. This @@ -830,7 +849,26 @@ Deoptimization::DeoptReason reason); void register_control(Node* n, IdealLoopTree *loop, Node* pred); - // Find a good location to insert a predicate + // Clone loop predicates to cloned loops (peeled, unswitched) + static ProjNode* clone_predicate(ProjNode* predicate_proj, Node* new_entry, + Deoptimization::DeoptReason reason, + PhaseIdealLoop* loop_phase, + PhaseIterGVN* igvn); + static ProjNode* move_predicate(ProjNode* predicate_proj, Node* new_entry, + Deoptimization::DeoptReason reason, + PhaseIdealLoop* loop_phase, + PhaseIterGVN* igvn); + static Node* clone_loop_predicates(Node* old_entry, Node* new_entry, + bool move_predicates, + PhaseIdealLoop* loop_phase, + PhaseIterGVN* igvn); + Node* clone_loop_predicates(Node* old_entry, Node* new_entry); + Node* move_loop_predicates(Node* old_entry, Node* new_entry); + + void eliminate_loop_predicates(Node* entry); + static Node* skip_loop_predicates(Node* entry); + + // 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); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/loopopts.cpp --- a/hotspot/src/share/vm/opto/loopopts.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/opto/loopopts.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -2139,9 +2139,12 @@ // // orig // -// stmt1 -// | -// v +// stmt1 +// | +// v +// loop predicate +// | +// v // loop<----+ // | | // stmt2 | @@ -2172,6 +2175,9 @@ // after clone loop // // stmt1 +// | +// v +// loop predicate // / \ // clone / \ orig // / \ @@ -2210,12 +2216,15 @@ // after partial peel // // stmt1 +// | +// v +// loop predicate // / // clone / orig // / TOP // / \ // v v -// TOP->region region----+ +// TOP->loop loop----+ // | | | // stmt2 stmt2 | // | | | @@ -2253,13 +2262,17 @@ // stmt1 // | // v +// stmt2 clone +// | +// v // ........> ifA clone // : / | // dom / | // : v v // : false true // : | | -// : | stmt2 clone +// : | v +// : | loop predicate // : | | // : | v // : | newloop<-----+ @@ -2289,6 +2302,7 @@ // bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) { + assert(!loop->_head->is_CountedLoop(), "Non-counted loop only"); if (!loop->_head->is_Loop()) { return false; } @@ -2316,6 +2330,7 @@ } } + Node* entry = head->in(LoopNode::EntryControl); int dd = dom_depth(head); // Step 1: find cut point @@ -2612,6 +2627,8 @@ // Backedge of the surviving new_head (the clone) is original last_peel _igvn.hash_delete(new_head_clone); + Node* new_entry = move_loop_predicates(entry, new_head_clone->in(LoopNode::EntryControl)); + new_head_clone->set_req(LoopNode::EntryControl, new_entry); new_head_clone->set_req(LoopNode::LoopBackControl, last_peel); _igvn._worklist.push(new_head_clone); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/parse2.cpp --- a/hotspot/src/share/vm/opto/parse2.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/opto/parse2.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -795,8 +795,9 @@ taken = method()->scale_count(taken); not_taken = method()->scale_count(not_taken); - // Give up if too few counts to be meaningful - if (taken + not_taken < 40) { + // Give up if too few (or too many, in which case the sum will overflow) counts to be meaningful. + // We also check that individual counters are positive first, overwise the sum can become positive. + if (taken < 0 || not_taken < 0 || taken + not_taken < 40) { if (C->log() != NULL) { C->log()->elem("branch target_bci='%d' taken='%d' not_taken='%d'", iter().get_dest(), taken, not_taken); } @@ -804,13 +805,13 @@ } // Compute frequency that we arrive here - int sum = taken + not_taken; + float sum = taken + not_taken; // Adjust, if this block is a cloned private block but the // Jump counts are shared. Taken the private counts for // just this path instead of the shared counts. if( block()->count() > 0 ) sum = block()->count(); - cnt = (float)sum / (float)FreqCountInvocations; + cnt = sum / FreqCountInvocations; // Pin probability to sane limits float prob; diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/phaseX.hpp --- a/hotspot/src/share/vm/opto/phaseX.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/opto/phaseX.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -471,6 +471,13 @@ _delay_transform = delay; } + // Clone loop predicates. Defined in loopTransform.cpp. + Node* clone_loop_predicates(Node* old_entry, Node* new_entry); + Node* move_loop_predicates(Node* old_entry, Node* new_entry); + // Create a new if below new_entry for the predicate to be cloned + ProjNode* create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry, + Deoptimization::DeoptReason reason); + #ifndef PRODUCT protected: // Sub-quadratic implementation of VerifyIterativeGVN. diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/split_if.cpp --- a/hotspot/src/share/vm/opto/split_if.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/opto/split_if.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -399,6 +399,9 @@ #ifndef PRODUCT if( PrintOpto && VerifyLoopOptimizations ) tty->print_cr("Split-if"); + if (TraceLoopOpts) { + tty->print_cr("SplitIf"); + } #endif C->set_major_progress(); Node *region = iff->in(0); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/superword.cpp --- a/hotspot/src/share/vm/opto/superword.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/opto/superword.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -1132,6 +1132,13 @@ void SuperWord::output() { if (_packset.length() == 0) return; +#ifndef PRODUCT + if (TraceLoopOpts) { + tty->print("SuperWord "); + lpt()->dump_head(); + } +#endif + // MUST ENSURE main loop's initial value is properly aligned: // (iv_initial_value + min_iv_offset) % vector_width_in_bytes() == 0 diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/opto/vectornode.hpp --- a/hotspot/src/share/vm/opto/vectornode.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/opto/vectornode.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -32,6 +32,7 @@ //------------------------------VectorNode-------------------------------------- // Vector Operation class VectorNode : public Node { + virtual uint size_of() const { return sizeof(*this); } protected: uint _length; // vector length virtual BasicType elt_basic_type() const = 0; // Vector element basic type diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/prims/jvm.h --- a/hotspot/src/share/vm/prims/jvm.h Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/prims/jvm.h Wed Jul 05 17:41:25 2017 +0200 @@ -1062,7 +1062,7 @@ JVM_CONSTANT_NameAndType, JVM_CONSTANT_MethodHandle = 15, // JSR 292 JVM_CONSTANT_MethodType = 16, // JSR 292 - JVM_CONSTANT_InvokeDynamicTrans = 17, // JSR 292, only occurs in old class files + //JVM_CONSTANT_(unused) = 17, // JSR 292 early drafts only JVM_CONSTANT_InvokeDynamic = 18, // JSR 292 JVM_CONSTANT_ExternalMax = 18 // Last tag found in classfiles }; diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/prims/jvmtiManageCapabilities.cpp --- a/hotspot/src/share/vm/prims/jvmtiManageCapabilities.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/prims/jvmtiManageCapabilities.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -319,8 +319,11 @@ bool enter_all_methods = interp_events || avail.can_generate_breakpoint_events; - UseFastEmptyMethods = !enter_all_methods; - UseFastAccessorMethods = !enter_all_methods; + if (enter_all_methods) { + // Disable these when tracking the bytecodes + UseFastEmptyMethods = false; + UseFastAccessorMethods = false; + } if (avail.can_generate_breakpoint_events) { RewriteFrequentPairs = false; diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/prims/methodHandleWalk.cpp --- a/hotspot/src/share/vm/prims/methodHandleWalk.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/prims/methodHandleWalk.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -959,12 +959,6 @@ if (m == NULL) { // Get the intrinsic methodOop. m = vmIntrinsics::method_for(iid); - if (m == NULL && iid == vmIntrinsics::_checkSpreadArgument && AllowTransitionalJSR292) { - m = vmIntrinsics::method_for(vmIntrinsics::_checkSpreadArgument_TRANS); - if (m == NULL) - // sun.dyn.MethodHandleImpl not found, look for java.dyn.MethodHandleNatives: - m = vmIntrinsics::method_for(vmIntrinsics::_checkSpreadArgument_TRANS2); - } if (m == NULL) { ArgToken zero; lose(vmIntrinsics::name_at(iid), CHECK_(zero)); diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/prims/methodHandleWalk.hpp --- a/hotspot/src/share/vm/prims/methodHandleWalk.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/prims/methodHandleWalk.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -343,6 +343,7 @@ int cpool_symbol_put(int tag, Symbol* con) { if (con == NULL) return 0; ConstantValue* cv = new ConstantValue(tag, con); + con->increment_refcount(); return _constants.append(cv); } diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/prims/methodHandles.cpp --- a/hotspot/src/share/vm/prims/methodHandles.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/prims/methodHandles.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -928,6 +928,7 @@ }; static bool is_always_null_type(klassOop klass) { + if (klass == NULL) return false; // safety if (!Klass::cast(klass)->oop_is_instance()) return false; instanceKlass* ik = instanceKlass::cast(klass); // Must be on the boot class path: @@ -944,6 +945,8 @@ } bool MethodHandles::class_cast_needed(klassOop src, klassOop dst) { + if (dst == NULL) return true; + if (src == NULL) return (dst != SystemDictionary::Object_klass()); if (src == dst || dst == SystemDictionary::Object_klass()) return false; // quickest checks Klass* srck = Klass::cast(src); @@ -1026,10 +1029,15 @@ int first_ptype_pos, KlassHandle insert_ptype, TRAPS) { + Handle mhi_type; + if (m->is_method_handle_invoke()) { + // use this more exact typing instead of the symbolic signature: + mhi_type = Handle(THREAD, m->method_handle_type()); + } objArrayHandle ptypes(THREAD, java_lang_invoke_MethodType::ptypes(mtype())); int pnum = first_ptype_pos; int pmax = ptypes->length(); - int mnum = 0; // method argument + int anum = 0; // method argument const char* err = NULL; ResourceMark rm(THREAD); for (SignatureStream ss(m->signature()); !ss.is_done(); ss.next()) { @@ -1048,47 +1056,70 @@ else ptype_oop = insert_ptype->java_mirror(); pnum += 1; - mnum += 1; + anum += 1; } - klassOop pklass = NULL; - BasicType ptype = T_OBJECT; - if (ptype_oop != NULL) - ptype = java_lang_Class::as_BasicType(ptype_oop, &pklass); - else - // null does not match any non-reference; use Object to report the error - pklass = SystemDictionary::Object_klass(); - klassOop mklass = NULL; - BasicType mtype = ss.type(); - if (mtype == T_ARRAY) mtype = T_OBJECT; // fold all refs to T_OBJECT - if (mtype == T_OBJECT) { - if (ptype_oop == NULL) { + KlassHandle pklass; + BasicType ptype = T_OBJECT; + bool have_ptype = false; + // missing ptype_oop does not match any non-reference; use Object to report the error + pklass = SystemDictionaryHandles::Object_klass(); + if (ptype_oop != NULL) { + have_ptype = true; + klassOop pklass_oop = NULL; + ptype = java_lang_Class::as_BasicType(ptype_oop, &pklass_oop); + pklass = KlassHandle(THREAD, pklass_oop); + } + ptype_oop = NULL; //done with this + KlassHandle aklass; + BasicType atype = ss.type(); + if (atype == T_ARRAY) atype = T_OBJECT; // fold all refs to T_OBJECT + if (atype == T_OBJECT) { + if (!have_ptype) { // null matches any reference continue; } - KlassHandle pklass_handle(THREAD, pklass); pklass = NULL; - // If we fail to resolve types at this point, we will throw an error. - Symbol* name = ss.as_symbol(CHECK); - instanceKlass* mk = instanceKlass::cast(m->method_holder()); - Handle loader(THREAD, mk->class_loader()); - Handle domain(THREAD, mk->protection_domain()); - mklass = SystemDictionary::resolve_or_null(name, loader, domain, CHECK); - pklass = pklass_handle(); - if (mklass == NULL && pklass != NULL && - Klass::cast(pklass)->name() == name && - m->is_method_handle_invoke()) { - // Assume a match. We can't really decode the signature of MH.invoke*. - continue; + if (mhi_type.is_null()) { + // If we fail to resolve types at this point, we will usually throw an error. + TempNewSymbol name = ss.as_symbol_or_null(); + if (name != NULL) { + instanceKlass* mk = instanceKlass::cast(m->method_holder()); + Handle loader(THREAD, mk->class_loader()); + Handle domain(THREAD, mk->protection_domain()); + klassOop aklass_oop = SystemDictionary::resolve_or_null(name, loader, domain, CHECK); + if (aklass_oop != NULL) + aklass = KlassHandle(THREAD, aklass_oop); + } + } else { + // for method handle invokers we don't look at the name in the signature + oop atype_oop; + if (ss.at_return_type()) + atype_oop = java_lang_invoke_MethodType::rtype(mhi_type()); + else + atype_oop = java_lang_invoke_MethodType::ptype(mhi_type(), anum-1); + klassOop aklass_oop = NULL; + atype = java_lang_Class::as_BasicType(atype_oop, &aklass_oop); + aklass = KlassHandle(THREAD, aklass_oop); } } if (!ss.at_return_type()) { - err = check_argument_type_change(ptype, pklass, mtype, mklass, mnum); + err = check_argument_type_change(ptype, pklass(), atype, aklass(), anum); } else { - err = check_return_type_change(mtype, mklass, ptype, pklass); // note reversal! + err = check_return_type_change(atype, aklass(), ptype, pklass()); // note reversal! } if (err != NULL) break; } if (err != NULL) { +#ifndef PRODUCT + if (PrintMiscellaneous && (Verbose || WizardMode)) { + tty->print("*** verify_method_signature failed: "); + java_lang_invoke_MethodType::print_signature(mtype(), tty); + tty->cr(); + tty->print_cr(" first_ptype_pos = %d, insert_ptype = "UINTX_FORMAT, first_ptype_pos, insert_ptype()); + tty->print(" Failing method: "); + m->print(); + } +#endif //PRODUCT THROW_MSG(vmSymbols::java_lang_InternalError(), err); } } @@ -1288,10 +1319,12 @@ // format, format, format const char* src_name = type2name(src_type); const char* dst_name = type2name(dst_type); - if (src_type == T_OBJECT) src_name = Klass::cast(src_klass)->external_name(); - if (dst_type == T_OBJECT) dst_name = Klass::cast(dst_klass)->external_name(); if (src_name == NULL) src_name = "unknown type"; if (dst_name == NULL) dst_name = "unknown type"; + if (src_type == T_OBJECT) + src_name = (src_klass != NULL) ? Klass::cast(src_klass)->external_name() : "an unresolved class"; + if (dst_type == T_OBJECT) + dst_name = (dst_klass != NULL) ? Klass::cast(dst_klass)->external_name() : "an unresolved class"; size_t msglen = strlen(err) + strlen(src_name) + strlen(dst_name) + (argnum < 10 ? 1 : 11); char* msg = NEW_RESOURCE_ARRAY(char, msglen + 1); @@ -2488,74 +2521,21 @@ } JVM_END -JVM_ENTRY(void, MHN_registerBootstrap(JNIEnv *env, jobject igcls, jclass caller_jh, jobject bsm_jh)) { - instanceKlassHandle ik = MethodHandles::resolve_instance_klass(caller_jh, THREAD); - if (!AllowTransitionalJSR292) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - "registerBootstrapMethod is only supported in JSR 292 EDR"); - } - ik->link_class(CHECK); - if (!java_lang_invoke_MethodHandle::is_instance(JNIHandles::resolve(bsm_jh))) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "method handle"); - } - const char* err = NULL; - if (ik->is_initialized() || ik->is_in_error_state()) { - err = "too late: class is already initialized"; - } else { - ObjectLocker ol(ik, THREAD); // note: this should be a recursive lock - if (ik->is_not_initialized() || - (ik->is_being_initialized() && ik->is_reentrant_initialization(THREAD))) { - if (ik->bootstrap_method() != NULL) { - err = "class is already equipped with a bootstrap method"; - } else { - ik->set_bootstrap_method(JNIHandles::resolve_non_null(bsm_jh)); - err = NULL; - } - } else { - err = "class is already initialized"; - if (ik->is_being_initialized()) - err = "class is already being initialized in a different thread"; - } - } - if (err != NULL) { - THROW_MSG(vmSymbols::java_lang_IllegalStateException(), err); - } -} -JVM_END - -JVM_ENTRY(jobject, MHN_getBootstrap(JNIEnv *env, jobject igcls, jclass caller_jh)) { - if (!AllowTransitionalJSR292) - THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "getBootstrap: transitional only"); - instanceKlassHandle ik = MethodHandles::resolve_instance_klass(caller_jh, THREAD); - return JNIHandles::make_local(THREAD, ik->bootstrap_method()); -} -JVM_END - -JVM_ENTRY(void, MHN_setCallSiteTarget(JNIEnv *env, jobject igcls, jobject site_jh, jobject target_jh)) { - if (!AllowTransitionalJSR292) - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "setCallSite: transitional only"); -} -JVM_END - /// JVM_RegisterMethodHandleMethods #define LANG "Ljava/lang/" -#define JLINV "Ljava/lang/invoke/" /* standard package */ -#define JDYN "Ljava/dyn/" /* alternative package to JLINV if AllowTransitionalJSR292 */ -#define IDYN "Lsun/dyn/" /* alternative package to JDYN if AllowTransitionalJSR292 */ -// FIXME: After AllowTransitionalJSR292 is removed, replace JDYN and IDYN by JLINV. +#define JLINV "Ljava/lang/invoke/" #define OBJ LANG"Object;" #define CLS LANG"Class;" #define STRG LANG"String;" -#define CST JDYN"CallSite;" -#define MT JDYN"MethodType;" -#define MH JDYN"MethodHandle;" -#define MEM IDYN"MemberName;" -#define AMH IDYN"AdapterMethodHandle;" -#define BMH IDYN"BoundMethodHandle;" -#define DMH IDYN"DirectMethodHandle;" +#define MT JLINV"MethodType;" +#define MH JLINV"MethodHandle;" +#define MEM JLINV"MemberName;" +#define AMH JLINV"AdapterMethodHandle;" +#define BMH JLINV"BoundMethodHandle;" +#define DMH JLINV"DirectMethodHandle;" #define CC (char*) /*cast a literal from (const char*)*/ #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f) @@ -2579,39 +2559,6 @@ {CC"getMembers", CC"("CLS""STRG""STRG"I"CLS"I["MEM")I", FN_PTR(MHN_getMembers)} }; -// FIXME: Remove methods2 after AllowTransitionalJSR292 is removed. -static JNINativeMethod methods2[] = { - {CC"registerBootstrap", CC"("CLS MH")V", FN_PTR(MHN_registerBootstrap)}, - {CC"getBootstrap", CC"("CLS")"MH, FN_PTR(MHN_getBootstrap)}, - {CC"setCallSiteTarget", CC"("CST MH")V", FN_PTR(MHN_setCallSiteTarget)} -}; - -static void hack_signatures(JNINativeMethod* methods, jint num_methods, const char* from_sig, const char* to_sig) { - for (int i = 0; i < num_methods; i++) { - const char* sig = methods[i].signature; - if (!strstr(sig, from_sig)) continue; - size_t buflen = strlen(sig) + 100; - char* buf = NEW_C_HEAP_ARRAY(char, buflen); - char* bufp = buf; - const char* sigp = sig; - size_t from_len = strlen(from_sig), to_len = strlen(to_sig); - while (*sigp != '\0') { - assert(bufp < buf + buflen - to_len - 1, "oob"); - if (strncmp(sigp, from_sig, from_len) != 0) { - *bufp++ = *sigp++; - } else { - strcpy(bufp, to_sig); - bufp += to_len; - sigp += from_len; - } - } - *bufp = '\0'; - methods[i].signature = buf; // replace with new signature - if (TraceMethodHandles) - tty->print_cr("MethodHandleNatives: %s: change signature %s => %s", methods[i].name, sig, buf); - } -} - // This one function is exported, used by NativeLookup. JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) { @@ -2622,92 +2569,41 @@ return; // bind nothing } - if (SystemDictionary::MethodHandleNatives_klass() != NULL && - SystemDictionary::MethodHandleNatives_klass() != java_lang_Class::as_klassOop(JNIHandles::resolve(MHN_class))) { - warning("multiple versions of MethodHandleNatives in boot classpath; consider using -XX:+PreferTransitionalJSR292"); - THROW_MSG(vmSymbols::java_lang_InternalError(), "multiple versions of MethodHandleNatives in boot classpath; consider using -XX:+PreferTransitionalJSR292"); - } - bool enable_MH = true; - // Loop control. FIXME: Replace by dead reckoning after AllowTransitionalJSR292 is removed. - bool registered_natives = false; - bool try_plain = true, try_JDYN = true, try_IDYN = true; - for (;;) { + { ThreadToNativeFromVM ttnfv(thread); - if (try_plain) { try_plain = false; } - else if (try_JDYN) { try_JDYN = false; hack_signatures(methods, sizeof(methods)/sizeof(JNINativeMethod), IDYN, JDYN); } - else if (try_IDYN) { try_IDYN = false; hack_signatures(methods, sizeof(methods)/sizeof(JNINativeMethod), JDYN, JLINV); } - else { break; } int status = env->RegisterNatives(MHN_class, methods, sizeof(methods)/sizeof(JNINativeMethod)); if (env->ExceptionOccurred()) { + MethodHandles::set_enabled(false); + warning("JSR 292 method handle code is mismatched to this JVM. Disabling support."); + enable_MH = false; env->ExceptionClear(); - // and try again... - } else { - registered_natives = true; - break; } } - if (!registered_natives) { - MethodHandles::set_enabled(false); - warning("JSR 292 method handle code is mismatched to this JVM. Disabling support."); - enable_MH = false; - } if (enable_MH) { - bool found_raise_exception = false; KlassHandle MHN_klass = SystemDictionaryHandles::MethodHandleNatives_klass(); - KlassHandle MHI_klass = SystemDictionaryHandles::MethodHandleImpl_klass(); - // Loop control. FIXME: Replace by dead reckoning after AllowTransitionalJSR292 is removed. - bool try_MHN = true, try_MHI = AllowTransitionalJSR292; - for (;;) { - KlassHandle try_klass; - if (try_MHN) { try_MHN = false; try_klass = MHN_klass; } - else if (try_MHI) { try_MHI = false; try_klass = MHI_klass; } - else { break; } - if (try_klass.is_null()) continue; + if (MHN_klass.not_null()) { TempNewSymbol raiseException_name = SymbolTable::new_symbol("raiseException", CHECK); TempNewSymbol raiseException_sig = SymbolTable::new_symbol("(ILjava/lang/Object;Ljava/lang/Object;)V", CHECK); - methodOop raiseException_method = instanceKlass::cast(try_klass->as_klassOop()) + methodOop raiseException_method = instanceKlass::cast(MHN_klass->as_klassOop()) ->find_method(raiseException_name, raiseException_sig); if (raiseException_method != NULL && raiseException_method->is_static()) { MethodHandles::set_raise_exception_method(raiseException_method); - found_raise_exception = true; - break; + } else { + warning("JSR 292 method handle code is mismatched to this JVM. Disabling support."); + enable_MH = false; } - } - if (!found_raise_exception) { - warning("JSR 292 method handle code is mismatched to this JVM. Disabling support."); + } else { enable_MH = false; } } if (enable_MH) { - if (AllowTransitionalJSR292) { - // We need to link the MethodHandleImpl klass before we generate - // the method handle adapters as the _raise_exception adapter uses - // one of its methods (and its c2i-adapter). - klassOop k = SystemDictionary::MethodHandleImpl_klass(); - if (k != NULL) { - instanceKlass* ik = instanceKlass::cast(k); - ik->link_class(CHECK); - } - } - MethodHandles::generate_adapters(); MethodHandles::set_enabled(true); } - - if (AllowTransitionalJSR292) { - ThreadToNativeFromVM ttnfv(thread); - - int status = env->RegisterNatives(MHN_class, methods2, sizeof(methods2)/sizeof(JNINativeMethod)); - if (env->ExceptionOccurred()) { - // Don't do this, since it's too late: - // MethodHandles::set_enabled(false) - env->ExceptionClear(); - } - } } JVM_END diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/prims/nativeLookup.cpp --- a/hotspot/src/share/vm/prims/nativeLookup.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/prims/nativeLookup.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -117,8 +117,6 @@ { CC"Java_sun_misc_Unsafe_registerNatives", NULL, FN_PTR(JVM_RegisterUnsafeMethods) }, { CC"Java_java_lang_invoke_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) }, - { CC"Java_sun_dyn_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) }, // AllowTransitionalJSR292 - { CC"Java_java_dyn_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) }, // AllowTransitionalJSR292 { CC"Java_sun_misc_Perf_registerNatives", NULL, FN_PTR(JVM_RegisterPerfMethods) } }; diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/runtime/arguments.cpp --- a/hotspot/src/share/vm/runtime/arguments.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/runtime/arguments.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -59,7 +59,8 @@ #include "gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp" #endif -#define DEFAULT_VENDOR_URL_BUG "http://java.sun.com/webapps/bugreport/crash.jsp" +// Note: This is a special bug reporting site for the JVM +#define DEFAULT_VENDOR_URL_BUG "http://bugreport.sun.com/bugreport/crash.jsp" #define DEFAULT_JAVA_LAUNCHER "generic" char** Arguments::_jvm_flags_array = NULL; @@ -243,6 +244,7 @@ { "MaxLiveObjectEvacuationRatio", JDK_Version::jdk_update(6,24), JDK_Version::jdk(8) }, { "ForceSharedSpaces", JDK_Version::jdk_update(6,25), JDK_Version::jdk(8) }, + { "AllowTransitionalJSR292", JDK_Version::jdk(7), JDK_Version::jdk(8) }, { NULL, JDK_Version(0), JDK_Version(0) } }; @@ -962,6 +964,16 @@ UseCompiler = true; UseLoopCounter = true; +#ifndef ZERO + // Turn these off for mixed and comp. Leave them on for Zero. + if (FLAG_IS_DEFAULT(UseFastAccessorMethods)) { + UseFastAccessorMethods = mode == _int; + } + if (FLAG_IS_DEFAULT(UseFastEmptyMethods)) { + UseFastEmptyMethods = mode == _int; + } +#endif + // Default values may be platform/compiler dependent - // use the saved values ClipInlining = Arguments::_ClipInlining; diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/runtime/globals.cpp --- a/hotspot/src/share/vm/runtime/globals.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/runtime/globals.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -63,6 +63,12 @@ bool Flag::is_unlocked() const { if (strcmp(kind, "{diagnostic}") == 0) { + if (strcmp(name, "EnableInvokeDynamic") == 0 && UnlockExperimentalVMOptions && !UnlockDiagnosticVMOptions) { + // transitional logic to allow tests to run until they are changed + static int warned; + if (++warned == 1) warning("Use -XX:+UnlockDiagnosticVMOptions before EnableInvokeDynamic flag"); + return true; + } return UnlockDiagnosticVMOptions; } else if (strcmp(kind, "{experimental}") == 0 || strcmp(kind, "{C2 experimental}") == 0) { diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/runtime/globals.hpp --- a/hotspot/src/share/vm/runtime/globals.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/runtime/globals.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -3718,13 +3718,7 @@ experimental(bool, TrustFinalNonStaticFields, false, \ "trust final non-static declarations for constant folding") \ \ - experimental(bool, AllowTransitionalJSR292, true, \ - "recognize pre-PFD formats of invokedynamic") \ - \ - experimental(bool, PreferTransitionalJSR292, false, \ - "prefer pre-PFD APIs on boot class path, if they exist") \ - \ - experimental(bool, AllowInvokeForInvokeGeneric, false, \ + experimental(bool, AllowInvokeGeneric, true, \ "accept MethodHandle.invoke and MethodHandle.invokeGeneric " \ "as equivalent methods") \ \ diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/runtime/os.cpp --- a/hotspot/src/share/vm/runtime/os.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/runtime/os.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -1291,3 +1291,41 @@ } return result; } + +// Read file line by line, if line is longer than bsize, +// skip rest of line. +int os::get_line_chars(int fd, char* buf, const size_t bsize){ + size_t sz, i = 0; + + // read until EOF, EOL or buf is full + while ((sz = (int) read(fd, &buf[i], 1)) == 1 && i < (bsize-1) && buf[i] != '\n') { + ++i; + } + + if (buf[i] == '\n') { + // EOL reached so ignore EOL character and return + + buf[i] = 0; + return (int) i; + } + + buf[i+1] = 0; + + if (sz != 1) { + // EOF reached. if we read chars before EOF return them and + // return EOF on next call otherwise return EOF + + return (i == 0) ? -1 : (int) i; + } + + // line is longer than size of buf, skip to EOL + int ch; + while (read(fd, &ch, 1) == 1 && ch != '\n') { + // Do nothing + } + + // return initial part of line that fits in buf. + // If we reached EOF, it will be returned on next call. + + return (int) i; +} diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/runtime/os.hpp --- a/hotspot/src/share/vm/runtime/os.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/runtime/os.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -658,6 +658,10 @@ // Hook for os specific jvm options that we don't want to abort on seeing static bool obsolete_option(const JavaVMOption *option); + // Read file line by line. If line is longer than bsize, + // rest of line is skipped. Returns number of bytes read or -1 on EOF + static int get_line_chars(int fd, char *buf, const size_t bsize); + // Platform dependent stuff #ifdef TARGET_OS_FAMILY_linux # include "os_linux.hpp" diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/runtime/sharedRuntime.cpp --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -1700,9 +1700,11 @@ message = generate_class_cast_message(objName, targetKlass->external_name()); } else { // %%% need to get the MethodType string, without messing around too much + const char* desc = NULL; // Get a signature from the invoke instruction const char* mhName = "method handle"; const char* targetType = "the required signature"; + int targetArity = -1, mhArity = -1; vframeStream vfst(thread, true); if (!vfst.at_end()) { Bytecode_invoke call(vfst.method(), vfst.bci()); @@ -1716,20 +1718,35 @@ && target->is_method_handle_invoke() && required == target->method_handle_type()) { targetType = target->signature()->as_C_string(); + targetArity = ArgumentCount(target->signature()).size(); } } - klassOop kignore; int fignore; - methodOop actual_method = MethodHandles::decode_method(actual, - kignore, fignore); + klassOop kignore; int dmf_flags = 0; + methodOop actual_method = MethodHandles::decode_method(actual, kignore, dmf_flags); + if ((dmf_flags & ~(MethodHandles::_dmf_has_receiver | + MethodHandles::_dmf_does_dispatch | + MethodHandles::_dmf_from_interface)) != 0) + actual_method = NULL; // MH does extra binds, drops, etc. + bool has_receiver = ((dmf_flags & MethodHandles::_dmf_has_receiver) != 0); if (actual_method != NULL) { - if (methodOopDesc::is_method_handle_invoke_name(actual_method->name())) - mhName = "$"; + mhName = actual_method->signature()->as_C_string(); + mhArity = ArgumentCount(actual_method->signature()).size(); + if (!actual_method->is_static()) mhArity += 1; + } else if (java_lang_invoke_MethodHandle::is_instance(actual)) { + oopDesc* mhType = java_lang_invoke_MethodHandle::type(actual); + mhArity = java_lang_invoke_MethodType::ptype_count(mhType); + stringStream st; + java_lang_invoke_MethodType::print_signature(mhType, &st); + mhName = st.as_string(); + } + if (targetArity != -1 && targetArity != mhArity) { + if (has_receiver && targetArity == mhArity-1) + desc = " cannot be called without a receiver argument as "; else - mhName = actual_method->signature()->as_C_string(); - if (mhName[0] == '$') - mhName = actual_method->signature()->as_C_string(); + desc = " cannot be called with a different arity as "; } message = generate_class_cast_message(mhName, targetType, + desc != NULL ? desc : " cannot be called as "); } if (TraceMethodHandles) { diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/runtime/stubRoutines.cpp --- a/hotspot/src/share/vm/runtime/stubRoutines.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/runtime/stubRoutines.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -433,3 +433,77 @@ #undef RETURN_STUB } + +// constants for computing the copy function +enum { + COPYFUNC_UNALIGNED = 0, + COPYFUNC_ALIGNED = 1, // src, dest aligned to HeapWordSize + COPYFUNC_CONJOINT = 0, + COPYFUNC_DISJOINT = 2 // src != dest, or transfer can descend +}; + +// Note: The condition "disjoint" applies also for overlapping copies +// where an descending copy is permitted (i.e., dest_offset <= src_offset). +address +StubRoutines::select_arraycopy_function(BasicType t, bool aligned, bool disjoint, const char* &name, bool dest_uninitialized) { + int selector = + (aligned ? COPYFUNC_ALIGNED : COPYFUNC_UNALIGNED) + + (disjoint ? COPYFUNC_DISJOINT : COPYFUNC_CONJOINT); + +#define RETURN_STUB(xxx_arraycopy) { \ + name = #xxx_arraycopy; \ + return StubRoutines::xxx_arraycopy(); } + +#define RETURN_STUB_PARM(xxx_arraycopy, parm) { \ + name = #xxx_arraycopy; \ + return StubRoutines::xxx_arraycopy(parm); } + + switch (t) { + case T_BYTE: + case T_BOOLEAN: + switch (selector) { + case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jbyte_arraycopy); + case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jbyte_arraycopy); + case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jbyte_disjoint_arraycopy); + case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jbyte_disjoint_arraycopy); + } + case T_CHAR: + case T_SHORT: + switch (selector) { + case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jshort_arraycopy); + case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jshort_arraycopy); + case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jshort_disjoint_arraycopy); + case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jshort_disjoint_arraycopy); + } + case T_INT: + case T_FLOAT: + switch (selector) { + case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jint_arraycopy); + case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jint_arraycopy); + case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jint_disjoint_arraycopy); + case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jint_disjoint_arraycopy); + } + case T_DOUBLE: + case T_LONG: + switch (selector) { + case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jlong_arraycopy); + case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jlong_arraycopy); + case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jlong_disjoint_arraycopy); + case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jlong_disjoint_arraycopy); + } + case T_ARRAY: + case T_OBJECT: + switch (selector) { + case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB_PARM(oop_arraycopy, dest_uninitialized); + case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB_PARM(arrayof_oop_arraycopy, dest_uninitialized); + case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB_PARM(oop_disjoint_arraycopy, dest_uninitialized); + case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB_PARM(arrayof_oop_disjoint_arraycopy, dest_uninitialized); + } + default: + ShouldNotReachHere(); + return NULL; + } + +#undef RETURN_STUB +#undef RETURN_STUB_PARM +} diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/runtime/stubRoutines.hpp --- a/hotspot/src/share/vm/runtime/stubRoutines.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/runtime/stubRoutines.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -282,6 +282,8 @@ static address addr_fpu_subnormal_bias2() { return (address)&_fpu_subnormal_bias2; } + static address select_arraycopy_function(BasicType t, bool aligned, bool disjoint, const char* &name, bool dest_uninitialized); + static address jbyte_arraycopy() { return _jbyte_arraycopy; } static address jshort_arraycopy() { return _jshort_arraycopy; } static address jint_arraycopy() { return _jint_arraycopy; } diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/runtime/sweeper.cpp --- a/hotspot/src/share/vm/runtime/sweeper.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/runtime/sweeper.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -418,6 +418,11 @@ // state of the code cache if it's requested. void NMethodSweeper::log_sweep(const char* msg, const char* format, ...) { if (PrintMethodFlushing) { + stringStream s; + // Dump code cache state into a buffer before locking the tty, + // because log_state() will use locks causing lock conflicts. + CodeCache::log_state(&s); + ttyLocker ttyl; tty->print("### sweeper: %s ", msg); if (format != NULL) { @@ -426,10 +431,15 @@ tty->vprint(format, ap); va_end(ap); } - CodeCache::log_state(tty); tty->cr(); + tty->print_cr(s.as_string()); } if (LogCompilation && (xtty != NULL)) { + stringStream s; + // Dump code cache state into a buffer before locking the tty, + // because log_state() will use locks causing lock conflicts. + CodeCache::log_state(&s); + ttyLocker ttyl; xtty->begin_elem("sweeper state='%s' traversals='" INTX_FORMAT "' ", msg, (intx)traversal_count()); if (format != NULL) { @@ -438,7 +448,7 @@ xtty->vprint(format, ap); va_end(ap); } - CodeCache::log_state(xtty); + xtty->print(s.as_string()); xtty->stamp(); xtty->end_elem(); } diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/shark/llvmHeaders.hpp --- a/hotspot/src/share/vm/shark/llvmHeaders.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/shark/llvmHeaders.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -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. * Copyright 2008, 2009, 2010 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -46,7 +46,11 @@ #include #endif #include +#if SHARK_LLVM_VERSION >= 29 +#include +#else #include +#endif #include #include #include @@ -55,8 +59,12 @@ #include #include #include +#if SHARK_LLVM_VERSION >= 29 +#include +#else #include #endif +#endif #include diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/shark/sharkCompiler.cpp --- a/hotspot/src/share/vm/shark/sharkCompiler.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/shark/sharkCompiler.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -1,6 +1,6 @@ /* * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009, 2010 Red Hat, Inc. + * Copyright 2008, 2009, 2010, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -218,6 +218,7 @@ nmethod* SharkCompiler::generate_native_wrapper(MacroAssembler* masm, methodHandle target, + int compile_id, BasicType* arg_types, BasicType return_type) { assert(is_initialized(), "should be"); @@ -241,6 +242,7 @@ // Return the nmethod for installation in the VM return nmethod::new_native_nmethod(target, + compile_id, masm->code(), 0, 0, diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/shark/sharkCompiler.hpp --- a/hotspot/src/share/vm/shark/sharkCompiler.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/shark/sharkCompiler.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -1,6 +1,6 @@ /* * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2008, 2009 Red Hat, Inc. + * Copyright 2008, 2009, 2010, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,6 +60,7 @@ // Generate a wrapper for a native (JNI) method nmethod* generate_native_wrapper(MacroAssembler* masm, methodHandle target, + int compile_id, BasicType* arg_types, BasicType return_type); @@ -113,7 +114,8 @@ // Global access public: static SharkCompiler* compiler() { - AbstractCompiler *compiler = CompileBroker::compiler(CompLevel_simple); + AbstractCompiler *compiler = + CompileBroker::compiler(CompLevel_full_optimization); assert(compiler->is_shark() && compiler->is_initialized(), "should be"); return (SharkCompiler *) compiler; } diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/utilities/constantTag.cpp --- a/hotspot/src/share/vm/utilities/constantTag.cpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/utilities/constantTag.cpp Wed Jul 05 17:41:25 2017 +0200 @@ -93,8 +93,6 @@ return "MethodType"; case JVM_CONSTANT_InvokeDynamic : return "InvokeDynamic"; - case JVM_CONSTANT_InvokeDynamicTrans : - return "InvokeDynamic/transitional"; case JVM_CONSTANT_Object : return "Object"; case JVM_CONSTANT_Utf8 : diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/utilities/constantTag.hpp --- a/hotspot/src/share/vm/utilities/constantTag.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/utilities/constantTag.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -86,8 +86,7 @@ bool is_method_type() const { return _tag == JVM_CONSTANT_MethodType; } bool is_method_handle() const { return _tag == JVM_CONSTANT_MethodHandle; } - bool is_invoke_dynamic() const { return (_tag == JVM_CONSTANT_InvokeDynamic || - _tag == JVM_CONSTANT_InvokeDynamicTrans); } + bool is_invoke_dynamic() const { return _tag == JVM_CONSTANT_InvokeDynamic; } bool is_loadable_constant() const { return ((_tag >= JVM_CONSTANT_Integer && _tag <= JVM_CONSTANT_String) || diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/utilities/globalDefinitions.hpp --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -746,9 +746,9 @@ CompLevel_simple = 1, // C1 CompLevel_limited_profile = 2, // C1, invocation & backedge counters CompLevel_full_profile = 3, // C1, invocation & backedge counters + mdo - CompLevel_full_optimization = 4, // C2 + CompLevel_full_optimization = 4, // C2 or Shark -#if defined(COMPILER2) +#if defined(COMPILER2) || defined(SHARK) CompLevel_highest_tier = CompLevel_full_optimization, // pure C2 and tiered #elif defined(COMPILER1) CompLevel_highest_tier = CompLevel_simple, // pure C1 @@ -760,7 +760,7 @@ CompLevel_initial_compile = CompLevel_full_profile // tiered #elif defined(COMPILER1) CompLevel_initial_compile = CompLevel_simple // pure C1 -#elif defined(COMPILER2) +#elif defined(COMPILER2) || defined(SHARK) CompLevel_initial_compile = CompLevel_full_optimization // pure C2 #else CompLevel_initial_compile = CompLevel_none diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp --- a/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp Wed Jul 05 17:41:25 2017 +0200 @@ -77,7 +77,9 @@ # endif #ifdef LINUX +#ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS +#endif // __STDC_LIMIT_MACROS #include #include #include diff -r af2ac0dd2fa6 -r 0327745d3737 hotspot/test/compiler/6795161/Test.java --- a/hotspot/test/compiler/6795161/Test.java Thu Apr 14 15:22:12 2011 -0700 +++ b/hotspot/test/compiler/6795161/Test.java Wed Jul 05 17:41:25 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 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 @@ -26,7 +26,7 @@ * @test * @bug 6795161 * @summary Escape analysis leads to data corruption - * @run main/othervm -server -Xcomp -XX:CompileOnly=Test -XX:+DoEscapeAnalysis Test + * @run main/othervm -server -XX:+IgnoreUnrecognizedVMOptions -Xcomp -XX:CompileOnly=Test -XX:+DoEscapeAnalysis Test */ class Test_Class_1 { diff -r af2ac0dd2fa6 -r 0327745d3737 jaxp/.hgtags --- a/jaxp/.hgtags Thu Apr 14 15:22:12 2011 -0700 +++ b/jaxp/.hgtags Wed Jul 05 17:41:25 2017 +0200 @@ -112,3 +112,4 @@ 4aa9916693dc1078580c1865e6f2584046851e5a jdk7-b135 1759daa85d33800bd578853f9531f9de73f70fc7 jdk7-b136 1d87f7460cde7f8f30af668490f82b52b879bfd8 jdk7-b137 +be3758943770a0a3dd4be6a1cb4063507c4d7062 jdk7-b138 diff -r af2ac0dd2fa6 -r 0327745d3737 jaxws/.hgtags --- a/jaxws/.hgtags Thu Apr 14 15:22:12 2011 -0700 +++ b/jaxws/.hgtags Wed Jul 05 17:41:25 2017 +0200 @@ -112,3 +112,4 @@ d5fc61f18043765705ef22b57a68c924ab2f1a5b jdk7-b135 c81d289c9a532d6e94af3c09d856a2a20529040f jdk7-b136 ccea3282991ce8b678e188cf32a8239f76ff3bfa jdk7-b137 +cc956c8a8255583535597e9a63db23c510e9a063 jdk7-b138 diff -r af2ac0dd2fa6 -r 0327745d3737 jdk/.hgtags --- a/jdk/.hgtags Thu Apr 14 15:22:12 2011 -0700 +++ b/jdk/.hgtags Wed Jul 05 17:41:25 2017 +0200 @@ -112,3 +112,4 @@ d8ced728159fbb2caa8b6adb477fd8efdbbdf179 jdk7-b135 aa13e7702cd9d8aca9aa38f1227f966990866944 jdk7-b136 29296ea6529a418037ccce95903249665ef31c11 jdk7-b137 +60d3d55dcc9c31a30ced9caa6ef5c0dcd7db031d jdk7-b138 diff -r af2ac0dd2fa6 -r 0327745d3737 jdk/make/common/shared/Defs.gmk --- a/jdk/make/common/shared/Defs.gmk Thu Apr 14 15:22:12 2011 -0700 +++ b/jdk/make/common/shared/Defs.gmk Wed Jul 05 17:41:25 2017 +0200 @@ -218,11 +218,7 @@ else LAUNCHER_NAME = java PRODUCT_NAME = Java(TM) - ifeq ($(J4B), true) - PRODUCT_SUFFIX = SE Runtime Environment for Business - else - PRODUCT_SUFFIX = SE Runtime Environment - endif + PRODUCT_SUFFIX = SE Runtime Environment JDK_RC_PLATFORM_NAME = Platform SE COMPANY_NAME = Oracle Corporation endif diff -r af2ac0dd2fa6 -r 0327745d3737 jdk/src/share/classes/sun/util/resources/CurrencyNames_de.properties --- a/jdk/src/share/classes/sun/util/resources/CurrencyNames_de.properties Thu Apr 14 15:22:12 2011 -0700 +++ b/jdk/src/share/classes/sun/util/resources/CurrencyNames_de.properties Wed Jul 05 17:41:25 2017 +0200 @@ -65,6 +65,8 @@ # adp=Andorranische Pesete aed=UAE Dirham +afa=Afghani (1927-2002) +afn=Afghani all=Lek amd=Dram ang=Niederl. Antillen Gulden @@ -85,6 +87,7 @@ bif=Burundi-Franc bmd=Bermuda-Dollar bnd=Brunei-Dollar +bob=Boliviano bov=Mvdol brl=Real bsd=Bahama-Dollar @@ -106,6 +109,7 @@ cve=Kap Verde Escudo cyp=Zypern-Pfund czk=Tschechische Krone +dem=Deutsche Mark djf=Dschibuti-Franc dkk=D\u00e4nische Krone dop=Dominikanischer Peso @@ -176,7 +180,9 @@ mtl=Maltesische Lira mur=Mauritius-Rupie mvr=Rufiyaa +mwk=Malawi Kwacha mxn=Mexikanischer Peso +mxv=Mexican Unidad de Inversion (UDI) myr=Malaysischer Ringgit mzm=Alter Metical mzn=Metical @@ -217,6 +223,7 @@ srd=Surinamischer Dollar srg=Suriname Gulden std=Dobra +svc=El Salvador Colon syp=Syrisches Pfund szl=Lilangeni thb=Baht diff -r af2ac0dd2fa6 -r 0327745d3737 jdk/src/share/classes/sun/util/resources/CurrencyNames_it.properties --- a/jdk/src/share/classes/sun/util/resources/CurrencyNames_it.properties Thu Apr 14 15:22:12 2011 -0700 +++ b/jdk/src/share/classes/sun/util/resources/CurrencyNames_it.properties Wed Jul 05 17:41:25 2017 +0200 @@ -86,6 +86,7 @@ bif=Franco del Burundi bmd=Dollaro delle Bermuda bnd=Dollaro del Brunei +bob=Boliviano bov=Mvdol Boliviano brl=Real Brasiliano bsd=Dollaro delle Bahamas diff -r af2ac0dd2fa6 -r 0327745d3737 jdk/test/java/lang/invoke/ClassValueTest.java --- a/jdk/test/java/lang/invoke/ClassValueTest.java Thu Apr 14 15:22:12 2011 -0700 +++ b/jdk/test/java/lang/invoke/ClassValueTest.java Wed Jul 05 17:41:25 2017 +0200 @@ -52,9 +52,9 @@ static String nameForCV1(Class type) { return "CV1:" + type.getName(); } - static int countForCV1; - static final ClassValue CV1 = new CV1(); - private static class CV1 extends ClassValue { + int countForCV1; + final ClassValue CV1 = new CV1(); + private class CV1 extends ClassValue { protected String computeValue(Class type) { countForCV1++; return nameForCV1(type); @@ -103,8 +103,8 @@ static String nameForCVN(Class type, int n) { return "CV[" + n + "]" + type.getName(); } - static int countForCVN; - static class CVN extends ClassValue { + int countForCVN; + class CVN extends ClassValue { final int n; CVN(int n) { this.n = n; } protected String computeValue(Class type) { diff -r af2ac0dd2fa6 -r 0327745d3737 jdk/test/java/util/Currency/CurrencyTest.java --- a/jdk/test/java/util/Currency/CurrencyTest.java Thu Apr 14 15:22:12 2011 -0700 +++ b/jdk/test/java/util/Currency/CurrencyTest.java Wed Jul 05 17:41:25 2017 +0200 @@ -23,7 +23,7 @@ /* * @test * @bug 4290801 4692419 4693631 5101540 5104960 6296410 6336600 6371531 - * 6488442 + * 6488442 7036905 * @summary Basic tests for Currency class. */ @@ -249,7 +249,7 @@ testDisplayName("ITL", new Locale("it"), "Lira Italiana"); testDisplayName("JPY", Locale.JAPANESE, "\u65e5\u672c\u5186"); testDisplayName("KRW", Locale.KOREAN, "\ub300\ud55c\ubbfc\uad6d \uc6d0"); - testDisplayName("SEK", new Locale("sv"), "Svensk krona"); + testDisplayName("SEK", new Locale("sv"), "svensk krona"); testDisplayName("CNY", Locale.SIMPLIFIED_CHINESE, "\u4eba\u6c11\u5e01"); testDisplayName("TWD", Locale.TRADITIONAL_CHINESE, "\u65b0\u81fa\u5e63"); } diff -r af2ac0dd2fa6 -r 0327745d3737 jdk/test/sun/text/resources/LocaleData --- a/jdk/test/sun/text/resources/LocaleData Thu Apr 14 15:22:12 2011 -0700 +++ b/jdk/test/sun/text/resources/LocaleData Wed Jul 05 17:41:25 2017 +0200 @@ -6942,3 +6942,14 @@ CurrencyNames/zh_TW/xts=XTS CurrencyNames/zh_TW/xxx=XXX CurrencyNames/zh_TW/yer=\u8449\u9580\u91cc\u96c5 + +# bug 7036905 +CurrencyNames/de/afa=Afghani (1927-2002) +CurrencyNames/de/afn=Afghani +CurrencyNames/de/bob=Boliviano +CurrencyNames/de/dem=Deutsche Mark +CurrencyNames/de/mwk=Malawi Kwacha +CurrencyNames/de/mxv=Mexican Unidad de Inversion (UDI) +CurrencyNames/de/svc=El Salvador Colon + +CurrencyNames/it/bob=Boliviano diff -r af2ac0dd2fa6 -r 0327745d3737 jdk/test/sun/text/resources/LocaleDataTest.java --- a/jdk/test/sun/text/resources/LocaleDataTest.java Thu Apr 14 15:22:12 2011 -0700 +++ b/jdk/test/sun/text/resources/LocaleDataTest.java Wed Jul 05 17:41:25 2017 +0200 @@ -33,7 +33,7 @@ * 6379214 6485516 6486607 4225362 4494727 6533691 6531591 6531593 6570259 * 6509039 6609737 6610748 6645271 6507067 6873931 6450945 6645268 6646611 * 6645405 6650730 6910489 6573250 6870908 6585666 6716626 6914413 6916787 - * 6919624 6998391 7019267 7020960 7025837 7020583 + * 6919624 6998391 7019267 7020960 7025837 7020583 7036905 * @summary Verify locale data * */